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

时间:2012-10-13 17:32:45

标签: xml dom xpath

有这样的标记:

<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,我有兴趣让所有spana1 。因此,在整个代码的末尾,我的结果应该是来自第一个<a>的{​​{1}}和来自第三个的div。如果some text<a>位于some textspan内有div属性,那就很容易了,但没有运气。

我现在正在做的是class使用span类:

a1

然后我得到它的父节点并用该父节点做另一个//div[contains(@class,'foo')]/div/span[contains(@class,'a1')] 作为上下文节点。这看起来远非有效,所以问题显然是否有更好的方法来实现我的目标?


答案附录

根据@MarcB accepted answer,要使用的正确查询是:

query()

但对于//div[contains(@class,'foo')]/div/span[contains(@class,'a1')]/.. ,最好使用:

<a>

获取//div[contains(@class,'foo')]/div/span[contains(@class,'a1')]/../a 而不是其容器。

2 个答案:

答案 0 :(得分:55)

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

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

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

答案 1 :(得分:16)

表达更好而不是使用反向轴

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

这会选择div的{​​{1}}个孩子div,其class属性包含字符串“foo”,并且(所选的div)有{span 1}} class属性包含字符串“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>

在提供的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>

<强> II。关于通过其中一个类访问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 ')]