xml.dom.minidom --- 最小化的 DOM 實現(xiàn)?

源代碼: Lib/xml/dom/minidom.py


xml.dom.minidom 是文檔對象模型接口的最小化實現(xiàn),具有與其他語言類似的 API。 它的目標是比完整 DOM 更簡單并且更為小巧。 對于 DOM 還不十分熟悉的用戶則應當考慮改用 xml.etree.ElementTree 模塊來進行 XML 處理。

警告

xml.dom.minidom 模塊對于惡意構建的數(shù)據(jù)是不安全的。 如果你需要解析不受信任或未經(jīng)身份驗證的數(shù)據(jù),請參閱 XML 漏洞

DOM 應用程序通常會從將某個 XML 解析為 DOM 開始。 使用 xml.dom.minidom 時,這是通過各種解析函數(shù)來完成的:

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() 函數(shù)可接受一個文件名或者打開的文件對象。

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

根據(jù)給定的輸入返回一個 Document。 filename_or_file 可以是一個文件名,或是一個文件類對象。 如果給定 parser 則它必須是一個 SAX2 解析器對象。 此函數(shù)將修改解析器的處理程序并激活命名空間支持;其他解析器配置(例如設置一個實體求解器)必須已經(jīng)提前完成。

如果你將 XML 存放為字符串形式,則可以改用 parseString() 函數(shù):

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

返回一個代表 stringDocument。 此方法會為指定字符串創(chuàng)建一個 io.StringIO 對象并將其傳遞給 parse()。

兩個函數(shù)均返回一個代表文檔內(nèi)容的 Document 對象。object representing the content of the document.

parse()parseString() 函數(shù)所做的是將 XML 解析器連接到一個 "DOM 構建器",它可以從任意 SAX 解析器接收解析事件并將其轉換為 DOM 樹結構。 這兩個函數(shù)的名稱可能有些誤導性,但在學習此接口時是很容易掌握的。 文檔解析操作將在這兩個函數(shù)返回之前完成;簡單地說這兩個函數(shù)本身并不提供解析器實現(xiàn)。

你也可以通過在一個 "DOM 實現(xiàn)" 對象上調(diào)用方法來創(chuàng)建 Document。 此對象可通過調(diào)用 xml.dom 包或者 xml.dom.minidom 模塊中的 getDOMImplementation() 函數(shù)來獲取。 一旦你獲得了一個 Document,你就可以向它添加子節(jié)點來填充 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 規(guī)格說明當中;文檔對象的主要特征屬性是 documentElement。 它給出了 XML 文檔中的主元素:即包含了所有其他元素的元素。 以下是一個示例程序:

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

當你完成對一個 DOM 樹的處理時,你可以選擇調(diào)用 unlink() 方法以鼓勵盡早清除不再需要的對象。 unlink()xml.dom.minidom 針對 DOM API 的專屬擴展,它會將特定節(jié)點及其下級標記為不再有用。 在其他情況下,Python 的垃圾回收器將負責最終處理樹結構中的對象。

參見

文檔對象模型 (DOM) 第 1 層級規(guī)格說明

xml.dom.minidom 所支持的 W3C 針對 DOM 的建議。

DOM 對象?

Python 的 DOM API 定義被作為 xml.dom 模塊文檔的一部分給出。 這一節(jié)列出了該 API 和 xml.dom.minidom 之間的差異。

破壞 DOM 的內(nèi)部引用以便它能在沒有循環(huán) GC 的 Python 版本上垃圾回收器回收。 即使在循環(huán) GC 可用的時候,使用此方法也可讓大量內(nèi)存更快變?yōu)榭捎?,因此?DOM 對象不再被需要時盡早調(diào)用它們的這個方法是很好的做法。 此方法只須在 Document 對象上調(diào)用,但也可以在下級節(jié)點上調(diào)用以丟棄該節(jié)點的下級節(jié)點。

你可以通過使用 with 語句來避免顯式調(diào)用此方法。 以下代碼會在 with 代碼塊退出時自動取消鏈接 dom:

with xml.dom.minidom.parse(datasource) as dom:
    ... # Work with dom.
Node.writexml(writer, indent='', addindent='', newl='', encoding=None, standalone=None)?

將 XML 寫入到寫入器對象。 寫入器接受文本而非字節(jié)串作為輸入,它應當具有與文件對象接口相匹配的 write() 方法。 indent 形參是當前節(jié)點的縮進層級。 addindent 形參是用于當前節(jié)點的下級節(jié)點的縮進量。 newl 形參指定用于一行結束的字符串。

對于 Document 節(jié)點,可以使用附加的關鍵字參數(shù) encoding 來指定 XML 標頭的編碼格式字段。

