满足复杂条件时覆盖模板

时间:2019-10-17 10:05:16

标签: xslt xpath xslt-1.0

我有一些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也是如此。在示例中,这些节点都不应该匹配

1 个答案:

答案 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>