xml.dom.minidom
--- 最小化的 DOM 實現(xiàn)?
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)?
返回一個代表 string 的
Document
。 此方法會為指定字符串創(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
之間的差異。
- Node.unlink()?
破壞 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 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
會改為使用標準 Python 異常例如TypeError
和AttributeError
。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-EncodingDecl 和 https://www.iana.org/assignments/character-sets/character-sets.xhtml。