使用Nokogiri和XPath获取具有多个属性的节点

时间:2010-08-29 01:51:17

标签: ruby xpath nokogiri

我正在尝试使用Nokogiri来解析一个带有一些相当古怪的标记的HTML文件。具体来说,我正在尝试抓取同时定义了id,多个类和样式的div。标记看起来像这样:

<div id="foo">
  <div id="bar" class="baz bang" style="display: block;">
    <h2>title</h2>
    <dl>
      List of stuff
    </dl>
  </div>
</div>

我正试图抓住位于问题div内的<dl>。我可以使用单个id属性获得没有问题的div,但是我无法想出让Nokogiri用id 类来获取div的方法。所以这些工作正常:

content = @doc.xpath("//div[id='foo']")

content = @doc.css('div#foo')

但这些不会返回任何内容:

content = @doc.xpath("//div[id='bar']")

content = @doc.xpath("div#bar")

我有什么明显的遗漏吗?

5 个答案:

答案 0 :(得分:4)

  

我可以通过一个id获得div   属性没有问题,但我不能   找出一种获得Nokogiri的方法   用两个ID抓住div   类。

你想要

//div[id='bar' and class='baz bang' and style='display: block;']

答案 1 :(得分:2)

以下适用于我。

require 'rubygems'
require 'nokogiri'

html = %{
<div id="foo">
  <div id="bar" class="baz bang" style="display: block;">
    <h2>title</h2>
    <dl>
      List of stuff
    </dl>
  </div>
</div>
}

doc = Nokogiri::HTML.parse(html)
content = doc
  .xpath("//div[@id='foo']/div[@id='bar' and @class='baz bang']/dl")
  .inner_html

puts content

答案 2 :(得分:1)

我认为content = @doc.xpath("div#bar")是一个拼写错误,应该是content = @doc.css("div#bar")或更好content = @doc.css("#bar")。第二个代码块中的第一个表达式似乎没问题。

答案 3 :(得分:1)

您写道:

  

我正试图抓住那些拥有的div   两个ID,多个类和样式   定义

并且

  

我正试图抓住问题div中的<dl>

所以,这个XPath 1.0:

//div[@id][contains(normalize-space(@class),' ')][@style]/dl

答案 4 :(得分:0)

我强烈建议使用CSS选择器而不是XPath作为起点,因为CSS更具可读性,并且不太可能导致视觉噪音。

require 'nokogiri'

doc = Nokogiri::HTML(<<EOT)
<div id="foo">
  <div id="bar" class="baz bang" style="display: block;">
    <h2>title</h2>
    <dl>
      List of stuff
    </dl>
  </div>
</div>
EOT

解析后,使用CSS查找<div ... id="foo">

doc.at('div#foo').to_html 
# => "<div id=\"foo\">\n" +
#    "  <div id=\"bar\" class=\"baz bang\" style=\"display: block;\">\n" +
#    "    <h2>title</h2>\n" +
#    "    <dl>\n" +
#    "      List of stuff\n" +
#    "    </dl>\n" +
#    "  </div>\n" +
#    "</div>"

还有<div id="bar">

doc.at('div#bar').to_html 
# => "<div id=\"bar\" class=\"baz bang\" style=\"display: block;\">\n" +
#    "    <h2>title</h2>\n" +
#    "    <dl>\n" +
#    "      List of stuff\n" +
#    "    </dl>\n" +
#    "  </div>"

我们可以搜索具有两个类名称的标签:


doc.at('.baz.bang').to_html
# => "<div id=\"bar\" class=\"baz bang\" style=\"display: block;\">\n" +
#    "    <h2>title</h2>\n" +
#    "    <dl>\n" +
#    "      List of stuff\n" +
#    "    </dl>\n" +
#    "  </div>"

我们可以查找带有两个类及其嵌入式<dl>标签的显式div:

doc.at('div.baz.bang dl').to_html
# => "<dl>\n" +
#    "      List of stuff\n" +
#    "    </dl>"

或者甚至通过ID和类别:

doc.at('div#bar.baz.bang').to_html
# => "<div id=\"bar\" class=\"baz bang\" style=\"display: block;\">\n" +
#    "    <h2>title</h2>\n" +
#    "    <dl>\n" +
#    "      List of stuff\n" +
#    "    </dl>\n" +
#    "  </div>"

使用<dl>

doc.at('div#bar.baz.bang dl').to_html
# => "<dl>\n" +
#    "      List of stuff\n" +
#    "    </dl>"

我正在使用at,与使用search(...some selector...).first等效。 Nokogiri支持searchcssxpath,它们是CSS和XPath的变体,并且返回NodeSet以及atat_css和{{1} },它返回一个Node。了解“ NodeSet”和“ Node”之间的区别以及它们与at_xpathSearchable的关系非常重要,因此请阅读文档。