由于这个问题已经有一段时间没有活动了,我想自己回答一下。回顾一下评论中的一个想法,当然,很难回顾为什么 XSLT 1.0 规范的负责人省略了该sibling
轴。
最确凿的原因之一可能与@JLRiche 和@MichaelKay 的评论有关:轴应该相对于参考节点进入特定方向,并且可能难以确定方向是什么sibling
。
为了进一步研究这一点,我设置了一个测试 XSLT 和一个测试输入 XML 来检查轴的工作方式(请参见下文),特别是轴中节点的顺序是什么。结果令我惊讶:
preceding-sibling
轴不是从最靠近参考节点的节点开始,而是从最靠近文档开头的节点开始。
following-sibling
确实从参考节点开始。
这实际上允许定义
sibling := preceding-sibling | following-sibling
该集合中的节点从文档的开头到结尾不断迭代。不会有“跳跃”。
建议的替代方案
../node except .
也可以很好地工作并以相同的顺序产生相同的集合。但是,查看一个不熟悉的 XSLT,我会假设sibling
轴比使用父子构造更好地解释逻辑。
有趣的是,轴不是从最接近参考节点的节点开始,而是从最接近文档开头的节点开始这一事实也适用于preceding
,ancestor
因此例如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> following siblings: </xsl:text>
<xsl:for-each select="following-sibling::node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text> 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> 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> following siblings: </xsl:text>
<xsl:for-each select="following-sibling::node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text> parent's children: </xsl:text>
<xsl:for-each select="../node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text> parent's children except self: </xsl:text>
<xsl:for-each select="../node except .">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text> 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> ancestors: </xsl:text>
<xsl:for-each select="ancestor::node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text> immediate ancestor: </xsl:text>
<xsl:for-each select="(ancestor::node)[1]">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text> ancestors or self: </xsl:text>
<xsl:for-each select="ancestor-or-self::node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text> descendants: </xsl:text>
<xsl:for-each select="descendant::node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text> descendants or self: </xsl:text>
<xsl:for-each select="descendant-or-self::node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text> preceding: </xsl:text>
<xsl:for-each select="preceding::node">
<xsl:call-template name="dump"/>
</xsl:for-each>
<xsl:text> 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