XPath查找具有特定子节点的所有元素

61

请问能否帮助我找到在下面示例中具有子元素 c 的所有元素 b?

<a>
    <b name = "b1"></b>
    <b name = "b2"><c/></b>
    <b name = "b3"></b>
</a>

XPath查询必须返回b2元素。

第二个问题是:我想结合两个条件:获取具有名称为“b2”且具有元素c的元素。但是这个语法似乎不起作用: //b[@name='b2' and c]


1
“似乎未能起作用”到底意味着什么?请提出一个新的、独立的问题,并提供完整(尽可能小)的源XML文档,使用的XPath表达式以及期望的结果和实际得到的结果。对于当前的XML文档,XPath表达式//b[@name='b2' and c]选择了a的第二个子节点--正如它应该做的那样。 - Dimitre Novatchev
2个回答

71

如果已知XML文档的结构,最好避免使用XPath中的//伪运算符,因为使用它可能会导致效率低下(遍历整个文档树)。

因此,我建议对于提供的XML文档使用以下XPath表达式:

/*/b[c]

这个选择器选择了XML文档顶层元素的任何一个子元素b,并且该元素具有名为c的子元素。

更新:OP在几分钟前问了第二个问题:

第二个问题是:我想要结合两个条件:我想要获取名称为"b2"且具有元素c的元素。但这种语法似乎不起作用://b[@name='b2' and c]

提供的XPath表达式确实可以精确选择所需的元素。

以下是基于XSLT的验证::

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/*">
     <xsl:copy-of select="//b[@name='b2' and c]"/>
 </xsl:template>
</xsl:stylesheet>

当应用此转换到提供的 XML 文档时:

<a>
    <b name = "b1"></b>
    <b name = "b2"><c/></b>
    <b name = "b3"></b>
</a>

评估XPath表达式并将正确选择的元素复制到输出中:

<b name="b2">
   <c/>
</b>

我使用Python选择元素 如果我使用:root.findall("b[c]") 结果是我想要的 但是如果我使用root.findall("b[@name='b2' and c]") 我会得到“无效断言”错误 也许我应该开一个关于Python的新问题吗? - nam
@HOAINAMNGUYEN:是的,开另一个问题似乎是正确的做法——这似乎是与Python相关的问题。 - Dimitre Novatchev
我知道 //some-element-deep-within-the-dom 会搜索 每个 //some-element-deep-within-the-dom,但如果 //some-element-deep-within-the-dom 被移动到 DOM 中的其他位置,使用它是否更灵活、更不容易破坏脚本呢? - oldboy
@Anthony,如果XML文档发生变化,那么修改所有XPath表达式是一个好主意。像提出的措施并不总是安全和充分的。有一种编写XPath表达式的方法,可以始终选择预期的内容,而不管文档的变化——只需不在表达式中使用任何名称即可。 - Dimitre Novatchev
我不太理解你的回答。为什么它不安全且不足够?当然,我会通过它们的ID选择元素,但在许多情况下,元素没有ID,所以...无论如何,显然没有绝对可靠的方法来始终选择特定的元素。例如,即使您不按名称选择元素,如果文档的结构发生更改,则您的选择器也会出现问题。 - oldboy
@Antony,如果文档的结构已经改变,那么这就不再是同一个XML文档了。在验证之前,人们不应该有信心认为预先存在的XPath表达式仍然选择它们原本要选择的内容。随着XML文档语义的变化,XPath表达式的语义也会发生变化。这个评论是一般性的。可能有特定的XML文档实例允许受限的类别更改,而没有任何(或显著的)语义变化。始终执行所需操作的表达式://*//*[not(*)]等。 - Dimitre Novatchev

29

这应该很简单

//b[c]

即在任何地方查找一个具有c子元素的b


你好,现在我想结合2个条件:我想要得到名称为“b2”的元素,并且拥有元素c。 但是这个语法似乎不起作用: //b[@name='b2' and c] - nam
在 Perl 中使用 xsh 对我有效。 - choroba

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接