如何使用Python的xml.dom.minidom渲染doctype?
我试过了:
document.doctype = xml.dom.minidom.DocumentType('html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"')
输出中没有文档类型声明(doctype)。怎么才能不手动插入它来解决这个问题呢?
1 个回答
11
>>> doc.doctype
# None
>>> dt.ownerDocument
# None
你不应该直接创建 minidom
的类实例。这不是官方支持的用法,ownerDocument
不会正常工作,可能会出现一些奇怪的问题。正确的做法是使用 DOM Level 2 Core 的方法:
>>> imp= minidom.getDOMImplementation('')
>>> dt= imp.createDocumentType('html', '-//W3C//DTD XHTML 1.0 Strict//EN', 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd')
(‘DTD/xhtml1-strict.dtd’ 是一个常用但错误的 SystemId
。这个相对网址只有在 w3.org 的 xhtml1 文件夹内才有效。)
现在你有了一个 DocumentType
节点,你可以把它添加到一个文档中。根据标准,唯一保证的做法是在创建文档的时候:
>>> doc= imp.createDocument('http://www.w3.org/1999/xhtml', 'html', dt)
>>> print doc.toxml()
<?xml version="1.0" ?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'><html/>
如果你想更改一个已有文档的文档类型,那就麻烦了。DOM 标准并不要求没有 ownerDocument
的 DocumentType
节点可以插入到文档中。不过,有些 DOM 是允许的,比如 pxdom
。minidom
也算是允许,但会有一些问题:
>>> doc= minidom.parseString('<html xmlns="http://www.w3.org/1999/xhtml"><head/><body/></html>')
>>> dt= minidom.getDOMImplementation('').createDocumentType('html', '-//W3C//DTD XHTML 1.0 Strict//EN', 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd')
>>> doc.insertBefore(dt, doc.documentElement)
<xml.dom.minidom.DocumentType instance>
>>> print doc.toxml()
<?xml version="1.0" ?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'><html xmlns="http://www.w3.org/1999/xhtml"><head/><body/></html>
这些问题可能对你来说重要,也可能不重要。
从技术上讲,根据标准,设置已有文档的文档类型的唯一可靠方法是创建一个新文档,并把旧文档的全部内容导入到新文档中!
def setDoctype(document, doctype):
imp= document.implementation
newdocument= imp.createDocument(doctype.namespaceURI, doctype.name, doctype)
newdocument.xmlVersion= document.xmlVersion
refel= newdocument.documentElement
for child in document.childNodes:
if child.nodeType==child.ELEMENT_NODE:
newdocument.replaceChild(
newdocument.importNode(child, True), newdocument.documentElement
)
refel= None
elif child.nodeType!=child.DOCUMENT_TYPE_NODE:
newdocument.insertBefore(newdocument.importNode(child, True), refel)
return newdocument