xml.dom.minidom
--- 最小化的 DOM 實(shí)現?
xml.dom.minidom
是文檔對象模型接口的最小化實(shí)現,具有與其他語(yǔ)言類(lèi)似的 API。 它的目標是比完整 DOM 更簡(jiǎn)單并且更為小巧。 對于 DOM 還不十分熟悉的用戶(hù)則應當考慮改用 xml.etree.ElementTree
模塊來(lái)進(jìn)行 XML 處理。
警告
xml.dom.minidom
模塊對于惡意構建的數據是不安全的。 如果你需要解析不受信任或未經(jīng)身份驗證的數據,請參閱 XML 漏洞。
DOM 應用程序通常會(huì )從將某個(gè) XML 解析為 DOM 開(kāi)始。 使用 xml.dom.minidom
時(shí),這是通過(guò)各種解析函數來(lái)完成的:
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()
函數可接受一個(gè)文件名或者打開(kāi)的文件對象。
- xml.dom.minidom.parse(filename_or_file, parser=None, bufsize=None)?
根據給定的輸入返回一個(gè)
Document
。 filename_or_file 可以是一個(gè)文件名,或是一個(gè)文件類(lèi)對象。 如果給定 parser 則它必須是一個(gè) SAX2 解析器對象。 此函數將修改解析器的處理程序并激活命名空間支持;其他解析器配置(例如設置一個(gè)實(shí)體求解器)必須已經(jīng)提前完成。
如果你將 XML 存放為字符串形式,則可以改用 parseString()
函數:
- xml.dom.minidom.parseString(string, parser=None)?
返回一個(gè)代表 string 的
Document
。 此方法會(huì )為指定字符串創(chuàng )建一個(gè)io.StringIO
對象并將其傳遞給parse()
。
兩個(gè)函數均返回一個(gè)代表文檔內容的 Document
對象。object representing the content of the document.
parse()
和 parseString()
函數所做的是將 XML 解析器連接到一個(gè) "DOM 構建器",它可以從任意 SAX 解析器接收解析事件并將其轉換為 DOM 樹(shù)結構。 這兩個(gè)函數的名稱(chēng)可能有些誤導性,但在學(xué)習此接口時(shí)是很容易掌握的。 文檔解析操作將在這兩個(gè)函數返回之前完成;簡(jiǎn)單地說(shuō)這兩個(gè)函數本身并不提供解析器實(shí)現。
你也可以通過(guò)在一個(gè) "DOM 實(shí)現" 對象上調用方法來(lái)創(chuàng )建 Document
。 此對象可通過(guò)調用 xml.dom
包或者 xml.dom.minidom
模塊中的 getDOMImplementation()
函數來(lái)獲取。 一旦你獲得了一個(gè) Document
,你就可以向它添加子節點(diǎn)來(lái)填充 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 文檔對象,你就可以通過(guò)其屬性和方法訪(fǎng)問(wèn)對應 XML 文檔的各個(gè)部分。 這些屬性定義在 DOM 規格說(shuō)明當中;文檔對象的主要特征屬性是 documentElement
。 它給出了 XML 文檔中的主元素:即包含了所有其他元素的元素。 以下是一個(gè)示例程序:
dom3 = parseString("<myxml>Some data</myxml>")
assert dom3.documentElement.tagName == "myxml"
當你完成對一個(gè) DOM 樹(shù)的處理時(shí),你可以選擇調用 unlink()
方法以鼓勵盡早清除不再需要的對象。 unlink()
是 xml.dom.minidom
針對 DOM API 的專(zhuān)屬擴展,它會(huì )將特定節點(diǎn)及其下級標記為不再有用。 在其他情況下,Python 的垃圾回收器將負責最終處理樹(shù)結構中的對象。
參見(jiàn)
- 文檔對象模型 (DOM) 第 1 層級規格說(shuō)明
被
xml.dom.minidom
所支持的 W3C 針對 DOM 的建議。
DOM 對象?
Python 的 DOM API 定義被作為 xml.dom
模塊文檔的一部分給出。 這一節列出了該 API 和 xml.dom.minidom
之間的差異。
- Node.unlink()?
破壞 DOM 的內部引用以便它能在沒(méi)有循環(huán) GC 的 Python 版本上垃圾回收器回收。 即使在循環(huán) GC 可用的時(shí)候,使用此方法也可讓大量?jì)却娓熳優(yōu)榭捎?,因此?DOM 對象不再被需要時(shí)盡早調用它們的這個(gè)方法是很好的做法。 此方法只須在
Document
對象上調用,但也可以在下級節點(diǎn)上調用以丟棄該節點(diǎn)的下級節點(diǎn)。你可以通過(guò)使用
with
語(yǔ)句來(lái)避免顯式調用此方法。 以下代碼會(huì )在with
代碼塊退出時(shí)自動(dòng)取消鏈接 dom:with xml.dom.minidom.parse(datasource) as dom: ... # Work with dom.
- Node.writexml(writer, indent='', addindent='', newl='', encoding=None, standalone=None)?
將 XML 寫(xiě)入到寫(xiě)入器對象。 寫(xiě)入器接受文本而非字節串作為輸入,它應當具有與文件對象接口相匹配的
write()
方法。 indent 形參是當前節點(diǎn)的縮進(jìn)層級。 addindent 形參是用于當前節點(diǎn)的下級節點(diǎn)的縮進(jìn)量。 newl 形參指定用于一行結束的字符串。對于
Document
節點(diǎn),可以使用附加的關(guān)鍵字參數 encoding 來(lái)指定 XML 標頭的編碼格式字段。類(lèi)似地,顯式指明 standalone 參數將會(huì )使單獨的文檔聲明被添加到 XML 文檔的開(kāi)頭部分。 如果將該值設為 True,則會(huì )添加 standalone="yes",否則將為 "no"。 未指明該參數將使文檔聲明被省略。
在 3.8 版更改:
writexml()
方法現在會(huì )保留用戶(hù)指定的屬性順序。在 3.9 版更改: The standalone parameter was added.
- Node.toxml(encoding=None, standalone=None)?
返回一個(gè)包含 XML DOM 節點(diǎn)所代表的 XML 的字符串或字節串。
帶有顯式的 encoding 1 參數時(shí),結果為使用指定編碼格式的字節串。 沒(méi)有 encoding 參數時(shí),結果為 Unicode 字符串,并且結果字符串中的 XML 聲明將不指定編碼格式。 使用 UTF-8 以外的編碼格式對此字符串進(jìn)行編碼通常是不正確的,因為 UTF-8 是 XML 的默認編碼格式。
standalone 參數的行為與
writexml()
中的完全一致。在 3.8 版更改:
toxml()
方法現在會(huì )保留用戶(hù)指定的屬性順序。在 3.9 版更改: The standalone parameter was added.
- Node.toprettyxml(indent='\t', newl='\n', encoding=None, standalone=None)?
返回文檔的美化打印版本。 indent 指定縮進(jìn)字符串并默認為制表符;newl 指定標示每行結束的字符串并默認為
\n
。encoding 參數的行為類(lèi)似于
toxml()
的對應參數。standalone 參數的行為與
writexml()
中的完全一致。在 3.8 版更改:
toprettyxml()
方法現在會(huì )保留用戶(hù)指定的屬性順序。在 3.9 版更改: The standalone parameter was added.
DOM 示例?
此示例程序是個(gè)相當實(shí)際的簡(jiǎn)單程序示例。 在這個(gè)特定情況中,我們沒(méi)有過(guò)多地利用 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
模塊實(shí)際上是兼容 DOM 1.0 的 DOM 并帶有部分 DOM 2 特性(主要是命名空間特性)。
Python 中 DOM 接口的用法十分直觀(guān)。 會(huì )應用下列映射規則:
接口是通過(guò)實(shí)例對象來(lái)訪(fǎng)問(wèn)的。 應用程序不應實(shí)例化這些類(lèi)本身;它們應當使用
Document
對象提供的創(chuàng )建器函數。 派生的接口支持上級接口的所有操作(和屬性),并添加了新的操作。操作以方法的形式使用。 因由 DOM 只使用
in
形參,參數是以正常順序傳入的(從左至右)。 不存在可選參數。void
操作返回None
。IDL 屬性會(huì )映射到實(shí)例屬性。 為了兼容針對 Python 的 OMG IDL 語(yǔ)言映射,屬性
foo
也可通過(guò)訪(fǎng)問(wèn)器方法_get_foo()
和_set_foo()
來(lái)訪(fǎng)問(wèn)。readonly
屬性不可被修改;運行時(shí)并不強制要求這一點(diǎn)。short int
,unsigned int
,unsigned long long
和boolean
類(lèi)型都會(huì )映射為 Python 整數類(lèi)型。DOMString
類(lèi)型會(huì )映射為 Python 字符串。xml.dom.minidom
支持字節串或字符串,但通常是產(chǎn)生字符串。DOMString
類(lèi)型的值也可以為None
,W3C 的 DOM 規格說(shuō)明允許其具有 IDLnull
值。const
聲明會(huì )映射為它們各自的作用域內的變量 (例如xml.dom.minidom.Node.PROCESSING_INSTRUCTION_NODE
);它們不可被修改。DOMException
目前不被xml.dom.minidom
所支持。xml.dom.minidom
會(huì )改為使用標準 Python 異常例如TypeError
和AttributeError
。NodeList
對象是使用 Python 內置列表類(lèi)型來(lái)實(shí)現的。 這些對象提供了 DOM 規格說(shuō)明中定義的接口,但在較早版本的 Python 中它們不支持官方 API。 相比在 W3C 建議中定義的接口,它們要更加的 "Pythonic"。
下列接口未在 xml.dom.minidom
中實(shí)現:
DOMTimeStamp
EntityReference
這些接口所反映的 XML 文檔信息對于大多數 DOM 用戶(hù)來(lái)說(shuō)沒(méi)有什么幫助。
備注
- 1
包括在 XML 輸出中的編碼格式名稱(chēng)應當遵循適當的標準。 例如,"UTF-8" 是有效的,但 "UTF8" 在 XML 文檔的聲明中是無(wú)效的,即使 Python 接受其作為編碼格式名稱(chēng)。 詳情參見(jiàn) https://www.w3.org/TR/2006/REC-xml11-20060816/#NT-EncodingDecl 和 https://www.iana.org/assignments/character-sets/character-sets.xhtml。