使用Nokogiri用xhtml解析HTML:link标签?

时间:2014-06-18 10:09:08

标签: html ruby xpath nokogiri

我正在使用Nokogiri gem来解析HTML数据。

$ gem list nokogiri

*** LOCAL GEMS ***

nokogiri (1.6.2.1)

示例HTML是:

<html>
  <body>
    <xhtml:link>
      <div>
    Some content.
      </div>
    </xhtml:link>
  </body>
</html>

我正在

>>  doc.xpath('/html/body/xhtml:link/div')
Nokogiri::XML::XPath::SyntaxError: Undefined namespace prefix: /html/body/xhtml:link/div
    from /var/lib/gems/1.9.1/gems/nokogiri-1.6.2.1/lib/nokogiri/xml/node.rb:159:in `evaluate'
    from /var/lib/gems/1.9.1/gems/nokogiri-1.6.2.1/lib/nokogiri/xml/node.rb:159:in `block in xpath'
    from /var/lib/gems/1.9.1/gems/nokogiri-1.6.2.1/lib/nokogiri/xml/node.rb:150:in `map'
    from /var/lib/gems/1.9.1/gems/nokogiri-1.6.2.1/lib/nokogiri/xml/node.rb:150:in `xpath'
    from (irb):95
    from /usr/bin/irb:12:in `<main>'

可以找到完整的示例实时HTML页面here

如何避免此错误?

2 个答案:

答案 0 :(得分:2)

您需要将XML命名空间(在您的示例中为xhtml)添加到您的根元素,以便Nokogiri识别它,除非您这样做,Nokogiri将忽略它并且将出现该错误。

你可以这样做:

<html xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <body>
        <xhtml:link>
            <div>Some content.</div>
        </xhtml:link>
    </body>
</html>

另请参阅thisthis个答案。

根据评论更新

我查看了Nokogiri文档并找到了两个解决方法,一个是传递名称空间:

doc.xpath('/html/body/xhtml:link/div', 'xhtml' => 'http://www.w3.org/1999/xhtml')

另一种方法是手动将该命名空间添加到根文档中:

doc.root.add_namespace 'xhtml', 'http://www.w3.org/1999/xhtml'
doc.xpath('/html/body/xhtml:link/div')

虽然 两种方式都使这个错误无声,但两种情况下的查询都只为我返回一个空数组,这与xmlns属性最初包含在文档中的情况不同。 / p>

答案 1 :(得分:0)

如果您确定在同一上下文中没有带有相同名称的无前缀元素,则可以忽略命名空间。命名空间会影响元素和属性名称。如果您使用node()*选择它们,则可以在谓词中测试local-name(),而无需处理命名空间。

在您的示例中,您可以通过在xhtml:link的上下文中选择所有元素来选择body元素,然后将结果集限制为仅具有 local-name 等于link

doc.xpath('/html/body/*[local-name()="link"]/div')

可能选择不需要的HTML <link>元素(如果它们出现在正文中)(它们永远不应该存在,但HTML解析器并不关心它们是否存在)。但如果它们发生,它们应该是空元素。内部永远不会有<div>,所以你很安全。