我是XSLT的新手,并且一直在尝试合并匹配键(元素)的节点。我尝试了其他一些解决方案,但没有在我的数据集上正确理解它。
输入:
<coll>
<rootNode>
<Header>
<code> 1234 </code> <-- key to match on
<name> Name1 </name>
</Header>
<node2> Any text </node2>
<node4> Any data here </node4>
<children>
<childID> 3456 </childID>
<type> Child </type>
</children>
</rootNode>
<rootNode>
<Header>
<code> 1234 </code>
<name> Name1 </name>
</Header>
<node2> Different Text </node2>
<node4> Different data here </node4>
<children>
<childID> 789 </childID>
<type> Parent </type>
</children>
</rootNode>
</coll>
预期产出:
<coll>
<rootNode>
<Header>
<code> 1234 </code>
<name> Name1 </name>
</Header>
<node2> Any text </node2>
<node4> Any data here </node4>
<node2> Different Text </node2>
<node4> Different data here </node4>
<children>
<childID> 3456 </childID>
<type> Child </type>
<childID> 789 </childID>
<type> Parent </type>
</children>
</rootNode>
</coll>
即。匹配标头/代码值,然后合并任何子节点具有不同值的位置。因此,具有相同值的任何节点都不会重复。
希望这是有道理的,我的第一篇SO帖子,谢谢!
答案 0 :(得分:2)
以下是一个例子:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:functx="http://www.functx.com"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs functx">
<xsl:output indent="yes"/>
<xsl:function name="functx:index-of-node" as="xs:integer*">
<xsl:param name="nodes" as="node()*"/>
<xsl:param name="nodeToFind" as="node()"/>
<xsl:sequence select="
for $seq in (1 to count($nodes))
return $seq[$nodes[$seq] is $nodeToFind]
"/>
</xsl:function>
<xsl:function name="mf:eliminate-deep-equal-duplicates" as="node()*">
<xsl:param name="nodes"/>
<xsl:sequence
select="for $node in $nodes
return $node[not(some $preceding-node in $nodes[position() lt functx:index-of-node($nodes, $node)] satisfies deep-equal($node, $preceding-node))]"/>
</xsl:function>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="coll">
<xsl:copy>
<xsl:for-each-group select="rootNode" group-by="Header/code">
<xsl:copy>
<xsl:apply-templates select="Header,
mf:eliminate-deep-equal-duplicates(current-group()/(* except (Header, children))),
children"/>
</xsl:copy>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="rootNode/children">
<xsl:copy>
<xsl:apply-templates select="mf:eliminate-deep-equal-duplicates(current-group()/children/*)"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
至于解释:发布的样式表有三个模板,第一个是身份转换模板(允许我们通过在其他模板中对它们执行apply-templates
来复制我们想要复制的元素),第二个匹配coll
元素以创建它们的浅表副本,然后在for-each-group
元素上应用教科书rootNode
,按照Header/code
对其进行分组,如您所要求的那样。在for-each-group
内,对于每个组,xsl:copy
创建rootNode
并通过处理组中第一项的Header
元素来填充它(因此我们只获得一个Header
{1}}每个组中的结果元素),组中每个项目的Header
和children
除外,其中组中没有先前的deep-equals
元素且{{1}组中第一个项目的元素,以确保每个组都获得children
子元素。在该元素的模板中,我们需要确保我们处理当前组中没有children
重复的所有大孩子。
我已将长表达式重构为函数deep-equal
,它选择节点序列中的那些节点,同一序列中的前一节点不是mf:eliminate-deep-equal-duplicates
。
该解决方案利用了functx库的函数http://www.xsltfunctions.com/xsl/functx_index-of-node.html,该函数为我们提供了序列中节点的索引。
正如Vladimir Nesterovsky在评论中指出的那样,函数deep-equal
也可以在不使用functx mf:eliminate-deep-equal-duplicates
的情况下实现:
functx:index-of-node