25

有这样的标记:

<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>

我有兴趣获得所有<a>并且some text 只有在相邻span是类的情况下a1。所以在整个代码的最后,我的结果应该<a>来自第一个divsome text第三个。如果<a>并且some text在内部spandiv将具有class属性会很容易,但没有运气。

我现在正在做的是寻找spana1

//div[contains(@class,'foo')]/div/span[contains(@class,'a1')]

query()然后我得到它的父级并以该父级作为上下文节点再做一次。这看起来远非高效,所以问题显然是是否有更好的方法来实现我的目标?


答案附录

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

//div[contains(@class,'foo')]/div/span[contains(@class,'a1')]/..

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

//div[contains(@class,'foo')]/div/span[contains(@class,'a1')]/../a

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

4

2 回答 2

55

xpath 查询的好处是您可以将它们视为文件系统路径,因此只需

//div[contains(@class,'foo')]/div/span[contains(@class,'a1')]/..
                                                              ^^

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

于 2012-10-13T17:35:15.160 回答
16

比使用 reverse axis更好的表达式

//div[contains(@class,'foo')]/div[span[contains(@class,'a1')]]

这将选择任何div一个divclass属性包含字符串“foo”的子元素,并且(选定的div)具有一个属性包含字符串“a1”的span子元素。class

基于 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>

当此转换应用于提供的 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>

计算 XPath 表达式并将所选元素复制到输出:

<div>
   <span class="a1"/>
   <a href="...">...</a>
</div>
<div>
   <span class="a1"/>some text</div>

二、关于通过其类之一访问 Html 元素的备注

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

不要使用

//div[contains(@class, 'foo')]

使用

//div[@class = 'foo']

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

//div[normalize-space(@class) = 'foo']

一个关键问题

//div[contains(@class, 'foo')]

是这会选择任何div类,例如“myfoo”、“foo2”或“myfoo3”。

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

//div[contains(concat(' ', @class, ' '), ' foo ')]
于 2012-10-13T17:50:57.067 回答