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