【问题标题】:Nokogiri replace inner text with <span>ed wordsNokogiri 用 <span>ed 词替换内部文本
【发布时间】:2011-09-13 15:28:04
【问题描述】:

这是一个 HTML 片段示例:

<p class="stanza">Thus grew the tale of Wonderland:<br/>
  Thus slowly, one by one,<br/>
  Its quaint events were hammered out -<br/>
  And now the tale is done,<br/>
  And home we steer, a merry crew,<br/>
  Beneath the setting sun.<br/></p>

我需要用&lt;span id="w0"&gt;Thus &lt;/span&gt; 包围每个单词,如下所示:

<span id='w1'>Anon,</span> <span id='w2'>to</span> <span id='w3'>sudden</span> 
<span id='w4'>silence</span> <span id='w5'>won,</span> ....

我写了这个,它创建了新的片段。如何以旧换新?

def callchildren(n)
  n.children.each do |n| # call recursively until arrive at a node w/o children
    callchildren(n)
  end
  if n.node_type == 3 && n.to_s.strip.empty? != true 
    new_node = ""
    n.to_s.split.each { |w|
      new_node = new_node + "<span id='w#{$word_number}'>#{w}</span> "
      $word_number += 1
    }  
    # puts new_node 
    # HELP? How do I get new_node swapped in?
  end
end

【问题讨论】:

    标签: ruby replace nokogiri html swap


    【解决方案1】:

    我尝试为您的问题提供解决方案:

    require 'nokogiri'
    
    Inf = 1.0/0.0
    
    def number_words(node, counter = nil)
      # define infinite counter (Ruby >= 1.8.7)
      counter ||= (1..Inf).each
      doc = node.document
    
      unless node.is_a?(Nokogiri::XML::Text)
        # recurse for children and collect all the returned
        # nodes into an array
        children = node.children.inject([]) { |acc, child|
          acc += number_words(child, counter)
        }
        # replace the node's children
        node.children = Nokogiri::XML::NodeSet.new(doc, children)
        return [node]
      end
    
      # for text nodes, we generate a list of span nodes
      # and return it (this is more secure than OP's original
      # approach that is vulnerable to HTML injection)n
      node.to_s.strip.split.inject([]) { |acc, word|
        span = Nokogiri::XML::Node.new("span", node)
        span.content = word
        span["id"] = "w#{counter.next}"
        # add a space if we are not at the beginning
        acc << Nokogiri::XML::Text.new(" ", doc) unless acc.empty?
        # add our new span to the collection
        acc << span
      }
    end
    
    # demo
    if __FILE__ == $0
      h = <<-HTML
      <p class="stanza">Thus grew the tale of Wonderland:<br/>
        Thus slowly, one by one,<br/>
        Its quaint events were hammered out -<br/>
        And now the tale is done,<br/>
        And home we steer, a merry crew,<br/>
        Beneath the setting sun.<br/></p>
      HTML
    
      doc = Nokogiri::HTML.parse(h)
      number_words(doc)
      p doc.to_xml
    end
    

    【讨论】:

    • 我是 Ruby 新手,我不得不说我真的很喜欢无限循环结构和 .inject 的使用。该死的优雅。我认为我的问题不是“完全”包含 nokogiri 和添加节点的需要。非常感谢。而且我更聪明。
    【解决方案2】:

    给定doc 中的 Nokogiri::HTML::Document,您可以执行以下操作:

    i = 0
    doc.search('//p[@class="stanza"]/text()').each do |n|
        spans = n.content.scan(/\S+/).map do |s|
            "<span id=\"w#{i += 1}\">" + s + '</span>'
        end
        n.replace(spans.join(' '))
    end
    

    【讨论】:

    • 这也有效,但在不同的、更复杂的 html 布局中并不普遍。非常感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 2013-09-05
    • 1970-01-01
    • 2016-05-09
    • 1970-01-01
    • 2022-06-10
    • 2021-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多