获取节点中的特定标记?

时间:2014-06-26 13:55:02

标签: ruby xml xpath nokogiri

我使用Ruby,XPath和Nokogiri并尝试从以下XML中检索d1

<a>
  <b1>
    <c>
      <d1>01/11/2001</d1>
      <d2>02/02/2004</d2>
    </c>
  </b1>
</a>

这是我循环中的代码:

rs = doc.xpath("//a/b1/c/d1").inner_text

puts rs

它什么都不返回(没有错误)。

我想在<d1>中获取文字。

2 个答案:

答案 0 :(得分:2)

您不会在xpath查询中询问文本内容:

rs = doc.xpath('//a/b1/c/d1/text()')

答案 1 :(得分:2)

您滥用XPath:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<a>
  <b1>
    <c>
      <d1>01/11/2001</d1>
      <d2>02/02/2004</d2>
    </c>
  </b1>
</a>
EOT

doc.at('/a/b1/c/d1').text # => "01/11/2001"
doc.at('//d1').text # => "01/11/2001"
XPath-ese中的

//表示从顶部开始,查看文档中的任何位置。相反,如果您要提供显式/绝对选择器,请从文档顶部开始,然后使用'/a/b1/c/d1'向下钻取。或者,做一件简单的事情,让解析器使用//d1在文档中搜索该特定节点。如果您知道该节点的单个实例,则可以这样做。

在上面的代码中,我使用at代替xpathat返回第一个匹配节点,类似于使用xpath('//d1').firstxpath返回NodeSet,类似于节点数组,而at仅返回Node。在NodeSet上使用inner_text可能无法提供您想要的结果,这将是特定节点的文本,因此请小心。

doc.xpath('/a/b1/c/d1/text()').class # => Nokogiri::XML::NodeSet

doc.xpath('//c').inner_text # => "\n      01/11/2001\n      02/02/2004\n    "
doc.xpath('/a/b1/c/d1').first.text # => "01/11/2001"

请看以下几行。我没有使用XPath选择器,而是使用了CSS,它往往更具可读性。 Nokogiri支持两者。

doc.at('d1').text # => "01/11/2001"
doc.at('a b1 c d1').text # => "01/11/2001"

另外,请注意从这两行返回的数据类型:

doc.at('/a/b1/c/d1/text()').class # => Nokogiri::XML::Text
doc.at('/a/b1/c/d1').text.class # => String

虽然告诉解析器在text()内找到<d1>节点似乎很好/聪明,但是返回的内容不是文本,需要进一步访问才能生成它可以使用,所以请考虑放弃使用text(),除非你确切知道为什么需要它:

doc.at('/a/b1/c/d1/text()').text # => "01/11/2001"

最后,Nokogiri有许多用于定位节点的方法。如上所述,xpath返回一个NodeSet,at返回一个Node。 xpath实际上是Nokogiri search方法的XPath特定版本。 searchcssxpath都返回NodeSet。 atat_cssat_xpath都返回节点。当您有一个模糊的选择器需要特别用作CSS或XPath时,CSS和XPath变体很有用。大部分时间Nokogiri可以自己判断它是CSS还是XPath并且会做正确的事情,所以可以使用通用的searchat来实现你编码的大部分。当您必须指定一个或另一个时,请使用特定版本。