满足复杂条件时模板覆盖
Template override when complex conditions are met
我有一些 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>
(N.B。在上面的示例中,文档顺序很重要,在下面的问题中则没有)
效果很好,但是现在我需要做一些更复杂的事情。
我想忽略上面示例中的第 4 个 a
元素 xml,前提是满足以下条件:
b/@t="2"
- 在同一父元素中还有一些其他
a
,其中 b/@t="1"
- 两个
a
元素的 b/c/@n
值相同。
在示例xml中,最后一个节点不应与此规则匹配,因为@n 的值不同。
我不关心 a
节点的顺序,或者中间是否有其他内容。但是我可以声明节点将按显示的顺序排列,如果需要,没有中间节点。
除了模板覆盖之外,可能还有其他方法可以实现此目的,但是为了代码整洁,我真的在寻找基于模板的解决方案(如果存在的话)。
我目前正在使用 xmlstarlet,它不支持 XSLT2.0 或 XPATH2.0,我可以研究其他引擎,但如果可能的话我更愿意坚持使用我现有的引擎。
N.B。不同 parent
节点中的节点不应相互影响 - 例如标有 @so=1
的节点不应受到标有 @so=2
的节点的影响,因为它们位于不同的父节点中。
@so=3
和 @so=4
也是如此。在这些节点的示例中 none 应该被匹配
以下 XSLT 片段按要求删除了第 4 个 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]"/>
匹配子句选择所有 a
具有 b/@t = 2
。然后它检查是否有 a
其中 b/@t = 1
与当前元素具有相同的 b/c/@n
值。
如果检查只应在同一个父项中发生,您可以像这样将父项的 ID 添加到键中:
<!-- 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]"/>
后一个XSLT脚本转换如下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>
进入
<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="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>
我有一些 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>
(N.B。在上面的示例中,文档顺序很重要,在下面的问题中则没有)
效果很好,但是现在我需要做一些更复杂的事情。
我想忽略上面示例中的第 4 个 a
元素 xml,前提是满足以下条件:
b/@t="2"
- 在同一父元素中还有一些其他
a
,其中b/@t="1"
- 两个
a
元素的b/c/@n
值相同。
在示例xml中,最后一个节点不应与此规则匹配,因为@n 的值不同。
我不关心 a
节点的顺序,或者中间是否有其他内容。但是我可以声明节点将按显示的顺序排列,如果需要,没有中间节点。
除了模板覆盖之外,可能还有其他方法可以实现此目的,但是为了代码整洁,我真的在寻找基于模板的解决方案(如果存在的话)。
我目前正在使用 xmlstarlet,它不支持 XSLT2.0 或 XPATH2.0,我可以研究其他引擎,但如果可能的话我更愿意坚持使用我现有的引擎。
N.B。不同 parent
节点中的节点不应相互影响 - 例如标有 @so=1
的节点不应受到标有 @so=2
的节点的影响,因为它们位于不同的父节点中。
@so=3
和 @so=4
也是如此。在这些节点的示例中 none 应该被匹配
以下 XSLT 片段按要求删除了第 4 个 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]"/>
匹配子句选择所有 a
具有 b/@t = 2
。然后它检查是否有 a
其中 b/@t = 1
与当前元素具有相同的 b/c/@n
值。
如果检查只应在同一个父项中发生,您可以像这样将父项的 ID 添加到键中:
<!-- 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]"/>
后一个XSLT脚本转换如下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>
进入
<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="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>