【问题标题】:Using Nokogiri to parse HTML with xhtml:link tag?使用 Nokogiri 解析带有 xhtml:link 标签的 HTML?
【发布时间】:2014-06-18 10:09:08
【问题描述】:

我正在使用 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>'

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

我怎样才能避免这个错误?

【问题讨论】:

  • 不是真正的问题,但您似乎错过了关闭body 标签。
  • 你不能doc.xpath('/html/body/link/div')吗?
  • 我通过检查 Firebug 中的元素来获取 xpath。这适用于其他文档,但只要元素标签中有冒号“:”,就会出现上述错误。
  • 您是在解析为 HTML 还是 XML?如果您解析为 HTML,那么 Nokogiri 会带有命名空间,所以您可以使用 link

标签: html ruby xpath nokogiri


【解决方案1】:

您需要将 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')

虽然两种方式 do 都可以消除错误,但两种情况下的查询都只为我返回一个空数组,这与 xmlns 属性最初包含在文档中时发生的情况不同。

【讨论】:

  • 我无法修改现有的 HTML,因为它来自外部源。那么我可以向 Nokigiri 提供命名空间,以便它可以在不修改 HTML 内容的情况下解析吗?
【解决方案2】:

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

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

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

如果它们出现在正文中,您可能选择不需要的 HTML &lt;link&gt; 元素(它们不应该存在,但 HTML 解析器不在乎它们是否存在)。但如果它们出现,它们应该是空元素。里面永远不会有&lt;div&gt;,所以你很安全。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-02
  • 1970-01-01
  • 1970-01-01
  • 2013-11-14
  • 2011-11-16
相关资源
最近更新 更多