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>
我有一个适用于所有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>
(注意在上面的例子中,文件顺序很重要,在下面的问题中不重要)
效果很好,但是现在我需要做一些更复杂的事情。a
鉴于满足以下条件,我想忽略上述示例 xml 中的第 4 个元素:
b/@t="2"
a
在同一个父元素中还有一些其他元素,其中b/@t="1"
- 两个元素的
b/c/@n
值相同。a
在示例 xml 中,最后一个节点不应与此规则匹配,因为 @n 的值不同。
我不在乎a
节点的顺序,或者中间是否有其他东西。但是,如果需要,我可以声明节点将按照显示的顺序排列,没有中间节点。
除了模板覆盖之外,可能还有其他方法可以实现这一点,但是为了代码整洁,我真的在寻找基于模板的解决方案,如果存在的话。
我目前正在使用不支持 XSLT2.0 或 XPATH2.0 的 xmlstarlet,我可以研究其他引擎,但如果可能的话,我更愿意坚持使用我所拥有的引擎。
NB 不同节点中的parent
节点不应相互影响 - 例如,标记为的节点@so=1
不应受到标记为的节点的存在影响,@so=2
因为它们位于不同的父节点中。对于@so=3
和 也是如此@so=4
。在示例中,这些节点都不应该匹配
解决方案
以下 XSLT 片段a
根据要求删除了第 4 个:
<!-- 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
where 。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>
推荐阅读
- wordpress - 如何在 WordPress 网站中添加自定义徽标而不是菜单主页图标?
- javascript - 下拉过滤器在 React 中显示不正确的结果
- javascript - 从页面上的 div 内的内容脚本中注入 iframe 会在页面上的每个 iframe 中注入 src html
- c - 为linux内核中的struct数组分配内存并得到奇怪的输出od structs ids
- c# - 在一个 TextBox Asp.Net Mvc 中搜索多个项目
- swift - Swift:TableView didSelectRowAt 仅针对某些行触发?
- javascript - React redux,数组状态不更新
- memory-management - 具有 CPU 和内存可视化的循环内存调度
- go - 评估期望值为 Go 接口的 hcl.Expression
- java - 注入的类是否必须具有特定于弹簧的注释?