如何解决如何在带有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>`
在上面的“
`<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() > 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爱好者使用。我希望在这里使用具有副作用的功能。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。