xml.dom.minidom — 最小 DOM 實現

原始碼: Lib/xml/dom/minidom.py


xml.dom.minidom 是文件物件模型介面的最小實現,其 API 與其他語言中的類似。它旨在比完整 DOM 更簡單,也顯著更小。不熟悉 DOM 的使用者應考慮使用 xml.etree.ElementTree 模組進行 XML 處理。

備註

如果您需要解析不受信任或未經身份驗證的資料,請參閱 XML 安全

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)

從給定輸入返回一個 Documentfilename_or_file 可以是檔名,也可以是類檔案物件。parser(如果給定)必須是 SAX2 解析器物件。此函式將更改解析器的文件處理程式並激活名稱空間支援;其他解析器配置(如設定實體解析器)必須事先完成。

如果您有一個包含 XML 的字串,您可以使用 parseString() 函式代替

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

返回表示 stringDocument。此方法為字串建立一個 io.StringIO 物件,並將其傳遞給 parse()

這兩個函式都返回一個表示文件內容的 Document 物件。

parse()parseString() 函式的作用是將 XML 解析器與“DOM 構建器”連線起來,該構建器可以接受來自任何 SAX 解析器的解析事件,並將其轉換為 DOM 樹。這些函式的名稱可能具有誤導性,但在學習介面時很容易理解。文件的解析將在這些函式返回之前完成;這些函式只是不提供解析器實現本身。

您也可以透過呼叫“DOM 實現”物件上的方法來建立 Document。您可以透過呼叫 xml.dom 包中的 getDOMImplementation() 函式或 xml.dom.minidom 模組來獲取此物件。一旦您擁有 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 規範

xml.dom.minidom 支援的 W3C DOM 推薦標準。

DOM 物件

Python 的 DOM API 定義作為 xml.dom 模組文件的一部分提供。本節列出了 API 與 xml.dom.minidom 之間的差異。

斷開 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='', encoding=None, standalone=None)

將 XML 寫入 writer 物件。writer 接收文字而不是位元組作為輸入,它應該有一個與檔案物件介面匹配的 write() 方法。indent 引數是當前節點的縮排。addindent 引數是用於當前節點的子節點的增量縮排。newl 引數指定用於終止換行的字串。

對於 Document 節點,可以使用額外的關鍵字引數 encoding 來指定 XML 頭的編碼欄位。

同樣,顯式宣告 standalone 引數會導致將獨立文件宣告新增到 XML 文件的序言中。如果值設定為 True,則新增 standalone="yes",否則將其設定為 "no"。不宣告該引數將從文件中省略該宣告。

在 3.8 版本中更改: writexml() 方法現在保留使用者指定的屬性順序。

在 3.9 版本中更改: 添加了 standalone 引數。

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

返回包含 DOM 節點表示的 XML 的字串或位元組字串。

使用顯式 encoding [1] 引數,結果是指定編碼的位元組字串。如果沒有 encoding 引數,結果是 Unicode 字串,並且結果字串中的 XML 宣告不指定編碼。將此字串編碼為 UTF-8 以外的編碼可能不正確,因為 UTF-8 是 XML 的預設編碼。

standalone 引數的行為與 writexml() 中相應的引數完全相同。

在 3.8 版本中更改: toxml() 方法現在保留使用者指定的屬性順序。

在 3.9 版本中更改: 添加了 standalone 引數。

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

返回文件的漂亮列印版本。indent 指定縮排字串,預設為製表符;newl 指定每行末尾發出的字串,預設為 \n

encoding 引數的行為與 toxml() 的相應引數相同。

standalone 引數的行為與 writexml() 中相應的引數完全相同。

在 3.8 版本中更改: toprettyxml() 方法現在保留使用者指定的屬性順序。

在 3.9 版本中更改: 添加了 standalone 引數。

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 介面非常簡單。以下對映規則適用

  • 透過例項物件訪問介面。應用程式不應自行例項化類;它們應使用 Document 物件上可用的建立者函式。派生介面支援基本介面的所有操作(和屬性),以及任何新操作。

  • 操作用作方法。由於 DOM 只使用 in 引數,因此引數按正常順序(從左到右)傳遞。沒有可選引數。void 操作返回 None

  • IDL 屬性對映到例項屬性。為了與 OMG IDL Python 語言對映相容,屬性 foo 也可以透過訪問器方法 _get_foo()_set_foo() 訪問。readonly 屬性不得更改;這在執行時不強制執行。

  • 型別 short intunsigned intunsigned long longboolean 都對映到 Python 整數物件。

  • 型別 DOMString 對映到 Python 字串。xml.dom.minidom 支援位元組或字串,但通常會生成字串。型別為 DOMString 的值也可以是 None,如果 W3C 的 DOM 規範允許其具有 IDL null 值。

  • const 宣告對映到其各自作用域中的變數(例如 xml.dom.minidom.Node.PROCESSING_INSTRUCTION_NODE);它們不得更改。

  • DOMException 目前在 xml.dom.minidom 中不受支援。相反,xml.dom.minidom 使用標準 Python 異常,例如 TypeErrorAttributeError

  • NodeList 物件使用 Python 的內建列表型別實現。這些物件提供 DOM 規範中定義的介面,但在早期版本的 Python 中,它們不支援官方 API。然而,它們比 W3C 推薦標準中定義的介面更“Pythonic”。

以下介面在 xml.dom.minidom 中沒有實現

  • DOMTimeStamp

  • EntityReference

其中大部分反映了 XML 文件中對大多數 DOM 使用者沒有普遍實用價值的資訊。

腳註