使用Nokogiri解析带有xhtml:link标签的HTML



我使用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>

I am getting

>>  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页面示例可以在这里找到

如何避免这个错误?

您需要将XML命名空间(在您的示例中为xhtml)添加到根元素中,以便Nokogiri能够识别它,否则Nokogiri将忽略它并出现错误。

你可以这样做:

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

参见this and this answers。

基于注释更新

我查看了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属性最初包含在文档中会发生什么。

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

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

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

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

相关内容

  • 没有找到相关文章

最新更新