類似地,顯式指明 standalone 參數(shù)將會使單獨的文檔聲明被添加到 XML 文檔的開頭部分。 如果將該值設為 True,則會添加 standalone="yes",否則將為 "no"。 未指明該參數(shù)將使文檔聲明被省略。

在 3.8 版更改: writexml() 方法現(xiàn)在會保留用戶指定的屬性順序。

在 3.9 版更改: The standalone parameter was added.

Node.toxml(encoding=None, standalone=None)?

返回一個包含 XML DOM 節(jié)點所代表的 XML 的字符串或字節(jié)串。

帶有顯式的 encoding 1 參數(shù)時,結果為使用指定編碼格式的字節(jié)串。 沒有 encoding 參數(shù)時,結果為 Unicode 字符串,并且結果字符串中的 XML 聲明將不指定編碼格式。 使用 UTF-8 以外的編碼格式對此字符串進行編碼通常是不正確的,因為 UTF-8 是 XML 的默認編碼格式。

standalone 參數(shù)的行為與 writexml() 中的完全一致。

在 3.8 版更改: toxml() 方法現(xiàn)在會保留用戶指定的屬性順序。

在 3.9 版更改: The standalone parameter was added.

Node.toprettyxml(indent='\t', newl='\n', encoding=None, standalone=None)?

返回文檔的美化打印版本。 indent 指定縮進字符串并默認為制表符;newl 指定標示每行結束的字符串并默認為 \n。

encoding 參數(shù)的行為類似于 toxml() 的對應參數(shù)。

standalone 參數(shù)的行為與 writexml() 中的完全一致。

在 3.8 版更改: toprettyxml() 方法現(xiàn)在會保留用戶指定的屬性順序。

在 3.9 版更改: The standalone parameter was added.

DOM 示例?

此示例程序是個相當實際的簡單程序示例。 在這個特定情況中,我們沒有過多地利用 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(f"<title>{getText(title.childNodes)}</title>")

def handleSlideTitle(title):
    print(f"<h2>{getText(title.childNodes)}</h2>")

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

def handlePoint(point):
    print(f"<li>{getText(point.childNodes)}</li>")

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

handleSlideshow(dom)

minidom 和 DOM 標準?

xml.dom.minidom 模塊實際上是兼容 DOM 1.0 的 DOM 并帶有部分 DOM 2 特性(主要是命名空間特性)。

Python 中 DOM 接口的用法十分直觀。 會應用下列映射規(guī)則:

  • 接口是通過實例對象來訪問的。 應用程序不應實例化這些類本身;它們應當使用 Document 對象提供的創(chuàng)建器函數(shù)。 派生的接口支持上級接口的所有操作(和屬性),并添加了新的操作。

  • 操作以方法的形式使用。 因由 DOM 只使用 in 形參,參數(shù)是以正常順序傳入的(從左至右)。 不存在可選參數(shù)。 void 操作返回 None

  • IDL 屬性會映射到實例屬性。 為了兼容針對 Python 的 OMG IDL 語言映射,屬性 foo 也可通過訪問器方法 _get_foo()_set_foo() 來訪問。 readonly 屬性不可被修改;運行時并不強制要求這一點。

  • short int, unsigned int, unsigned long longboolean 類型都會映射為 Python 整數(shù)類型。

  • DOMString 類型會映射為 Python 字符串。 xml.dom.minidom 支持字節(jié)串或字符串,但通常是產(chǎn)生字符串。 DOMString 類型的值也可以為 None,W3C 的 DOM 規(guī)格說明允許其具有 IDL null 值。

  • const 聲明會映射為它們各自的作用域內(nèi)的變量 (例如 xml.dom.minidom.Node.PROCESSING_INSTRUCTION_NODE);它們不可被修改。

  • DOMException 目前不被 xml.dom.minidom 所支持。 xml.dom.minidom 會改為使用標準 Python 異常例如 TypeErrorAttributeError。

  • NodeList 對象是使用 Python 內(nèi)置列表類型來實現(xiàn)的。 這些對象提供了 DOM 規(guī)格說明中定義的接口,但在較早版本的 Python 中它們不支持官方 API。 相比在 W3C 建議中定義的接口,它們要更加的 "Pythonic"。

下列接口未在 xml.dom.minidom 中實現(xiàn):

  • DOMTimeStamp

  • EntityReference

這些接口所反映的 XML 文檔信息對于大多數(shù) DOM 用戶來說沒有什么幫助。

備注

1

包括在 XML 輸出中的編碼格式名稱應當遵循適當?shù)臉藴省?例如,"UTF-8" 是有效的,但 "UTF8" 在 XML 文檔的聲明中是無效的,即使 Python 接受其作為編碼格式名稱。 詳情參見 https://www.w3.org/TR/2006/REC-xml11-20060816/#NT-EncodingDeclhttps://www.iana.org/assignments/character-sets/character-sets.xhtml。