"xml.dom.pulldom" --- 对构建部分 DOM 树的支持
*********************************************

**源代码:** Lib/xml/dom/pulldom.py

======================================================================

"xml.dom.pulldom" 模块提供了一个“拉取式解析器”，它也可以在必要时生成文
档中可通过 DOM 访问的片段。基本概念涉及从传入的 XML 流中拉取“事件”并对
其进行处理。 与同样采用事件驱动处理模型并结合回调的 SAX 不同，拉取式解
析器的使用者需要负责显式地从流中拉取事件，循环遍历这些事件直到处理完成
或出现错误条件。

备注:

  如果你需要解析不受信任或未经身份验证的数据，请参阅 XML 安全。

在 3.7.1 版本发生变更: SAX 解析器默认不再处理一般外部实体以提升在默认
情况下的安全性。 要启用外部实体处理，请传入一个自定义的解析器实例:

   from xml.dom.pulldom import parse
   from xml.sax import make_parser
   from xml.sax.handler import feature_external_ges

   parser = make_parser()
   parser.setFeature(feature_external_ges, True)
   parse(filename, parser=parser)

示例:

   from xml.dom import pulldom

   doc = pulldom.parse('sales_items.xml')
   for event, node in doc:
       if event == pulldom.START_ELEMENT and node.tagName == 'item':
           if int(node.getAttribute('price')) > 50:
               doc.expandNode(node)
               print(node.toxml())

"event" is one of the following constants, and "node" is the node
which the event is about. The nodes implement the "xml.dom"
interfaces; they are created by the DOM implementation given to
"PullDOM", which is "xml.dom.minidom" by default.

xml.dom.pulldom.START_DOCUMENT
xml.dom.pulldom.END_DOCUMENT

   The start and the end of the document. *node* is the "Document".

xml.dom.pulldom.START_ELEMENT
xml.dom.pulldom.END_ELEMENT

   元素的起始和结束标记。 *node* 是 "Element"。

xml.dom.pulldom.CHARACTERS

   字符数据。 *node* 是 "Text" 节点。

xml.dom.pulldom.IGNORABLE_WHITESPACE

   元素内容中的空白符，见 DTD 中的声明。 *node* 是 "Text" 节点。

xml.dom.pulldom.COMMENT

   注释。 *node* 是 "Comment" 节点。

xml.dom.pulldom.PROCESSING_INSTRUCTION

   处理指令。 *node* 是 "ProcessingInstruction" 节点。

由于文档是被当作“展平”的事件流来处理的，文档“树”会被隐式地遍历并且无论
所需元素在树中的深度如何都会被找到。 换句话说，不需要考虑层级问题，例
如文档节点的递归搜索等，但是如果元素的上下文很重要，则有必要保留一些上
下文相关的状态（例如记住任意给定点在文档中的位置）或者使用
"DOMEventStream.expandNode()" 方法并切换到 DOM 相关的处理过程。

class xml.dom.pulldom.PullDOM(documentFactory=None)

   Subclass of "xml.sax.handler.ContentHandler" which turns SAX events
   into the events of the pull parser. The nodes are created, but they
   are not added to the tree, unless "expandNode()" is called.
   *documentFactory*, if given, is a DOM implementation used to create
   the document; by default the implementation of "xml.dom.minidom" is
   used.

class xml.dom.pulldom.SAX2DOM(documentFactory=None)

   Subclass of "PullDOM" which also adds every created node to the
   tree, so that the complete document is built.

xml.dom.pulldom.parse(stream_or_string, parser=None, bufsize=None)

   基于给定的输入返回一个 "DOMEventStream"。 *stream_or_string* 可以是
   一个文件名，或是一个文件型对象。 *parser* 如果给出，则必须是一个
   "XMLReader" 对象。 此函数将改变解析器的文档处理程序并激活命名空间支
   持；其他解析器配置（例如设置实体解析器）必须在之前已完成。

如果你将 XML 存放为字符串形式，则可以改用 "parseString()" 函数:

xml.dom.pulldom.parseString(string, parser=None)

   Return a "DOMEventStream" that represents the *string*. *string*
   must be a "str" instance; to parse bytes, pass a binary file object
   to "parse()".

xml.dom.pulldom.default_bufsize

   "parse()" 的 *bufsize* 形参的默认值。

   此变量的值可在调用 "parse()" 之前修改并使新值生效。


DOMEventStream 对象
===================

class xml.dom.pulldom.DOMEventStream(stream, parser, bufsize)

   Produce the events for the data read from the file object *stream*
   by the "XMLReader" *parser*. The data is read by *bufsize* bytes,
   or characters for a text stream, at a time.

   在 3.11 版本发生变更: 对 "__getitem__()" 方法的支持已被移除。

   getEvent()

      Return the next "(event, node)" tuple, or "None" at the end of
      the document. See above for the events and the corresponding
      nodes. The current node does not contain information about its
      children, unless "expandNode()" is called.

   expandNode(node)

      将 *node* 的所有子节点扩展到 *node* 中。 例如:

         from xml.dom import pulldom

         xml = '<html><title>Foo</title> <p>Some text <div>and more</div></p> </html>'
         doc = pulldom.parseString(xml)
         for event, node in doc:
             if event == pulldom.START_ELEMENT and node.tagName == 'p':
                 # 以下语句只打印 '<p/>'
                 print(node.toxml())
                 doc.expandNode(node)
                 # 以下语句将打印节点所有的子节点 '<p>Some text <div>and more</div></p>'
                 print(node.toxml())

   reset()

      Discard the events which are not read yet and prepare the object
      for parsing a new document.

   clear()

      释放解析器和文档。 流尚未被关闭，而对象将无法继续使用。
