lxml.html.tostring在打印时重新排序了doctype和xml标签

时间:2011-12-15 00:55:12

标签: python xhtml xml-parsing lxml

想象一下,我有一个包含内容的文件test.html,

<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>Components of the SDK</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body></body></html>

在python提示符下执行此操作,

>>>import lxml.html
>>>t = lxml.html.parse('test.html')
>>>lxml.html.etree.tostring(t)
>>>'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n<?xml version="1.0" encoding="UTF-8" standalone="no"??><html xmlns="http://www.w3.org/1999/xhtml"><head><title>Components of the SDK</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body/></html>'

注意在lxml读入数据然后再通过tostring将其打印出来后,doctype和xml标签是如何反转的?我们如何修复它以便它不会尝试修改文档(假设它已经很好地形成)。

1 个答案:

答案 0 :(得分:6)

简答

改为执行此操作(假设您的文档都是格式良好的XML)

etx = lxml.etree.parse('test.html')
print lxml.etree.tostring(etx, xml_declaration=True, encoding=etx.docinfo.encoding, standalone=etx.docinfo.standalone)

说明

test.html实际上并不是有效的HTML。它有空元素和xml处理指令。 html不理解这些。 html解析器将xml处理指令解释为SGML处理指令(这些指令类似于<? ... >而不是xml <? ... ?>),内容为xml version="1.0" encoding="UTF-8" standalone="no"?。因此,当重新序列化为XML时,XML处理指令有两个问题,如:??>

使用html5lib解析器或序列化程序的结果稍好一些 - 当重新序列化为XML时,处理指令将在注释中。这是因为HTML5也不允许使用SGML处理指令,并将xml前导码解释为要忽略的垃圾文本。

要获得所需的结果,请使用xml解析器(lxml.etree)解析和序列化文档。它似乎是格式良好的xml和有效的XHTML1.1。如果您使用html序列化程序(lxml.html.tostring()而非lxml.html.etree.tostring())进行序列化,则会输出一个多语言xhtml文档。

皱纹是序列化程序不会尝试完全保留xml声明(这毕竟不是xml信息集的一部分)。您必须将这些传递给tostring()属性中的docinfo方法。