如何使用Python的xml.dom.minidom渲染doctype?

6 投票
1 回答
4632 浏览
提问于 2025-04-15 17:29

我试过了:

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 标准并不要求没有 ownerDocumentDocumentType 节点可以插入到文档中。不过,有些 DOM 是允许的,比如 pxdomminidom 也算是允许,但会有一些问题:

>>> 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

撰写回答