Xml 是否有更好的方法获取XPath查询结果的父节点?

Xml 是否有更好的方法获取XPath查询结果的父节点?,xml,dom,xpath,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 cla

有这样的标记:

<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>
然后我得到它的父节点,并使用该父节点作为上下文节点执行另一个
query()
。这看起来远远不够有效,所以问题是,是否有更好的方法来实现我的目标


答案附录

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

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

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

获取
而不是它的容器。

xpath查询的好处在于,您可以将它们本质上看作文件系统路径,因此只需

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

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

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

//div[contains(@class,'foo')]/div[span[contains(@class,'a1')]]
<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>
//div[contains(@class, 'foo')]
//div[@class = 'foo']
//div[contains(@class, 'foo')]
//div[contains(concat(' ', @class, ' '), ' foo ')]
这将选择任何
div
的子级
div
,该子级
class
属性包含字符串“foo”,并且(所选
div
)具有
span
的子级
class
属性包含字符串“a1”

基于XSLT的验证

//div[contains(@class,'foo')]/div[span[contains(@class,'a1')]]
<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>
//div[contains(@class, 'foo')]
//div[@class = 'foo']
//div[contains(@class, 'foo')]
//div[contains(concat(' ', @class, ' '), ' foo ')]
使用

//div[contains(@class,'foo')]/div[span[contains(@class,'a1')]]
<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>
//div[contains(@class, 'foo')]
//div[@class = 'foo']
//div[contains(@class, 'foo')]
//div[contains(concat(' ', @class, ' '), ' foo ')]
或者,如果可能有前导/尾随空格,请使用:

<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>
<div>
   <span class="a1"/>
   <a href="...">...</a>
</div>
<div>
   <span class="a1"/>some text</div>
//div[normalize-space(@class) = 'foo']
一个与有关的关键问题:

//div[contains(@class,'foo')]/div[span[contains(@class,'a1')]]
<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>
//div[contains(@class, 'foo')]
//div[@class = 'foo']
//div[contains(@class, 'foo')]
//div[contains(concat(' ', @class, ' '), ' foo ')]
这将选择任何类为“myfoo”、“foo2”或“myfoo3”的
div

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

//div[contains(@class,'foo')]/div[span[contains(@class,'a1')]]
<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>
//div[contains(@class, 'foo')]
//div[@class = 'foo']
//div[contains(@class, 'foo')]
//div[contains(concat(' ', @class, ' '), ' foo ')]

+1对于文件系统路径的引用,我一直都是这样想的,但我从未听人解释过,因为suchI在问这个问题之前刚刚检查了手册,但似乎我忽略了“.”,因为它显然就在那里。但财政司司长的参考立即表明了这一点。谢谢,是的。当我第一次跳入xpath时,我像这样反复思考了一段时间,但是对我来说,创建querypath关联是一个非常有趣的时刻。。。但是,当您想了解更精细的细节时,将查询视为一条路径是绝对没有帮助的,特别是当您希望有一天更新到XPath2.0时。然后是某种二元运算符,它为左侧的每个节点计算右侧。。。(当我编写XPath解析器时,我花了数周或数月的时间来考虑/作为路径分隔符)不要忘记html允许多个类
@class='foo'
将跳过
class=“foo bar baz”
。因此,@contains是完全有效的,只要(正如您所指出的)注意falsepositives@MarcB,似乎您还没有阅读或理解这个答案——它详细讨论了元素具有多个类的情况。此外,这个答案为这种情况提供了一个正确的解决方案——不像不正确和简单的
contains(@calss,someString)