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

hin*_*nts 4 python xhtml lxml xml-parsing

想象一下,我有一个带有内容的文件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>
Run Code Online (Sandbox Code Playgroud)

并在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>'
Run Code Online (Sandbox Code Playgroud)

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

Fra*_*ila 6

简答

这样做(假设您的文档都是格式良好的XML)

etx = lxml.etree.parse('test.html')
print lxml.etree.tostring(etx, xml_declaration=True, encoding=etx.docinfo.encoding, standalone=etx.docinfo.standalone)
Run Code Online (Sandbox Code Playgroud)

说明

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.