Как обернуть текстовые элементы без тегов с помощью Nokogiri? - PullRequest
1 голос
/ 06 июня 2011

Например, у меня есть строка html:

<span class="no">1172</span><span class="r">case</span> primary_key_prefix_type

Как обернуть каждый элемент, у которого нет тега от Nokogiri, так:

<span class="no">1172</span><span class="r">case</span> <span>primary_key_prefix_type</span>

1 Ответ

1 голос
/ 06 июня 2011

Это не самое элегантное решение, но оно работает:

require 'nokogiri'

# Given a node, find each whitespace-delimited word
# and wrap it in the supplied markup
def wrap_text( node, wrapper='<span />' )
  wrapper = Nokogiri::XML::DocumentFragment.parse(wrapper).children.first
  node.xpath('child::text()').each do |text_node|
    text_node.swap( text_node.text.gsub(/(\s*)(\S+)(\s*)/) do
      "#{$1}#{
        wrapper.clone.tap{ |w| w.inner_html = $2 }.to_html
      }#{$3}"
    end )
  end
  node
end    

# Testing
html = Nokogiri::HTML '<body>
  <p><span class="no">1172</span><span class="r">case</span> primary_key_prefix_type</p>
  <p>Hello <b>cool</b> world #42!</p>
</body>'

html.search('p').each{ |para| wrap_text(para) }
puts html.at('body')
#=> <body>
#=>   <p><span class="no">1172</span><span class="r">case</span> <span>primary_key_prefix_type</span></p>
#=>   <p><span>Hello</span> <b>cool</b> <span>world</span> <span>#42!</span></p>
#=> </body>

Редактировать : Дополнительные примеры:

# If your lines don't have element wrapping them...
raw = [
  '<span class="no">1172</span><span class="r">case</span> primary_key',
  'Hello <b>cool</b> world #42!'
]
puts raw.map{ |line| wrap_text(Nokogiri::HTML(line).at('body')).inner_html }
#=> <span class="no">1172</span><span class="r">case</span> <span>primary_key</span>
#=> <p>Hello <b>cool</b> world #42!</p>

# If your lines each have exactly one element wrapping them...
wrapped = [
  '<a><span class="no">1172</span><span class="r">case</span> primary_key</a>',
  '<b>Hello <b>cool</b> world #42!</b>'
]
body = Nokogiri::HTML(wrapped.join("\n")).at('body')
puts body.children.map{ |e| wrap_text(e) }
#=> <a><span class="no">1172</span><span class="r">case</span> <span>primary_key</span></a>
#=> <b><span>Hello</span> <b>cool</b> <span>world</span> <span>#42!</span></b>
...