使用Nokogiri替换标签 - 更快捷的方式?

时间:2015-04-15 16:53:17

标签: html css ruby nokogiri

我在名为html_data的变量中有以下HTML,我希望用<img>标记替换<a>标记,并且“img”标记的src参数变为“{”标签的href

现有HTML:

<!DOCTYPE html>
<html>
   <head>
      <title>Learning Nokogiri</title>
   </head>
   <body marginwidth="6">
      <div valign="top">
         <div class="some_class">
            <div class="test">
               <img src="apple.png" alt="Apple" height="42" width="42">
               <div style="white-space: pre-wrap;"></div>
            </div>
         </div>
      </div>
   </body>
</html>

这是我的解决方案A:

nokogiri_html = Nokogiri::HTML(html_data)
nokogiri_html("img").each { |tag|
        a_tag = Nokogiri::XML::Node.new("a", nokogiri_html)
        a_tag["href"] = tag["src"]
        tag.add_next_sibling(a_tag)
        tag.remove()
}

puts 'nokogiri_html is', nokogiri_html

这是我的解决方案B:

nokogiri_html = Nokogiri::HTML(html_data)
nokogiri_html("img").each { |tag|
        tag.name= "a";
        tag.set_attribute("href" , tag["src"])
}

puts 'nokogiri_html is', nokogiri_html

虽然解决方案A工作正常,但我正在寻找使用Nokogiri更快/直接替换标签的方法。使用解决方案B,我的“img”标签确实被“a”标签取代,但“img”标签的属性仍然保留在“a”标签内。以下是解决方案B的结果:

<!DOCTYPE html>
<html>
   <body>
      <p>["\n", "\n", "   </p>
      \n", "      
      <title>Learning Nokogiri</title>
      \n", "   \n", "   \n", "      
      <div valign='\"top\"'>
         \n", "         
         <div class='\"some_class\"'>
            \n", "            
            <div class='\"test\"'>
               \n", "               <a src="%5C%22apple.png%5C%22" alt='\"Apple\"' height='\"42\"' width='\"42\"' href="%5C%22apple.png%5C%22"></a>\n", "               
               <div style='\"white-space:' pre-wrap></div>
               \n", "            
            </div>
            \n", "         
         </div>
         \n", "      
      </div>
      \n", "   \n", ""]
   </body>
</html>

有没有办法使用Nokogiri在HTML中更快地替换标签?另外如何删除“\ n”s得到的结果?

1 个答案:

答案 0 :(得分:0)

首先,请将您的样本数据(HTML)剥离到证明问题所需的最基本数量。

以下是做你想做的事情的基础:

require 'nokogiri'

doc = Nokogiri::HTML(<<EOT)
<!DOCTYPE html>
<html>
   <body>
     <img src="apple.png" alt="Apple" height="42" width="42">
   </body>
</html>
EOT

doc.search('img').each do |img|
  src, alt = %w[src alt].map{ |p| img[p] }
  img.replace("<a href='#{ src }'>#{ alt }</a>")
end

doc.to_html
# => "<!DOCTYPE html>\n<html>\n   <body>\n     <a href=\"apple.png\">Apple</a>\n   </body>\n</html>\n"

puts doc.to_html
# >> <!DOCTYPE html>
# >> <html>
# >>    <body>
# >>      <a href="apple.png">Apple</a>
# >>    </body>
# >> </html>

这样做可以让Nokogiri干净地替换节点。

没有必要做所有这些严峻的事情:

a_tag = Nokogiri::XML::Node.new("a", nokogiri_html)
a_tag["href"] = tag["src"]
tag.add_next_sibling(a_tag)
tag.remove()

相反,创建一个字符串作为您要使用的标记,让Nokogiri将字符串转换为节点并替换旧节点:

src, alt = %w[src alt].map{ |p| img[p] }
img.replace("<a href='#{ src }'>#{ alt }</a>")

没有必要在节点之间删除无关的空白。它可以影响HTML的外观,但浏览器会吞噬那些额外的空格而不显示它。

Nokogiri可以被告知不输出节点间空白,导致压缩/乱码输出,但如何做到这一点是一个单独的问题。