如何在带有xpath的样式表3.0中的xslt中声明和使用动态数组https://www.w3.org/TR/xpath-functions-31/#func-array-put

问题描述

我具有以下功能 '

`<xsl:function name="type:iterateICinDef">
    <xsl:param name="pElem" as="element()"/>
    <xsl:param name="parentSpc"/>
    <xsl:param name="sequence" as="xs:integer"/>
    <xsl:param name="cardinality"/>
    <xsl:param name="required"/>
    <xsl:param name="refNameSpc"/>
    <xsl:param name="type"/>
    <xsl:param name="flag" as="xs:integer"/>
    <xsl:param name="hierParent"/>
    <xsl:variable name="refName" select="replace($refNameSpc,'_spc',' ')"/>
    <xsl:variable name="parent" select="replace($parentSpc,' ')"/>
    <xsl:if test="not ($pElem/_u0024ref or $pElem/items/_u0024ref)">
        <Repository_spcIC>
            <xsl:attribute name="Name">
                <xsl:value-of select="$refName"></xsl:value-of>
            </xsl:attribute>
        </Repository_spcIC>
    </xsl:if>
   </xsl:function>`

在上面的“ 名称中,名称应该是唯一的,并且不应与另一个Repository_spcIC重复,因此我想通过在列表中形成名称数组和查找来避免重复名称已经存在,如果确实存在,则需要在名称后缀后缀“ __D1”,以使名称唯一。如果相同名称的重复超过两次,则序列号将增加以使其唯一如“ __D2”,“ __ D3”等,如果名称是唯一的,则需要将该名称添加到数组中,以便对函数的下一次调用将查找该数组以知道该名称是否已经存在,以决定是否将其后缀是否命名

上面的这个函数是从下面的另一个函数调用

`<xsl:for-each select="/*/deFinitions/element()">
    <!-- what this loop does is goes one level up,which is deFinitions
     and then iterate thru all nodes under it i.e each object to match 
    def1 or def2 got earlier-->
        <xsl:if test="name(.)=$def1 or name(.)=$def2">
            <xsl:variable name="cardinality">
                <xsl:if test="required">
                    <xsl:for-each select="required">
                        <countNo>
                            <xsl:if test="(position() &gt; 1)">
                                <xsl:text>,</xsl:text>
                            </xsl:if>
                        </countNo>
                        <xsl:value-of select="text()"/>
                    </xsl:for-each>
                </xsl:if>
            </xsl:variable>
            <xsl:sequence select="type:iterateICinDef((.),if($flag=1)     
        then $refName else if($pElem/comments) then $pElem/comments
    /text() 
        else $pElem/name(.),$sequence + 1,if($type='array') then 'Zero 
   or More' else 'Zero or One',$cardinality,$referredname,$type,1,$refName)"/>
    </xsl:if>
    </xsl:for-each>`

解决方法

与XDM数据模型中的其他所有数组一样,数组是不可变的。这意味着您永远不能“就地”更改现有阵列,只能通过对现有阵列进行更改来创建新阵列。

您已经用过程伪代码表达了您的需求,而XSLT不是过程语言,因此,对代码进行反向工程来确定真正的要求是非常困难的。最好通过描述过程的输入和输出来解释您的需求,而不是将它们作为从另一个到另一个的一系列动作。

问题中的短语“一次一个”响起了警钟。在像XSLT这样的声明性功能语言中,没有时间的概念,也没有一个接一个发生的事物的概念。

目前还不清楚您是否需要XDM阵列。我怀疑XDM序列会更容易使用。数组是该语言的3.0附加功能(主要是为了支持JSON而引入的),而序列自2.0以来一直存在,并且已更深入地集成到处理模型中。例如,XSLT的xsl:for-each指令可用于处理序列中的每个单个项目,但是没有等效的指令来处理数组的每个成员。

我可以解释设置空的序列或数组或包含一个字符串集合的序列或数组的详细语法,但是我不确定这是否会有所帮助。如果您可以用功能术语(什么是输入,什么是输出以及它们之间如何关联?)来解释您的需求,那就更好了,而且将其转换成XSLT代码可能会容易得多。

==更新==

