# 20.7. `xml.dom.minidom` - 最小DOM实现

源代码： Lib / xml / dom / minidom.py

`xml.dom.minidom`是文档对象模型接口的最小实现，其API类似于其他语言。它的目的是比完整的DOM更简单，也显着更小。尚未熟悉DOM的用户应考虑使用`xml.etree.ElementTree`模块进行XML处理。

警告

`xml.dom.minidom`模块对于恶意构造的数据不安全。如果需要解析不受信任或未经身份验证的数据，请参阅XML vulnerabilities。

DOM应用程序通常首先将一些XML解析为DOM。使用`xml.dom.minidom`，这是通过解析函数完成的：

    from xml.dom.minidom import parse, parseString

    dom1 = parse('c:\\temp\\mydata.xml')  # parse an XML file by name

    datasource = open('c:\\temp\\mydata.xml')
    dom2 = parse(datasource)  # parse an open file

    dom3 = parseString('<myxml>Some data<empty/> some more data</myxml>')

`parse()`函数可以采用文件名或打开的文件对象。

`xml.dom.minidom.``parse`(filename_or_file, parser=None, bufsize=None)

  从给定输入返回`Document`。filename_or_file may be either a file name, or a file-like object.解析器（如果给出）必须是SAX2解析器对象。此函数将更改解析器的文档处理程序并激活命名空间支持；其他解析器配置（如设置实体解析器）必须提前完成。

如果在字符串中有XML，可以使用`parseString()`函数：

`xml.dom.minidom.``parseString`(string, parser=None)

  返回表示字符串的`Document`。此方法为字符串创建`io.StringIO`对象，并将其传递到`parse()`。

这两个函数都返回一个表示文档内容的`Document`对象。

`parse()`和`parseString()`函数做的是连接一个XML解析器和一个“DOM构建器”，它可以接受来自任何SAX解析器的解析事件， DOM树。函数的名称可能是误导，但在学习界面时容易掌握。在这些函数返回之前，将完成文档的解析；只是这些函数不提供解析器实现本身。

您还可以通过调用“DOM实现”对象上的方法来创建`Document`。您可以通过调用`xml.dom`包或`xml.dom.minidom`模块中的`getDOMImplementation()`函数来获取此对象。一旦您有`Document`，就可以向其中添加子节点来填充DOM：

    from xml.dom.minidom import getDOMImplementation

    impl = getDOMImplementation()

    newdoc = impl.createDocument(None, "some_tag", None)
    top_element = newdoc.documentElement
    text = newdoc.createTextNode('Some textual content.')
    top_element.appendChild(text)

一旦有了DOM文档对象，就可以通过它的属性和方法访问XML文档的部分。这些属性在DOM规范中定义。文档对象的主要属性是`documentElement`属性。它为您提供了XML文档中的主要元素：包含所有其他元素的元素。这里是一个示例程序：

    dom3 = parseString("<myxml>Some data</myxml>")
    assert dom3.documentElement.tagName == "myxml"

当您完成DOM树时，您可以选择调用`unlink()`方法，以鼓励及早清理现在不需要的对象。`unlink()`是一个`xml.dom.minidom`特定的DOM API扩展，它显示节点及其后代本质上是无用的。否则，Python的垃圾收集器最终会处理树中的对象。

也可以看看

文档对象模型（DOM）1级规范
  W3C对`xml.dom.minidom`支持的DOM的建议。

## 20.7.1. DOM Objects

Python的DOM API的定义作为`xml.dom`模块文档的一部分提供。本节列出API与`xml.dom.minidom`之间的差异。

`Node.``unlink`()

  打破DOM中的内部引用，以便在没有循环GC的Python版本上进行垃圾回收。即使循环GC可用，使用它可以更快地使大量内存可用，因此一旦DOM对象不再需要，就调用它是一个好习惯。这只需要在`Document`对象上调用，但可以在子节点上调用以丢弃该节点的子代。

  您可以通过使用`with`语句来避免显式调用此方法。当退出`with`块时，以下代码将自动取消链接dom：

      with xml.dom.minidom.parse(datasource) as dom:
          ... # Work with dom.

`Node.``writexml`(writer, indent="", addindent="", newl="")

  将XML写入writer对象。写入程序应该有一个与文件对象接口匹配的`write()`方法。缩进参数是当前节点的缩进。addindent参数是用于当前子节点的增量缩进。newl参数指定用于终止换行符的字符串。

  对于`Document`节点，可以使用附加的关键字参数encoding来指定XML标头的编码字段。

`Node.``toxml`(encoding=None)

  返回一个包含由DOM节点表示的XML的字符串或字节字符串。

  使用显式的编码 [1]参数，结果是指定编码中的字节字符串。如果没有encoding参数，则结果是Unicode字符串，并且生成的字符串中的XML声明不指定编码。使用UTF-8之外的编码对此字符串进行编码可能不正确，因为UTF-8是XML的默认编码。

