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