我想知道是否有办法使用Xpath访问公共父节点。
<outer>
<main>
<a><b> sometext </b></a>
<c><d> sometext2 </d></c>
</main>
</outer>
我有文本节点sometext和sometext2。有没有办法可以访问这两个节点的主(共同父节点)?我不知道包含这些节点的xml的布局。
答案 0 :(得分:15)
使用以下XPath 1.0表达式:
$v1/ancestor::*
[count(. | $v2/ancestor::*)
=
count($v2/ancestor::*)
]
[1]
其中$ v1和$ v2包含两个文本节点(如果您不在XSLT中使用XPath,则必须使用XPath表达式替换上述表达式中的$ v1和$ v2选择这两个文本节点中的每一个。)
<强>解释强>:
上面的XPath 1.0表达式找到两个节点集的交集:$ v1的所有元素祖先的节点集和$ v2的所有元素祖先的节点集。 这是通过所谓的Kaysian交叉方法(在2000年发现这一点的Michael Kay之后)完成的。使用Kaysian方法进行交集,两个节点集的交集,$ ns1和$ ns2由以下XPath表达式选择:
$ns1[count(. | $ns2) = count($ns2)]
然后,从祖先的交叉点我们必须选择最后一个元素。但是,因为我们使用的是反向轴(祖先),所需的节点位置必须表示为1 。
通过应用以下转换,可以快速验证上述XPath表达式是否真正选择了最低共同祖先:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:variable name="v1" select="/*/*/a/b/text()"/>
<xsl:variable name="v2" select="/*/*/c/d/text()"/>
<xsl:variable name="vCommonAncestor" select=
"$v1/ancestor::*
[count(. | $v2/ancestor::*)
=
count($v2/ancestor::*)
]
[1]"
/>
<xsl:template match="/">
<xsl:value-of select="name($vCommonAncestor)"/>
</xsl:template>
</xsl:stylesheet>
应用于最初提供的XML文档(更正为格式良好的XML):
<outer>
<main>
<a>
<b>sometext</b>
</a>
<c>
<d>sometext2</d>
</c>
</main>
</outer>
想要的结果(两个文本节点的最低共同祖先元素的名称)生成:
主要强>
选择两个节点的最低共同祖先的XPath 2.0表达式更简单,因为它使用标准XPath 2.0运算符“intersect”:
($v1/ancestor::* intersect $v2/ancestor::*)
[last()]
答案 1 :(得分:1)
这看起来很复杂。试试吧:
xquery version "3.0";
let $test :=
<outer>
<main>
<a><b> sometext </b></a>
<c><d> sometext2 </d></c>
</main>
</outer>
return ($test//*[.//b][.//d])[last()]
获得最完美的共同祖先