Ruby Nokogiri SAX解析器在">"(也称为">")处截断字符串

5

背景:我正在使用Ruby的Nokogiri gem来解析一个XML文件。我的问题是,当一个字符串包含>时(这是>的HTML编码),SAX解析器返回一个不完整的结果。例如:

<element>PART1PART2</element> #=> returns "PART1PART2"
<element>PART3&gt;PART4</element> #=> returns "PART3"

我的解析器长这样:

require 'nokogiri'
class MySample < Nokogiri::XML::SAX::Document
  def characters(string)
    puts string
  end
end
# Create a new parser
parser = Nokogiri::XML::SAX::Parser.new(MySample.new)
# Feed the parser some XML
parser.parse_file(ARGV[0])

研究:如果一个字符串包含>,那么Nokogiri会认为这是字符串的结尾。但是,在字符串中有一个>被认为是格式不良好的XML。然而,我的XML格式是正确的,但Nokogiri认为&gt;标记了字符串的结尾。这意味着Nokogiri在解析字符串之前解释了HTML(将&gt;转换为>)。

问题:Nokogiri为什么要解释&gt;的HTML,并如何确保它解析整个字符串?


1年更新(供参考)

自从我第一次发布这个问题以来已经过去了一年多,此时我还没有找到对原始问题的明确答案。因此,我想为将来遇到这篇文章的任何人提供一些更新。请注意,我严格是指SAX解析,而不是DOM解析。

主要观点:

  • 原始问题涉及到Nokogiri v1.6.1。最新版本(撰写本文时)是v1.6.6,但问题仍未解决。

  • 然而,有一种解决这个问题的方法(请参见下面matt的评论),但如果不是所有字符串都格式相同(例如,一个字符串包含&gt;一次,另一个字符串包含两次&gt;等),实现将会很棘手。

  • 我简要测试了另一个名为Ox的Ruby解析器,并发现它没有与Nokogiri相同的问题。确实,它可以正确处理包含&gt;的字符串。此外,它还可以处理包含>的字符串。作为奖励,它似乎比Nokogiri运行得更快(但也不是没有缺点)

底线:

如果您遇到类似Nokogiri的问题,那么建议尝试使用Ox作为可能的替代方案。我不会争辩哪一个gem更好(这不是它的目的)。但是,我可以证明Ox在处理包含&gt;和/或>的字符串的能力方面是值得信赖的。


+1 是对你友善提问的奖励。 - Arup Rakshit
2
这对我来说还可以。请注意,characters方法“可能会在给定一个连续的字符字符串时被调用多次”,在这种情况下(至少对我来说),它被调用了三次——一次是 PART3,一次是实体(>被传递进去),一次是 PART4,所以看起来 Nokogiri(或 libxml)正在围绕实体将字符串分割开。你只看第一次调用时传入的内容吗?你需要缓存多次调用 characters 来形成完整的字符串。 - matt
你说得完全正确。这是我最终实现的解决方法,但并不理想。当每个字符串具有相同数量的 > 时,它可以正常工作,但我的字符串没有。我让它能够工作了,但它非常丑陋,所以我希望关闭 HTML 解释以使事情更清洁。 - seane
另外:在这里使用“>”是有效的(“<”不行,但“>”可以)。 - matt
你说得没错。然而,W3Schools 表示:“大于号是合法的,但最好将其替换为实体。” 我已经采取了这个预防措施,所以(除非我完全错过了什么),我有点失望 Nokogiri 没有相应地处理它。 - seane
1个回答

0

您没有说为什么要使用SAX解析器。当使用DOM解析器解析文档时,Nokogiri会正确地处理该文档:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<root>
  <element>PART1PART2</element>
  <element>PART3&gt;PART4</element>
</root>
EOT

puts doc.to_xml
# >> <?xml version="1.0"?>
# >> <root>
# >>   <element>PART1PART2</element>
# >>   <element>PART3&gt;PART4</element>
# >> </root>

你可能想要与开发人员邮件列表联系。


好的观点。我忘了提到我正在解析的XML文件太大,无法使用DOM解析器加载到内存中。 - seane

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接