2

查看 XSLT 中的可用轴,我不得不发现没有sibling轴可以是 and 的preceding-sibling并集following-sibling。对我来说,这有点令人惊讶,因为我已经写了一个答案(XSLT 问题...CSV 问题。?),其中这个轴会有所帮助(尽管到目前为止我只有大约 10 个答案)。当然,很明显,您总是可以通过使用联合来解决问题。所以这个轴并不是真正需要的。但它每隔一段时间就会非常方便,并且像所有其他轴恕我直言,它会使代码更具可读性和更易于维护。

有人知道为什么这个轴被遗漏了吗?这可能有一个不明显的原因吗?

顺便说一句:我在 StackExchange 上发现了至少一个问题,其中警告说使用preceding-siblingfollowing-sibling轴可能会降低性能。但我认为对于包含大部分 XML 树的所有轴都以嵌套方式使用这是正确的。因此,遗漏的原因不可能是由于性能。

4

1 回答 1

3

由于这个问题已经有一段时间没有活动了,我想自己回答一下。回顾一下评论中的一个想法,当然,很难回顾为什么 XSLT 1.0 规范的负责人省略了该sibling轴。

最确凿的原因之一可能与@JLRiche 和@MichaelKay 的评论有关:轴应该相对于参考节点进入特定方向,并且可能难以确定方向是什么sibling

为了进一步研究这一点,我设置了一个测试 XSLT 和一个测试输入 XML 来检查轴的工作方式(请参见下文),特别是轴中节点的顺序是什么。结果令我惊讶:

  • preceding-sibling不是从最靠近参考节点的节点开始,而是从最靠近文档开头的节点开始。
  • following-sibling 确实从参考节点开始。

这实际上允许定义

sibling := preceding-sibling | following-sibling

该集合中的节点从文档的开头到结尾不断迭代。不会有“跳跃”。

建议的替代方案

../node except .

也可以很好地工作并以相同的顺序产生相同的集合。但是,查看一个不熟悉的 XSLT,我会假设sibling轴比使用父子构造更好地解释逻辑。

有趣的是,轴不是从最接近参考节点的节点开始,而是从最接近文档开头的节点开始这一事实也适用于precedingancestor因此例如ancester::node[1]不返回节点的父节点,而是返回根节点。

我提出这个问题的最初动机是不必重复CONDITION对节点属性施加冗长的内容,例如我不想写

preceding-sibling::node[CONDITION] | following-sibling::node[CONDITION]

但是,由于上面的表达式可以重写为

(preceding-sibling::node | following-sibling::node)[CONDITION]

必须使用两个轴而不是一个sibling轴的缺点并没有想象的那么糟糕。当然,在 XSLT 2.0 中,这也适用于

(../node except .)[CONDITION]

所以,回答我的问题:我认为没有充分的理由不定义sibling轴。估计没人想到。:-)

测试设置

此 XML 测试输入

<?xml version="1.0" encoding="ISO-8859-1"?>
<node id="1">
  <node id="2">
    <node id="3">
      <node id="4"/>
      <node id="5"/>
      <node id="6"/>
    </node>
    <node id="7">
      <node id="8"/>
      <node id="9"/>
      <node id="10"/>
    </node>
    <node id="11">
      <node id="12"/>
      <node id="13"/>
      <node id="14"/>
    </node>
  </node>    
  <node id="15">
    <node id="16">
      <node id="17"/>
      <node id="18"/>
      <node id="19"/>
    </node>
    <node id="20">
      <node id="21"/>
      <node id="22"/>
      <node id="23"/>
    </node>
    <node id="24">
      <node id="25"/>
      <node id="26"/>
      <node id="27"/>
    </node>
  </node>
  <node id="28">
    <node id="29">
      <node id="30"/>
      <node id="31"/>
      <node id="32"/>
    </node>
    <node id="33" value="A">
      <node id="34"/>
      <node id="35"/>
      <node id="36"/>
    </node>
    <node id="37">
      <node id="38"/>
      <node id="39"/>
      <node id="40"/>
    </node>
    <node id="41">
      <node id="42"/>
      <node id="43"/>
      <node id="44"/>
    </node>
    <node id="45" value="A">
      <node id="46"/>
      <node id="47"/>
      <node id="48"/>
    </node>
  </node>
