有没有更好的方法来获取XPath查询结果的父节点?

Mar*_*ski 25 xml xpath dom

有这样的标记:

<div class="foo">
   <div><span class="a1"></span><a href="...">...</a></div>
   <div><span class="a2"></span><a href="...">...</a></div>
   <div><span class="a1"></span>some text</div>
   <div><span class="a3"></span>some text</div>
</div>
Run Code Online (Sandbox Code Playgroud)

我有兴趣获得所有<a>,some text 只有相邻span是等级a1.所以在整个代码结束时,我的结果应该<a>来自第一个divsome text第三个.这将会是容易的,如果<a>some text是内部spandiv将有class属性,但没有运气.

我现在正在做的就是寻找span具有a1类:

//div[contains(@class,'foo')]/div/span[contains(@class,'a1')]
Run Code Online (Sandbox Code Playgroud)

然后我得到它的父节点并query()用该父节点做另一个作为上下文节点.这简直远远没有效率,所以问题显然是否有更好的方法来实现我的目标?


回答附录

根据@MarcB 接受的答案,使用的正确查询是:

//div[contains(@class,'foo')]/div/span[contains(@class,'a1')]/..
Run Code Online (Sandbox Code Playgroud)

但是因为<a>它可能更好用:

//div[contains(@class,'foo')]/div/span[contains(@class,'a1')]/../a
Run Code Online (Sandbox Code Playgroud)

得到<a>而不是它的容器.

Mar*_*c B 55

关于xpath查询的好处是你可以基本上将它们视为文件系统路径,所以只需要

//div[contains(@class,'foo')]/div/span[contains(@class,'a1')]/..
                                                              ^^
Run Code Online (Sandbox Code Playgroud)

将找到位于.foo节点下的所有.a1节点,然后向上移动一级到a1节点的父节点.

  • +1用于引用文件系统路径,这就是我一直想到的但是我从来没有听说过这样解释过 (5认同)

Dim*_*hev 16

一个比使用反转轴更好的表达式:

//div[contains(@class,'foo')]/div[span[contains(@class,'a1')]]
Run Code Online (Sandbox Code Playgroud)

这将选择任何属性div的子节点,divclass属性包含字符串"foo",并且(所选div)具有spanclass属性包含字符串"a1" 的子节点.

基于XSLT的验证:

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

 <xsl:template match="/">
  <xsl:copy-of select=
  "//div[contains(@class,'foo')]
          /div[span[contains(@class,'a1')]]"/>
 </xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

在提供的XML文档上应用此转换时:

<div class="foo">
   <div><span class="a1"></span><a href="...">...</a></div>
   <div><span class="a2"></span><a href="...">...</a></div>
   <div><span class="a1"></span>some text</div>
   <div><span class="a3"></span>some text</div>
</div>
Run Code Online (Sandbox Code Playgroud)

评估XPath表达式,并将选定的元素复制到输出:

<div>
   <span class="a1"/>
   <a href="...">...</a>
</div>
<div>
   <span class="a1"/>some text</div>
Run Code Online (Sandbox Code Playgroud)

II.关于通过其中一个类访问Html元素的备注:

如果已知元素只能有一个类,则根本不需要使用 contains()

不要使用:

//div[contains(@class, 'foo')]
Run Code Online (Sandbox Code Playgroud)

用途:

//div[@class = 'foo']
Run Code Online (Sandbox Code Playgroud)

或者,如果可能有前导/尾随空格,请使用:

//div[normalize-space(@class) = 'foo']
Run Code Online (Sandbox Code Playgroud)

一个至关重要的问题:

//div[contains(@class, 'foo')]
Run Code Online (Sandbox Code Playgroud)

这是选择任何div类,如"myfoo","foo2"或"myfoo3".

如果元素可能有多个类,并且为了避免上述问题,正确的XPath表达式是:

//div[contains(concat(' ', @class, ' '), ' foo ')]
Run Code Online (Sandbox Code Playgroud)

  • @MarcB,似乎你没有阅读或理解这个答案 - 它详细讨论了一个元素有多个类的情况.而且,这个答案为这种情况提供了正确的解决方案 - 而不是像不正确和简单的`contains(@calss,someString)` (3认同)
  • 不要忘记html允许多个类.`@ class ='foo'`将跳过`class ="foo bar baz"`.因此,@ contains是完全有效的,只要你指出,你就会注意误报 (2认同)