我有一些XML,其语义类似于以下内容:
<root>
<parent>
<a>
<b t="0"/>
</a>
<a>
<b t="0"/>
</a>
<a so="2">
<b t="1">
<c n="x"/>
</b>
</a>
<a>
<b t="2">
<c n="x"/>
</b>
</a>
<a>
<b t="1">
<c n="y"/>
</b>
</a>
<a so="3">
<b t="2">
<c n="z"/>
</b>
</a>
</parent>
<parent>
<a so="1">
<b t="2">
<c n="x"/>
</b>
</a>
<a so="4">
<b t="1">
<c n="z"/>
</b>
</a>
</parent>
</root>
我有一个适用于所有a
元素的模板:
<xsl:template match="a" mode="whatever">
do some nice stuff with the content of a
</xsl:template>
我有一些模板可以覆盖该行为,如果满足某些条件,则它们什么也不做。 例如:
<xsl:template match="a[@t='0'][preceding-sibling:a[@t='0']" mode="whatever">
<!-- ignore this node entirely -->
</xsl:template>
(以上示例中的注解很重要,在下面的问题中没有关系)
哪个效果很好,但是现在我需要做一些更复杂的事情。
假设满足以下条件,我想忽略上述示例xml中的第四个a
元素:
b/@t="2"
a
,其中b/@t="1"
b/c/@n
元素的a
值是相同的。在示例xml中,由于@n的值不同,因此该规则不应匹配最后一个节点。
我不在乎a
节点位于哪个顺序,或者它们之间是否还有其他东西。但是我可以指出,如果需要,节点将按照所示顺序排列,没有中间节点。
除了模板覆盖之外,还有其他方法可以实现此目的,但是为了代码整洁,我真的在寻找一种基于模板的解决方案(如果有的话)。
我当前使用的是不支持XSLT2.0或XPATH2.0的xmlstarlet,我可以研究其他引擎,但是如果可能的话,我会坚持使用我拥有的东西。
不同parent
节点中的节点不应互相影响-例如标记为@so=1
的节点不应受到标记为@so=2
的节点的影响,因为它们位于不同的父节点中。
对于@so=3
和@so=4
也是如此。在示例中,这些节点都不应该匹配
答案 0 :(得分:1)
以下XSLT代码段根据要求删除了第四个a
:
<!-- all a keyed by the value of b/@t -->
<xsl:key name="k1" match="//parent/a" use="b/@t"/>
<xsl:template match="//parent/a[b/@t = 2 and
key('k1', 1)/b/c/@n = b/c/@n]"/>
match子句选择具有a
的所有b/@t = 2
。然后,它检查是否存在a
,其中b/@t = 1
的{{1}}值与当前元素相同。
如果仅在同一父级中进行检查,则可以将父级ID添加到密钥中,如下所示:
b/c/@n
后面的XSLT脚本转换以下XML:
<!-- all a keyed by parent node and the value of b/@t -->
<xsl:key name="k1" match="//parent/a" use="concat(generate-id(..),'|',b/@t)"/>
<xsl:template match="//parent/a[b/@t = 2 and
key('k1', concat(generate-id(..),'|',1))/b/c/@n = b/c/@n]"/>
进入
<root>
<parent>
<a> <b t="0"/></a>
<a> <b t="0"/></a>
<a so="2"><b t="1"><c n="x"/></b></a>
<a> <b t="2"><c n="x"/></b></a>
<a> <b t="1"><c n="y"/></b></a>
<a so="3"><b t="2"><c n="z"/></b></a>
</parent>
<parent>
<a so="1"><b t="2"><c n="x"/></b></a>
<a so="4"><b t="1"><c n="z"/></b></a>
</parent>
</root>