</node>

使用这个 XSLT 2.0 表

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
    version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes" />
  <xsl:strip-space elements="*"/>

  <xsl:variable name="id" select="'37'"/>

  <xsl:template name="dump">
    <xsl:text> </xsl:text>
    <xsl:value-of select="@id"/>
  </xsl:template>

  <xsl:template match="//node[@id = $id]">

    <xsl:text>preceding siblings: </xsl:text>
    <xsl:for-each select="preceding-sibling::node">
      <xsl:call-template name="dump"/>
    </xsl:for-each>
    <xsl:text>&#10;following siblings: </xsl:text>
    <xsl:for-each select="following-sibling::node">
      <xsl:call-template name="dump"/>
    </xsl:for-each>
    <xsl:text>&#10;preceding and following siblings: </xsl:text>
    <xsl:for-each select="preceding-sibling::node | following-sibling::node">
      <xsl:call-template name="dump"/>
    </xsl:for-each>
    <xsl:text>&#10;preceding and following siblings with value A: </xsl:text>
    <xsl:for-each select="(preceding-sibling::node | following-sibling::node)[@value = 'A']">
      <xsl:call-template name="dump"/>
    </xsl:for-each>
    <xsl:text>&#10;following siblings: </xsl:text>
    <xsl:for-each select="following-sibling::node">
      <xsl:call-template name="dump"/>
    </xsl:for-each>
    <xsl:text>&#10;parent's children: </xsl:text>
    <xsl:for-each select="../node">
      <xsl:call-template name="dump"/>
    </xsl:for-each>
    <xsl:text>&#10;parent's children except self: </xsl:text>
    <xsl:for-each select="../node except .">
      <xsl:call-template name="dump"/>
    </xsl:for-each>
    <xsl:text>&#10;parent's children except self with value A: </xsl:text>
    <xsl:for-each select="(../node except .)[@value = 'A']">
      <xsl:call-template name="dump"/>
    </xsl:for-each>
    <xsl:text>&#10;ancestors: </xsl:text>
    <xsl:for-each select="ancestor::node">
      <xsl:call-template name="dump"/>
    </xsl:for-each>
    <xsl:text>&#10;immediate ancestor: </xsl:text>
    <xsl:for-each select="(ancestor::node)[1]"> 
      <xsl:call-template name="dump"/>
    </xsl:for-each>
    <xsl:text>&#10;ancestors or self: </xsl:text>
    <xsl:for-each select="ancestor-or-self::node">
      <xsl:call-template name="dump"/>
    </xsl:for-each>
    <xsl:text>&#10;descendants: </xsl:text>
    <xsl:for-each select="descendant::node">
      <xsl:call-template name="dump"/>
    </xsl:for-each>
    <xsl:text>&#10;descendants or self: </xsl:text>
    <xsl:for-each select="descendant-or-self::node">
      <xsl:call-template name="dump"/>
    </xsl:for-each>
    <xsl:text>&#10;preceding: </xsl:text>
    <xsl:for-each select="preceding::node">
      <xsl:call-template name="dump"/>
    </xsl:for-each>
    <xsl:text>&#10;following: </xsl:text>
    <xsl:for-each select="following::node">
      <xsl:call-template name="dump"/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

将产生此输出

preceding siblings:  29 33
following siblings:  41 45
preceding and following siblings:  29 33 41 45
preceding and following siblings with value A:  33 45
following siblings:  41 45
parent's children:  29 33 37 41 45
parent's children except self:  29 33 41 45
parent's children except self with value A:  33 45
ancestors:  1 28
immediate ancestor:  1
ancestors or self:  1 28 37
descendants:  38 39 40
descendants or self:  37 38 39 40
preceding:  2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 29 30 31 32 33 34 35 36
following:  41 42 43 44 45 46 47 48
于 2013-11-16T08:20:07.413 回答