Nokogiri のようなパーサーがどのように機能するかを理解することは重要です。
あなたを助けるために、それは破損した/不正な形式の HTML または XML を修正しようとします。あなたの HTML は不正な形式であるため、Nokogiri がそれを解析するにつれて修正される予定ですが、そのプロセスにより、Nokogiri は HTML をさらに混乱させる可能性があります。それを避けるために、のこぎりに渡す前にコンテンツを前処理するか、後でノードを置き換えて解読する必要があります。
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">
それは物事をほとんど改善せず、代わりにドキュメントをさらにひどく混乱させたでしょう.
代わりに、外科的に問題を解決することをお勧めします。Web の暗黒の黎明期にさかのぼると、膨大な量の不正な形式のコンテンツが見られ、正規表現で処理しなければならないというのが通常の攻撃計画でした。現在、パーサーを使用すると、通常はそれを回避でき、問題を切り分けて、必要なものを選択的に修正できます。そのために必要なコードを見ると、正しく実行するのにそれほど時間はかからないことがわかります。