【问题标题】:Why is Nokogiri giving me multiple results?为什么 Nokogiri 会给我多个结果?
【发布时间】:2013-10-01 18:25:03
【问题描述】:

我正在尝试使用 Nokogiri 解析 HTML 字符串,但遇到了一些递归问题,我不知道为什么。

给定这些命令:

string = <h3>Lancers were arranged.&nbsp;</h3>
         <div>Gabriel found himself partnered with Miss Ivors.</div>
         <br>She leaned. He lit a <b>candle</b>.
         They followed him in silence, their feet falling in soft thuds on the thickly carpeted stairs.<br>

body = Nokogiri::HTML(string)
result = []
body.traverse { |node| result << node }

我希望有一个上述元素的数组。相反,我得到了这个:

[#<Nokogiri::XML::DTD:0x3fde1f3d5274 name="html">
#<Nokogiri::XML::Text:0x3fde1e88d330 "Lancers were arranged. ">
#<Nokogiri::XML::Element:0x3fde1ea56a68 name="h3" children=[#<Nokogiri::XML::Text:0x3fde1e88d330 "Lancers were arranged. ">]>
#<Nokogiri::XML::Text:0x3fde1e88c764 "Gabriel found himself partnered with Miss Ivors.">
#<Nokogiri::XML::Element:0x3fde1e88cd04 name="div" children=[#<Nokogiri::XML::Text:0x3fde1e88c764 "Gabriel found himself partnered with Miss Ivors.">]>
#<Nokogiri::XML::Element:0x3fde1e88c0fc name="br">
#<Nokogiri::XML::Text:0x3fde1e88b9e0 "She leaned. He lit a ">
#<Nokogiri::XML::Text:0x3fde1eba6c60 "candle">
#<Nokogiri::XML::Element:0x3fde1e88b5f8 name="b" children=[#<Nokogiri::XML::Text:0x3fde1eba6c60 "candle">]>
#<Nokogiri::XML::Text:0x3fde1eba6454 ". They followed him in silence
their feet falling in soft thuds on the thickly carpeted stairs.">
#<Nokogiri::XML::Element:0x3fde1eba5f54 name="br">
#<Nokogiri::XML::Element:0x3fde1ea56f7c name="body" children=[#<Nokogiri::XML::Element:0x3fde1ea56a68 name="h3" children=[#<Nokogiri::XML::Text:0x3fde1e88d330 "Lancers were arranged. ">]>
#<Nokogiri::XML::Element:0x3fde1e88cd04 name="div" children=[#<Nokogiri::XML::Text:0x3fde1e88c764 "Gabriel found himself partnered with Miss Ivors.">]>
#<Nokogiri::XML::Element:0x3fde1e88c0fc name="br">
#<Nokogiri::XML::Text:0x3fde1e88b9e0 "She leaned. He lit a ">
#<Nokogiri::XML::Element:0x3fde1e88b5f8 name="b" children=[#<Nokogiri::XML::Text:0x3fde1eba6c60 "candle">]>
#<Nokogiri::XML::Text:0x3fde1eba6454 ". They followed him in silence
their feet falling in soft thuds on the thickly carpeted stairs.">
#<Nokogiri::XML::Element:0x3fde1eba5f54 name="br">]>
#<Nokogiri::XML::Element:0x3fde1ea575e4 name="html" children=[#<Nokogiri::XML::Element:0x3fde1ea56f7c name="body" children=[#<Nokogiri::XML::Element:0x3fde1ea56a68 name="h3" children=[#<Nokogiri::XML::Text:0x3fde1e88d330 "Lancers were arranged. ">]>
#<Nokogiri::XML::Element:0x3fde1e88cd04 name="div" children=[#<Nokogiri::XML::Text:0x3fde1e88c764 "Gabriel found himself partnered with Miss Ivors.">]>
#<Nokogiri::XML::Element:0x3fde1e88c0fc name="br">
#<Nokogiri::XML::Text:0x3fde1e88b9e0 "She leaned. He lit a ">
#<Nokogiri::XML::Element:0x3fde1e88b5f8 name="b" children=[#<Nokogiri::XML::Text:0x3fde1eba6c60 "candle">]>
#<Nokogiri::XML::Text:0x3fde1eba6454 ". They followed him in silence
their feet falling in soft thuds on the thickly carpeted stairs.">
#<Nokogiri::XML::Element:0x3fde1eba5f54 name="br">]>]>
#<Nokogiri::HTML::Document:0x3fde1f3d6084 name="document" children=[#<Nokogiri::XML::DTD:0x3fde1f3d5274 name="html">
#<Nokogiri::XML::Element:0x3fde1ea575e4 name="html" children=[#<Nokogiri::XML::Element:0x3fde1ea56f7c name="body" children=[#<Nokogiri::XML::Element:0x3fde1ea56a68 name="h3" children=[#<Nokogiri::XML::Text:0x3fde1e88d330 "Lancers were arranged. ">]>
#<Nokogiri::XML::Element:0x3fde1e88cd04 name="div" children=[#<Nokogiri::XML::Text:0x3fde1e88c764 "Gabriel found himself partnered with Miss Ivors.">]>
#<Nokogiri::XML::Element:0x3fde1e88c0fc name="br">
#<Nokogiri::XML::Text:0x3fde1e88b9e0 "She leaned. He lit a ">
#<Nokogiri::XML::Element:0x3fde1e88b5f8 name="b" children=[#<Nokogiri::XML::Text:0x3fde1eba6c60 "candle">]>
#<Nokogiri::XML::Text:0x3fde1eba6454 ". They followed him in silence
their feet falling in soft thuds on the thickly carpeted stairs.">
#<Nokogiri::XML::Element:0x3fde1eba5f54 name="br">]>]>]>] 

抱歉,篇幅较长。谁能帮我弄清楚为什么会这样?和/或如何预防?

【问题讨论】:

  • 请分别粘贴输入输出HTML。不要使用单行字符串或字符串化对象。这很难理解,如果你这样做了,我想你会发现问题(Element 对象包括他们的孩子,即使是字符串化的)。

标签: ruby-on-rails ruby ruby-on-rails-3 nokogiri


【解决方案1】:

发生这种情况是因为traverse 递归地调用了它自己及其所有子级提供的块。因此,它将您的 html 字符串的每个节点添加到 result 数组,而不仅仅是顶级节点。您看到的“多个结果”是为 Nokogiri 节点定义 inspect 的结果。例如,返回数组中的第 3 个元素表示 h3 节点,但也会打印其所有子节点,其中包括作为数组的第 2 个元素的 text 节点。

如果您希望result 包含对文档中每个节点的引用,那么这是正确的方法。如果您只想要顶级节点,请使用children

【讨论】:

    【解决方案2】:

    当您解析不完整的 html 时,Nokogiri 会自动添加 doctype 以及 html 和 body 元素。您必须像这样解析它以避免这种行为:

    body = Nokogiri::HTML::DocumentFragment.parse(your_html)
    

    如果您希望结果是不包括文本节点的元素数组,您可以这样做:

    result = body.xpath('./*')
    

    那么结果(为了清楚起见转换为字符串)将是:

    ["<h3>Lancers were arranged. </h3>",
     "<div>Gabriel found himself partnered with Miss Ivors.</div>",
     "<br>",
     "<b>candle</b>",
     "<br>"]
    

    【讨论】:

    • 这似乎解决了一半的问题。重复次数明显减少,但像第一个 &lt;h3&gt; 这样的元素会重复两次。
    • 刚刚试了,没有重复,这是我得到的["text", "h3", "text", "div", "br", "text", "text" ,“b”,“文本”,“br”,“#document-fragment”]。也许最后一个元素让你感到困惑。它就是你所说的遍历的整个片段。
    • 那是如此接近。 xpath('./*') 会删除元素中的所有 not 内容。 HTML 代码的问题在于它是自动生成的,我无法预测哪些段落会被换行,哪些不会。
    • * 不包括文本节点。你可以做类似./*|./text() 的事情,但使用children 更简单,就像@Alex Bullard 说的那样。
    • 现在工作。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2014-08-14
    • 1970-01-01
    • 1970-01-01
    • 2012-07-30
    • 2016-02-07
    • 1970-01-01
    • 1970-01-01
    • 2023-02-07
    相关资源
    最近更新 更多