Ruby Nokogiri SAX 解析器在 “>” 处截断字符串(又名“>”)

Ruby Nokogiri SAX parser truncates strings at ">" (aka ">")

提问人:seane 提问时间:4/11/2014 最后编辑:Communityseane 更新时间:6/12/2015 访问量:521

问:

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

<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 认为这是字符串的结尾。在字符串中包含 a 将被视为格式不佳的 XML。但是,我的 XML 格式正确,但 Nokogiri 认为这标志着字符串的末尾。这意味着 Nokogiri 在解析字符串之前会解释 HTML(转换为 )。>>&gt;&gt;>

问题:为什么 Nokogiri 要解释 的 HTML,我怎样才能确保它解析完整的字符串?&gt;


1 年更新 (FWIW)

自从我第一次发布这个问题以来已经一年多了,在这个时间点上,我还没有找到我最初问题的明确答案。因此,我想我会为将来遇到这篇文章的任何人提供一些更新。请记住,严格来说,我是 SAX 解析,而不是 DOM 解析。

要点:

  • 最初的问题与 Nokogiri v1.6.1 有关。最新版本(在撰写本文时)是 v1.6.6,但问题仍未解决。

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

  • 我简要测试了另一个名为 Ox 的 Ruby 解析器,发现它没有与 Nokogiri 相同的问题。事实上,它可以正确处理包含 .此外,它还可以处理包含 .作为奖励,它的性能似乎比 Nokogiri 快(但它并非没有缺点)。&gt;>

底线:

如果您在使用 Nokogiri 时遇到类似的问题,那么我建议您查看 Ox 作为可能的替代方案。我不会争辩说一种宝石比另一种更好(这不是目的)。但是,我可以保证 Ox 能够处理包含和/或 .&gt;>

Ruby XML XML 解析 nokogiri sax

评论

0赞 Arup Rakshit 4/11/2014
+1 以良好的方式提出问题..
2赞 matt 4/11/2014
这对我来说没问题。请注意,characters 方法“可能会在给定一个连续的字符串的情况下多次调用”,在这种情况下(至少对我而言),它被调用了三次——一次是 ,一次用于实体(传入),一次是 ,所以看起来 Nokogiri(或 libxml)正在围绕实体拆分字符串。你只看第一次调用时传递的内容吗?您需要缓冲多个调用以形成完整的字符串。PART3>PART4characters
0赞 seane 4/11/2014
你是绝对正确的。这是我最终实现的解决方法,但并不理想。当每个字符串都有相同数量的 's 时,它工作正常,但我的字符串没有。我让它工作,但它非常丑陋,所以我希望关闭 HTML 解释以使事情更干净。>
0赞 matt 4/11/2014
另外:在这里实际上有效(不会,但没关系)。><>
0赞 seane 4/11/2014
你是对的。然而,W3Schools说,“大于性格是合法的,但取代它是一个好习惯。我已经采取了这种预防措施,所以(除非我完全遗漏了什么)我对 Nokogiri 没有相应地处理它感到有点失望。

答:

0赞 the Tin Man 4/11/2014 #1

你没有说你为什么要尝试使用 SAX 解析器。Nokogiri 在使用 DOM 解析器解析文档时会正确处理文档:

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>

您可能需要与开发人员的邮件列表进行核实。

评论

0赞 seane 4/11/2014
好点子。我忘了提到我正在解析的 XML 文件太大,无法使用 DOM 解析器加载到内存中。