`Node.``toprettyxml`(indent="", newl="", encoding="")

  返回文档的漂亮打印版本。缩进指定缩进字符串，默认为制表符； newl指定每行结尾处发出的字符串，默认为`\n`。

  encoding参数的行为类似于`toxml()`的相应参数。

## 20.7.2. DOM Example

这个例子程序是一个简单程序的一个相当现实的例子。在这种特殊情况下，我们没有利用DOM的灵活性。

    import xml.dom.minidom

    document = """\
    <slideshow>
    <title>Demo slideshow</title>
    <slide><title>Slide title</title>
    <point>This is a demo</point>
    <point>Of a program for processing slides</point>
    </slide>

    <slide><title>Another demo slide</title>
    <point>It is important</point>
    <point>To have more than</point>
    <point>one slide</point>
    </slide>
    </slideshow>
    """

    dom = xml.dom.minidom.parseString(document)

    def getText(nodelist):
        rc = []
        for node in nodelist:
            if node.nodeType == node.TEXT_NODE:
                rc.append(node.data)
        return ''.join(rc)

    def handleSlideshow(slideshow):
        print("<html>")
        handleSlideshowTitle(slideshow.getElementsByTagName("title")[0])
        slides = slideshow.getElementsByTagName("slide")
        handleToc(slides)
        handleSlides(slides)
        print("</html>")

    def handleSlides(slides):
        for slide in slides:
            handleSlide(slide)

    def handleSlide(slide):
        handleSlideTitle(slide.getElementsByTagName("title")[0])
        handlePoints(slide.getElementsByTagName("point"))

    def handleSlideshowTitle(title):
        print("<title>%s</title>" % getText(title.childNodes))

    def handleSlideTitle(title):
        print("<h2>%s</h2>" % getText(title.childNodes))

    def handlePoints(points):
        print("<ul>")
        for point in points:
            handlePoint(point)
        print("</ul>")

    def handlePoint(point):
        print("<li>%s</li>" % getText(point.childNodes))

    def handleToc(slides):
        for slide in slides:
            title = slide.getElementsByTagName("title")[0]
            print("<p>%s</p>" % getText(title.childNodes))

    handleSlideshow(dom)

## 20.7.3. minidom和DOM标准

`xml.dom.minidom`模块本质上是一个DOM 1.0兼容的DOM，具有一些DOM 2功能（主要是命名空间功能）。

在Python中使用DOM接口是直接的。以下映射规则适用：

- 接口通过实例对象访问。应用程序不应该实例化类本身；则应使用`Document`对象上提供的创建者函数。派生接口支持来自基本接口的所有操作（和属性），以及任何新操作。
- 操作用作方法。由于DOM在参数中仅使用`in` 没有可选参数。`void`操作返回`None`。
- IDL属性映射到实例属性。为了与Python的OMG IDL语言映射兼容，还可以通过访问器方法`_get_foo()`和`_set_foo()`访问属性`foo`。`readonly`属性不能更改；这不是在运行时强制。
- 类型`短 int`，`无符号 int `unsigned long long`和`boolean``
- 类型`DOMString`映​​射到Python字符串。`xml.dom.minidom`支持字节或字符串，但通常会产生字符串。类型`DOMString`的值也可以是`None`，其中允许具有来自W3C的DOM规范的IDL `null`值。
- `const`声明映射到它们各自范围内的变量。`xml.dom.minidom.Node.PROCESSING_INSTRUCTION_NODE`）；它们不能改变。
- `xml.dom.minidom`中目前不支持`DOMException`。而是，`xml.dom.minidom`使用标准Python异常，例如`TypeError`和`AttributeError`。
- `NodeList`对象使用Python的内建列表类型实现。这些对象提供了在DOM规范中定义的接口，但是对于早期版本的Python，它们不支持官方API。然而，它们比W3C建议中定义的接口更加“Pythonic”。

以下接口在`xml.dom.minidom`中没有实现：

- `DOMTimeStamp`
- `DocumentType`
- `DOMImplementation`
- `CharacterData`
- `CDATASection`
- `Notation`
- `Entity`
- `EntityReference`
- `DocumentFragment`

大多数这些都反映在XML文档中的信息，这对大多数DOM用户来说不是通用的。

脚注

[1] | XML输出中包含的编码名称应符合相应的标准。例如，“UTF-8”有效，但“UTF8”在XML文档的声明中无效，即使Python接受它作为编码名称。请参阅https://www.w3.org/TR/2006/REC-xml11-20060816/#NT-EncodingDecl和https://www.iana.org/assignments/character- sets / character-sets.xhtml。