在更新问题时,您已经解释说要编写一个生成唯一值的函数。为此,您建议该函数存储先前的调用,以便避免两次生成相同的值。因此,该函数需要修改一些外部函数(特别是其对先前调用的记忆):它是一个具有副作用的函数,通常称为“不纯函数”,在纯函数式编程语言中,强烈建议不要这样做。 / p>

有多种解决此问题的方法,其中最常见的是:

  • 生成一个值,该值是您当前正在输入中处理的事物的函数,例如通过使用position()generate-id()xsl:number

  • 生成一个有效的随机值,并且具有极低的重复概率(例如,基于当前时间戳记的值)。这就是UUID通常的工作方式。对于大多数实际目的而言,每百万年只能出现一次的值就足够了。

  • 编写一个提供生成器的函数,其中生成器具有两个属性:您可以使用此时间的值,以及可以调用以获取更多值的新生成器。这就是内置函数fn:random-number-generator()的工作方式。这是函数式编程爱好者的方法,但是如果您不熟悉函数式编程,则需要一点时间来适应。

,

如果您需要描述的唯一名称,则可以在上一步中重新计算名称。该代码显示了如何实现:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 

    <xsl:output method="xml" indent="yes"/> 

    <xsl:variable name="data">
        <data>
            <item name="A"/>
            <item name="A"/>
            <item name="B"/>
            <item name="A"/>
            <item name="C"/>
            <item name="C1"/>
            <item name="C1"/>
            <item name="C11"/>
            <item name="C1"/>
            <item name="C11"/>
            <item name="C12"/>
            <item name="D"/>
            <item name="A"/>
        </data>
    </xsl:variable>

    <xsl:template name="makeunique">
        <xsl:param name="data"/>
        <xsl:if test="not($data/data/item[@replaced = 'true']) and $data/data/item/@replaced">
            <data>
                <xsl:for-each select="$data/data/item">
                    <item name="{@name}" origname="{@origname}"/>
                </xsl:for-each>
            </data>
        </xsl:if>
        <xsl:if test="$data/data/item[@replaced = 'true'] or not($data/data/item/@replaced)">
            <xsl:variable name="newData">
                <data>
                    <xsl:for-each select="$data/data/item">
                        <xsl:variable name="name">
                            <xsl:if test="./preceding-sibling::item[@name = current()/@name]">
                                <xsl:value-of select="concat(current()/@name,./preceding-sibling::item[@name = current()/@name]/last()+1)"/>
                            </xsl:if>
                            <xsl:if test="not(./preceding-sibling::item[@name = current()/@name]) and not(./following-sibling::item[@name = current()/@name])">
                                <xsl:value-of select="@name"/>
                            </xsl:if>
                            <xsl:if test="not(./preceding-sibling::item[@name = current()/@name]) and (./following-sibling::item[@name = current()/@name])">
                                <xsl:value-of select="concat(current()/@name,'1')"/>
                            </xsl:if>
                        </xsl:variable>
                        <xsl:variable name="origname">
                            <xsl:if test="not(current()/@origname)">
                                <xsl:value-of select="current()/@name"/>
                            </xsl:if>
                            <xsl:if test="current()/@origname">
                                <xsl:value-of select="current()/@origname"/>
                            </xsl:if>
                        </xsl:variable>
                        <item name="{$name}" origname="{$origname}" replaced="{not($name = current()/@name)}"/>
                    </xsl:for-each>
                </data>
            </xsl:variable>   
            <xsl:call-template name ="makeunique">
                <xsl:with-param name="data" select="$newData"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>     

    <xsl:template name="test"> 
        <xsl:call-template name ="makeunique">
            <xsl:with-param name="data" select="$data"/>
        </xsl:call-template>
    </xsl:template> 
    
</xsl:stylesheet>

输出:

<?xml version="1.0" encoding="UTF-8"?>
<data>
   <item name="A1" origname="A"/>
   <item name="A2" origname="A"/>
   <item name="B" origname="B"/>
   <item name="A3" origname="A"/>
   <item name="C" origname="C"/>
   <item name="C11" origname="C1"/>
   <item name="C121" origname="C1"/>
   <item name="C111" origname="C11"/>
   <item name="C13" origname="C1"/>
   <item name="C112" origname="C11"/>
   <item name="C122" origname="C12"/>
   <item name="D" origname="D"/>
   <item name="A4" origname="A"/>
</data>

BTW:此解决方案更适合XSLT爱好者使用。我希望在这里使用具有副作用的功能。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...