如何使用Python的xml.dom.minidom呈现doctype?

myf*_*web 6 python xml doctype

我试过了:

document.doctype = xml.dom.minidom.DocumentType('html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd"')
Run Code Online (Sandbox Code Playgroud)

输出中没有doctype.如何在不插入手的情况下修复?

bob*_*nce 11

您不应该minidom直接实例化类.它不是API支持的部分,ownerDocuments不会占用,你可能会遇到一些奇怪的错误行为.而是使用适当的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')
Run Code Online (Sandbox Code Playgroud)

('DTD/xhtml1-strict.dtd'是常用的但是错误的SystemId.该相对URL只能在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/>
Run Code Online (Sandbox Code Playgroud)

如果要更改现有文档的doctype,那就更麻烦了.DOM标准不要求DocumentType没有ownerDocument可插入文档的节点.然而,一些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>
Run Code Online (Sandbox Code Playgroud)

但有bug:

>>> doc.doctype
# None
>>> dt.ownerDocument
# None
Run Code Online (Sandbox Code Playgroud)

这对你来说可能有关,也可能没有关系.

从技术上讲,在现有文档上设置文档类型的唯一可靠方法是创建一个新文档并将整个旧文档导入其中!

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