我正在使用nokogiri解析一个html文件并对其进行修改,然后将其输出到如下文件:
htext= File.open(inputOpts.html_file).read
h_doc = Nokogiri::HTML(htext)
File.open(outputfile, 'w+') do |file|
file.write(h_doc)
end
输出文件包含第一行:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
我不想这样,因为我将html嵌入到另一个文件中,而这个标记会导致问题。
问题是如何将其从h_doc中删除。
根据您要做的操作,您可以将HTML解析为DocumentFragment
:
h_doc = Nokogiri::HTML::DocumentFragment.parse(htext)
在片段上调用to_s
或to_html
时,doctype行将被省略,Nokogiri添加的<html>
和<body>
标记(如果它们还不存在)也将被省略。
这取决于您的需求。如果你只需要身体,那么
h_doc.at_xpath("//body") #this will just pull the data from the <body></body> tags
如果你也需要收集<head>
,只需要避开<DOCTYPE>
,那么
#this will capture everything between the <head></head> and <body></body> tags
h_doc.xpath("//head") + h_doc.xpath("//body")
所以像这个
h_doc = Nokogiri::HTML(open(input_opts.html_file))
File.open(outputfile,'w+') do |file|
#for just <body>
file << h_doc.at_xpath("//body").to_s
#for <head> and <body>
file << (h_doc.xpath("//head") + h_doc.xpath("//body")).to_s
end
注意,对于body
,我使用了#at_xpath
,因为这将返回Nokogiri::Element
,但在组合它们时,我使用#xpath
,因为这会返回Nokogiri::XML::NodeSet
。无需担心,这部分只是用于组合,html将显示相同的结果,例如h_doc.at_xpath("//head").to_s == h_doc.xpath("//head").to_s #=> true
读取输入文件时可以忽略第一行:
htext= File.readlines(inputOpts.html_file)[1..-1].join
h_doc = Nokogiri::HTML(htext)
File.open(outputfile, 'w+') do |file|
file.write(h_doc)
end
我设法用HTML::Document
和HTML::DocumentFragment
解决了这个问题。
-
作为背景,我使用Nokogiri来解析和修改HTML的"模板"、"部分"和/或"组件"。这意味着我遇到的文件不是有效的HTML文档。相反,它们是HTML文档的一部分,由我使用的框架组合在一起。
-
作为参考,
HTML::Document
添加了<!DOCTYPE>
声明,如果文档中还没有<html>
和<body>
实体,则还会将文档包装为它们。类似地,HTML::DocumentFragment
将用<p>
实体包裹您的片段。
与其花太多时间挖掘Nokogiri库代码来了解这些额外的实体在哪里,我决定接受这种固执己见的实现并围绕它工作
解决方案
以下是我如何写出修改后的HTML:
html_str = doc.xpath("//body").children.to_html(encoding: 'UTF-8')
File.open(_filename, 'w') {|f| f.write(html_str)}
词尾词
这似乎比应该的更难。我甚至尝试使用SaveOptions
设置save_with: Nokogiri::XML::Node::SaveOptions::NO_DECLARATION
,但没有成功。
无论如何,虽然这个解决方案对我来说有点草率,但它确实有效。