Xslt 为什么没有兄弟轴?
查看XSLT中可用的轴,我必须发现没有Xslt 为什么没有兄弟轴?,xslt,Xslt,查看XSLT中可用的轴,我必须发现没有同级轴是前同级和后同级的联合。对我来说,这有点令人惊讶,因为我已经写了一个答案(),其中这个轴会很有帮助(尽管到目前为止我只有大约10个答案)。当然,很明显,您可以通过使用union来解决问题。所以这个轴不是必需的。但它偶尔会非常方便,就像所有其他轴一样,它会使代码更可读,更易于维护 有人知道为什么这个轴被遗漏了吗?这可能有一个不明显的原因吗 顺便说一句:我在StackExchange上发现了至少一个问题,其中警告使用前面的同级和后面的同级轴可能会降低性能。
同级
轴是前同级
和后同级
的联合。对我来说,这有点令人惊讶,因为我已经写了一个答案(),其中这个轴会很有帮助(尽管到目前为止我只有大约10个答案)。当然,很明显,您可以通过使用union来解决问题。所以这个轴不是必需的。但它偶尔会非常方便,就像所有其他轴一样,它会使代码更可读,更易于维护
有人知道为什么这个轴被遗漏了吗?这可能有一个不明显的原因吗
顺便说一句:我在StackExchange上发现了至少一个问题,其中警告使用
前面的同级
和后面的同级
轴可能会降低性能。但我假设所有包含XML树大部分的轴都是以嵌套方式使用的,这是正确的。因此,遗漏的原因不可能是由于性能。因为有一段时间没有关于这个问题的活动,我想自己回答。当然,从评论中可以看出,很难追溯到XSLT1.0规范的负责人为什么省略了同级轴
最具决定性的原因之一可能与@JLRiche和@MichaelKay的评论有关:axis被认为是针对参考节点的特定方向,并且可能很难确定同级节点的方向
为了进一步研究这一点,我设置了一个测试XSLT和一个测试输入XML来检查轴是如何工作的(见下文),特别是轴中节点的顺序。结果令我惊讶:
- 前面的同级轴
不是从最靠近参考节点的节点开始,而是从最靠近文档开头的节点开始
确实从引用节点开始
sibling := preceding-sibling | following-sibling
该集合中的节点从文档开始到结束不断迭代。不会有“跳跃”
建议的替代方案
../node except .
也可以很好地工作,并以相同的顺序生成相同的集合。然而,在看一个不熟悉的XSLT时,我会假设一个同级轴会比使用父子结构更好地解释逻辑
有趣的是,轴不是从距离参考节点最近的节点开始,而是从距离文档开头最近的节点开始,这一事实也适用于前面的和祖先的,因此,例如安塞斯特::节点[1]
不会返回节点的父节点,而是返回根节点
我问这个问题的最初动机是不必重复强加在节点属性上的冗长的条件,例如,我不想写
preceding-sibling::node[CONDITION] | following-sibling::node[CONDITION]
但是,由于上面的表达式可以重写为
(preceding-sibling::node | following-sibling::node)[CONDITION]
必须使用两个轴而不是同级轴的缺点并不像想象的那么糟糕。当然,在XSLT2.0中,这也适用于
(../node except .)[CONDITION]
所以,为了回答我的问题:我认为没有一个好的理由不定义同级轴。我想没人想到。:-)
测试设置
此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>
我怀疑这个轴的大多数用法可以更简单地表示为。/X
,例外情况是当前上下文节点本身就是一个X。在XPath 2.0中,这很容易解决-。/X除外。
这正是我想的情况:X是应该忽略的上下文节点。如果我添加轴,我的优先顺序是前面的兄弟姐妹或自我,后面的兄弟姐妹或自我——除了名称太冗长之外,使用(后面的兄弟姐妹::*|)更快。
。为了得到所有的兄弟姐妹,。/*
通常就是为了这个目的。除非最初的工作组有人读到这个问题,或者在某个地方提到没有兄弟姐妹的决定::
axis,否则我认为你运气不好。但要冒险猜测一下,所有可用的轴都有一个方向:它们向前、向后或无处移动(如self::
)。同级::
轴会同时向两个方向移动,这可能被视为与轴的概念不一致。@JLRishe是:确定同级::x[1]应该是什么肯定很困难!
<?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