我需要处理HTML文档并在几个地方插入一些节点。我正在处理的内容无效,但Nokogiri足够聪明,可以弄清楚它应该是什么。问题是我不想更改原始文档的格式,除了我要插入的部分。
以下是一个例子:
require 'nokogiri'
orig_html = '
<html>
<meta name="Generator" content="Microsoft Word 97 O.o">
<body>
1
<b><p>2</p></b>
3
</body>
</html>'
puts Nokogiri::HTML(orig_html).inner_html
# >> <html>
# >> <head>
# >> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
# >> <meta name="Generator" content="Microsoft Word 97 O.o">
# >> </head>
# >> <body>
# >> 1
# >> <b></b><p>2</p>
# >> 3
# >> </body>
# >> </html>
我希望输出与输入相同。问题是我在<p>
内无法<b>
。我倾向于切换到XML,但是有一些无效的标签,例如<meta>
标签,它没有关闭。 HTML非常聪明,可以识别这一点,但XML不是。
答案 0 :(得分:2)
Nokogiri正在修复格式错误的HTML,以使其可解析。完成后,DOM处于合理状态,但Nokogiri不再提供原始文档。
如果您希望原件不受影响,您必须在将其传递给Nokogiri之前使其有效,然后您可以使用Nokogiri的方法对其进行操作。通常我会使用一些正则表达式找到问题点并添加/调整标签或其相关的结束标签,以允许Nokogiri解析而无需修复。
这不是HTML比XML更聪明的情况,它是Nokogiri尊重XML规范精神的一个例子,这是严格的,并且通过在文件填充错误时填充errors
数组来引发标记。无效。 HTML具有较不严格的规范,并且,因为浏览器在解析和显示HTML时(过于)宽容,Nokogiri会稍微进行修复,然后填充errors
数组。 (在任何一种情况下,您都可以检查该数组以查看错误。)
require 'nokogiri'
orig_html = '
<html>
<meta name="Generator" content="Microsoft Word 97 O.o">
<body>
1
<b><p>2</p></b>
3
</body>
</html>'
doc = Nokogiri::HTML(orig_html)
doc.errors
doc.errors
包含:
[
[0] #<Nokogiri::XML::SyntaxError: Unexpected end tag : b>
]
以下是我如何使用Nokogiri修复您的示例HTML:
doc = Nokogiri::HTML(orig_html)
p = doc.at('b+p')
p.previous_sibling.remove
此时这是HTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="Generator" content="Microsoft Word 97 O.o">
</head>
<body>
1
<p>2</p>
3
</body>
</html>
继续:
p.inner_html = "<b>#{p.content}</b>"
puts doc.to_html
这是生成的HTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="Generator" content="Microsoft Word 97 O.o">
</head>
<body>
1
<p><b>2</b></p>
3
</body>
</html>
很明显,示例HTML并不是您真正使用的,因此您必须更改访问者以找到需要更改的标记,但这应该可以帮助您。
答案 1 :(得分:0)
以上情况适用于上述特定情况,但不适用于以下情况。
orig_html = '
<html>
<meta name="Generator" content="Microsoft Word 97 O.o">
<body>
1
<b>this is a bold
<p>This is a paragraph</p>
</b>
3
</body>
</html>'
doc = Nokogiri::HTML(orig_html)
p = doc.at('b+p')
p.previous_sibling.remove
p.inner_html = "<b>#{p.content}</b>" # !> mismatched indentations at 'end' with 'def' at 17
puts doc.to_html
结果HTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="Generator" content="Microsoft Word 97 O.o">
</head>
<body>
1
<p><b>This is a paragraph</b></p>
3
</body>
</html>