我正在尝试使用Nokogiri将一些模板文件从一种格式转换为另一种格式。但它不断添加标签。我试图阻止它添加Doctype和meta标签,但无法弄明白。我试过了
@doc = Nokogiri::HTML.parse(r)
但是添加了标签。我也试过了
@doc = Nokogiri::HTML.fragment(r)
按照“How to prevent Nokogiri from adding <DOCTYPE> tags?”中的建议,但删除了文档中的所有<html>
,<head>
或<body>
标记。
如果重要,我的阅读文件的代码是:
f = File.read(infile)
r = f.gsub(/<tmpl_var ([^>]*)>/, '{{{\1}}}')
@doc = Nokogiri::HTML.fragment(r)
我需要事先做gsub
,因为我需要替换不正确HTML的<tmpl_var>
标记并导致更多问题。
使用HTML.fragment(r)
时,我会收到htmlParseStartTag: misplaced <html> tag
错误(以及<body>
和<head>
的类似错误。)
有没有办法阻止它进行这些添加?
转换示例:
在:
<html>
<head>
<script>
var x = "y";
</script>
</head>
<body>
<div>
Stuff
</div>
</body>
</html>
使用Parse之后:
<!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">
<script>
var x = "y";
</script>
</head>
<body>
<div>
Stuff
</div>
</body>
</html>
使用HTML.fragment
或HTML::DocumentFragment.parse
后:
<script>
var x = "y";
</script>
<div>
Stuff
</div>
在这种情况下,我希望它只输出之前的部分。 (在真实的剧本中,我做了一些改变)。
答案 0 :(得分:3)
可以告诉Nokogiri 不添加标准HTML标头。考虑这些:
require 'nokogiri'
doc = Nokogiri::HTML('<p>foo</p>')
doc.to_html # => "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n<html><body><p>foo</p></body></html>\n"
doc = Nokogiri::HTML.fragment('<p>foo</p>')
doc.to_html # => "<p>foo</p>"
tmpl_var
是HTML中的错误标记名称,{{{\1}}}
也是如此,因此要求Nokogiri尝试解析其中一个会导致出现问题:
doc = Nokogiri::HTML.fragment('<templ_var p1="baz">foo</templ_var>')
doc.errors # => [#<Nokogiri::XML::SyntaxError: Tag templ_var invalid>]
但你仍然可以使用DOM:
doc.to_html # => "<templ_var p1=\"baz\">foo</templ_var>"
doc.search('templ_var').each { |t| t.name = 'bar'}
doc.to_html # => "<bar p1=\"baz\">foo</bar>"
或者:
doc.to_html # => "<div><templ_var p1=\"baz\">foo</templ_var></div>"
doc.search('templ_var').each { |t| t.replace('{{{\1}}}') }
doc.to_html # => "<div>{{{\\1}}}</div>"
将这些东西放在一起,再加上一点诡计:
doc = Nokogiri::HTML.fragment('<div><templ_var p1="baz">foo</templ_var></div>')
doc.to_html # => "<div><templ_var p1=\"baz\">foo</templ_var></div>"
doc.search('templ_var').each { |t| t.replace('{{{\1}}}') }
doc.to_html # => "<div>{{{\\1}}}</div>"
header = Nokogiri::XML.fragment('<html><body>')
header.at('body').children = doc
header.to_html # => "<html><body><div>{{{\\1}}}</div></body></html>"
所以,我会追求这样的事情。
现在,为什么是Nokogiri在解析片段时剥离<html>
标签?我不知道。如果<body>
或<head>
丢失,则会<html>
单独留下:
Nokogiri::HTML.fragment('<p>foo<p>').to_html
# => "<p>foo</p><p></p>"
Nokogiri::HTML.fragment('<body><p>foo<p></body>').to_html
# => "<body>\n<p>foo</p>\n<p></p>\n</body>"
但如果存在<head>
或<html>
,则会变得很时髦:
Nokogiri::HTML.fragment('<head><style></style></head><body><p>foo<p></body>').to_html
# => "<style></style><p>foo</p><p></p>"
Nokogiri::HTML.fragment('<html><head><style></style></head><body><p>foo<p></body></html>').to_html
# => "<style></style><p>foo</p><p></p>"
这对我来说就像是Nokogiri的一个臭虫,因为我还没有看到任何记录这种行为的东西。
答案 1 :(得分:2)
您可以使用Nokogiri::XML::DocumentFragment
代替Nokogiri::HTML::DocumentFragment
来解决此问题。 XML版本不会删除html,head或body标签。