我从XML文件中读取了一些内容:
page_content = doc.xpath("/somenode/body").inner_text
此内容包含一些数据:
<p> Hello World, ""How are you today""
<a href=""www.hello.comm"">Hello</a>
etc.
</p>
如您所见,某些内容用两对双引号括起来。
我想要的结果是用一对双引号替换两对双引号:
<p> Hello World, "How are you today"
<a href="www.hello.comm">Hello</a>
etc.
</p>
我尝试的是:
page_content.gsub!(/[""]/, '"')
page_content.gsub!("""", '"')
这似乎不能完成这项工作。 关于如何获得预期结果的任何建议?
了解像Nokogiri这样的解析器是如何工作的是很重要的。
为了帮助您,它会尝试修复损坏/格式错误的 HTML 或 XML。您的HTML格式不正确,因此在Nokogiri解析它时将对其进行修复,但是,该过程可能会使Nokogiri进一步破坏HTML。为了避免这种情况,我们有时必须在将内容交给Nokogiri之前对其进行预处理,或者之后必须通过替换节点来解开它。
require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)
<p> Hello World, ""How are you today""
<a href=""www.hello.comm"">Hello</a>
etc.
</p>
EOT
这会将 HTML 解析为 DOM。
doc.at('p').to_html
# => "<p> Hello World, ""How are you today""n<a href="" www.hello.comm>Hello</a>netc.n</p>"
处理文本""How are you today""
时没有任何重整,因为它是一个文本节点:
doc.at('p').child.class # => Nokogiri::XML::Text
doc.at('p').child.content # => " Hello World, ""How are you today""n"
解析后很容易修复:
doc.at('p').child.content = doc.at('p').child.content.gsub('""', '"')
# => " Hello World, "How are you today"n"
尝试修复<a>
标签的参数是完全不同的情况,因为到那时,Nokogiri 已经修复了双引号,导致标记错误:
doc.at('a').to_html
# => "<a href="" www.hello.comm>Hello</a>"
请注意,www.hello.comm
已在其包含引号之外提升。
要解决此问题,需要在将HTML交给Nokogiri之前进行一些预处理,或者修复节点并用修复的节点替换损坏的节点。
以下是预处理<a>
标记的基础:
html = <<EOT
<p> Hello World, ""How are you today""
<a href=""www.hello.comm"">Hello</a>
etc.
</p>
EOT
html.gsub(/href=""([^"]+)""/, 'href="1"')
# => "<p> Hello World, ""How are you today""n<a href="www.hello.comm">Hello</a>netc.n</p>n"
如果你走那条路,不要花哨。编写小的原子更改,以避免在 HTML 更改时破坏模式。
一个更健壮的方法(其中"健壮"比我们通常使用解析器得到的要少一些)是:
bad_a = doc.at('a')
fixed_a = bad_a.to_html.gsub(/""s([^>]+)>/, '"1">')
bad_a.replace(fixed_a)
doc.at('p')
# => #(Element:0x3fe4ce9de9e4 {
# name = "p",
# children = [
# #(Text " Hello World, "How are you today"n"),
# #(Element:0x3fe4ce9e0fdc {
# name = "a",
# attributes = [
# #(Attr:0x3fe4ce9e0fa0 {
# name = "href",
# value = "www.hello.comm"
# })],
# children = [ #(Text "Hello")]
# }),
# #(Text "netc.n")]
# })
doc.at('p').to_html
# => "<p> Hello World, "How are you today"n<a href="www.hello.comm">Hello</a>netc.n</p>"
可以使用毯子gsub
来按摩文本,但这在大型/复杂文档中具有很高的附带损害风险。想象一下,如果文档会发生什么情况,如果
html.gsub('""', '"')
当有许多标签包含空字符串时使用,例如:
<input value="" name="foo"><input value="" name="bar">
搜索/替换的结果将是:
<input value=" name="foo"><input value=" name="bar">
这几乎不会改善事情,相反,它会进一步严重破坏文档。
相反,最好通过手术解决问题。回到黑暗的、早期的、网络先驱的日子里,我们曾经看到大量畸形的内容,不得不用正则表达式处理它是正常的攻击计划。现在,使用解析器,我们通常可以避免它,并且可以隔离问题并有选择地修复我们想要的内容。查看这样做所需的代码表明,正确完成它并不需要很多。
page_content.gsub!('""', '"')
page_content.gsub!(/"{2}/, '"')
rubular.com
a='<p> Hello World, ""How are you today""
<a href=""www.hello.comm"">Hello</a>
etc.
</p>'
a.gsub! '""', '"'
[19] pry(main)> puts a
<p> Hello World, "How are you today"
<a href="www.hello.comm">Hello</a>
etc.
</p>