简体   繁体   English

Nokogiri用<span>ed单词</span>替换内部文本

[英]Nokogiri replace inner text with <span>ed words

Here's an example HTML fragment: 这是一个示例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>

I need to surround each word with a <span id="w0">Thus </span> like this: 我需要用<span id="w0">Thus </span>围绕每个单词,如下所示:

<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> ....

I written this which creates the new fragment. 我写了这个创建了新的片段。 How do I replace/swap the new for old? 如何更换/更换旧的?

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

My attempt to provide a solution for your problem: 我试图为您的问题提供解决方案:

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

Given a Nokogiri::HTML::Document in doc , you could do something like this: 给定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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM