为什么没有兄弟姐妹轴?(Why is there no sibling axis?)

2019-10-18 22:13发布

综观XSLT我必须找出没有可用的轴sibling轴这将是联盟preceding-siblingfollowing-sibling 。 对我来说,这是一个令人感到有点惊讶,因为我已经写了一个答案( XSLT问题... CSV问题? ),其中该轴将是有帮助的(虽然我只有约10答案为止)。 当然,很明显,你可以随时通过工会解决问题。 所以这个轴是不是真的需要。 但它会在一段时间是非常方便的每一次,像所有其他轴恕我直言,这将使得代码更易读,更容易维护。

有谁知道为什么这个轴被排除在外? 是否有可能为这个非显而易见的原因是什么?

顺便说一句:我发现至少有一个问题上StackExchange了有关使用一个潜在的性能下降警告preceding-siblingfollowing-sibling轴。 但我相信在嵌套方式使用所有包含XML树的很大一部分轴这是真的。 因此,对于不作为的理由不能一直由于性能。

Answer 1:

由于一直没有活动这个问题了,而我想回答它自己。 在评论中拿起一个念头,这是当然的,很难追溯说为什么负责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


文章来源: Why is there no sibling axis?
标签: xslt