http://www.cnblogs.com/xuxm2007/archive/2011/01/16/1936610.html
http://blog.csdn.net/ywchen2000/archive/2006/07/04/876742.aspx
http://blog.csdn.net/zhangj1012003_2007/archive/2010/04/23/5514807.aspx
http://blog.csdn.net/zhangj1012003_2007/archive/2010/04/22/5514929.aspx
http://blog.csdn.net/zhangj1012003_2007/archive/2010/04/22/5514935.aspx
一.XML的讀取.
在 NewEdit 中有程式碼片段的功能,程式碼片段分為片段的分類和片段的內容。在預設情況下都是用XML格式儲存的。下面我講述一下,如何使用minidom來讀取和儲存XML檔案。
下面是片段分類的一個樣本檔案--catalog.xml
<?xml version="1.0" encoding="utf-8"?>
<catalog>
<maxid>4</maxid>
<item id="1">
<caption>Python</caption>
<item id="4">
<caption>測試</caption>
</item>
</item>
<item id="2">
<caption>Zope</caption>
</item>
</catalog>
分類是樹狀結構,顯示出來可能為:
Python
測試
Zope
先簡單介紹一下XML的知識,如果你已經知道了可以跳過去。
1. XML文檔的編碼
此XML文檔的編碼為utf-8,因此你看到的“測試”其實是UTF-8編碼。在XML文檔的處理中都是使用UTF-8編碼進行的,因此,如果你不寫明encoding的話,都是認為檔案是UTF-8編碼的。在Python中,好象只支援幾種編碼,象我們常用的GB2312碼就不支援,因此建議大家在處理XML時使用UTF-8編碼。
2. XML文檔的結構
XML文檔有XML頭資訊和XML資訊體。頭資訊如:
<?xml version="1.0" encoding="utf-8"?>
它表明了此XML文檔所用的版本,編碼方式。有些複雜的還有一些文件類型的定義(DOCTYPE),用於定義此XML文檔所用的DTD或Schema和一些實體的定義。這裡並沒有用到,而且我也不是專家,就不再細說了。
XML資訊體是由樹狀元素組成。每個XML文檔都有一個文件項目,也就是樹的根項目,所有其它的元素和內容都包含在根項目中。
3. DOM
DOM是Document Object Model的簡稱,它是以對象樹來表示一個XML文檔的方法,使用它的好處就是你可以非常靈活的在對象中進行遍曆。
4. 元素和結點
元素就是標記,它是成對出現的。XML文檔就是由元素組成的,但元素與元素之間可以有文本,元素的內容也是文本。在minidom中有許多的結點,元素也屬於結點的一種,它不是葉子結點,即它存在子結點;還存在一些葉子結點,如文本結點,它下面不再有子結點。
象catalog.xml中,文件項目是catalog,它下面有兩種元素:maxid和item。maxid用來表示當前最大的item的id值。每一個item都有一個id屬性,id屬性是唯一的,在 NewEdit 中用來產生每個分類所對應的程式碼片段的XML文檔名,因此不能重複,而且它是一個遞增的值。item元素有一個caption子項目,用來表示此分類項的名稱,它還可以包含item元素。這樣,就定義了一個樹狀XML結構,下面讓我們看一看如果把它們讀出來。
一、得到dom對象
>>> import xml.dom.minidom
>>> dom = xml.dom.minidom.parse('d:/catalog.xml')
這樣我們得到了一個dom對象,它的第一個元素應該是catalog。
二、得到文件項目對象
>>> root = dom.documentElement
這樣我們得到了根項目(catalog)。
三、結點屬性
每一個結點都有它的nodeName,nodeValue,nodeType屬性。nodeName為結點名字。
>>> root.nodeName
u'catalog'
nodeValue是結點的值,只對文本結點有效。nodeType是結點的類型,現在有以下幾種:
'ATTRIBUTE_NODE'
'CDATA_SECTION_NODE'
'COMMENT_NODE'
'DOCUMENT_FRAGMENT_NODE'
'DOCUMENT_NODE'
'DOCUMENT_TYPE_NODE'
'ELEMENT_NODE'
'ENTITY_NODE'
'ENTITY_REFERENCE_NODE'
'NOTATION_NODE'
'PROCESSING_INSTRUCTION_NODE'
'TEXT_NODE'
這些結點通過名字很好理解。catalog是ELEMENT_NODE類型。
>>> root.nodeType
1
>>> root.ELEMENT_NODE
1
四、子項目、子結點的訪問
訪問子項目、子結點的方法很多,對於知道元素名字的子項目,可以使用getElementsByTagName方法,如讀取maxid子項目:
>>> root.getElementsByTagName('maxid')
[<DOM Element: maxid at 0xb6d0a8>]
這樣返回一個列表,由於我們的例子中maxid只有一項,因此列表也只有一項。
如果想得到某個元素下的所有子結點(包括元素),可以使用childNodes屬性:
>>> root.childNodes
[<DOM Text node "\n ">, <DOM Element: maxid at 0xb6d0a8>, <DOM Text node "\n ">, <DOM Element: item at 0xb6d918>, <DOM Text node "\n ">, <DOM Element: item at 0xb6de40>, <DOM Text node "\n ">, <DOM Element: item at 0xb6dfa8>, <DOM Text node "\n">]
可以看出所有兩個標記間的內容都被視為文本結點。象每行後面的斷行符號,都被看到文本結點。從上面的結果我們可以看出每個結點的類型,本例中有文本結點和元素結點;結點的名字(元素結點);結點的值(文本結點)。每個結點都是一個對象,不同的結點對象有不同的屬性和方法,更詳細的要參見文檔。由於本例比較簡單,只涉及文本結點和元素結點。
getElementsByTagName可以搜尋當前元素的所有子項目,包括所有層次的子項目。childNodes只儲存了當前元素的第一層子結點。
這樣我們可以遍曆childNodes來訪問每一個結點,判斷它的nodeType來得到不同的內容。如,列印出所有元素的名字:
>>> for node in root.childNodes:
if node.nodeType == node.ELEMENT_NODE:
print node.nodeName
maxid
item
item
對於文本結點,想得到它的常值內容可以使用: .data屬性。
對於簡單的元素,如:<caption>Python</caption>,我們可以編寫這樣一個函數來得到它的內容(這裡為Python)。
def getTagText(root, tag):
node = root.getElementsByTagName(tag)[0]
rc = ""
for node in node.childNodes:
if node.nodeType in ( node.TEXT_NODE, node.CDATA_SECTION_NODE):
rc = rc + node.data
return rc
這個函數只處理找到的第一個符合的子項目。它會將符合的第一個子項目中的所有文本結點拼在一起。當nodeType為文本類結點時,node.data為文本的內容。如果我們考查一下元素caption,我們可能看到:
[<DOM Text node "Python">]
說明caption元素只有一個文本結點。
如果一個元素有屬性,那麼可以使用getAttribute方法,如:
>>> itemlist = root.getElementsByTagName('item')
>>> item = itemlist[0]
>>> item.getAttribute('id')
u'1'
這樣就得到了第一個item元素的屬性值。
下面讓我們簡單地小結一下如何使用minidom來讀取XML中的資訊
1. 匯入xml.dom.minidom模組,產生dom對象
2. 得到文檔對象(根對象)
3. 通過getElementsByTagName()方法和childNodes屬性(還有其它一些方法和屬性)找到要處理的元素
4. 取得元素下文本結點的內容
二.寫入.
下面我來示範一下如何從無到有產生象catalog.xml一樣的XML檔案。
一、產生dom對象
>>> import xml.dom.minidom
>>> impl = xml.dom.minidom.getDOMImplementation()
>>> dom = impl.createDocument(None, 'catalog', None)
這樣就產生了一個空的dom對象。其中catalog為文件項目名,即根項目名。
二、顯示產生的XML內容
每一個dom結點對象(包括dom對象本身)都有輸出XML內容的方法,如:toxml(), toprettyxml()
toxml()輸出緊湊格式的XML文本,如:
<catalog><item>test</item><item>test</item></catalog>
toprettyxml()輸出美化後的XML文本,如:
<catalog>
<item>
test
</item>
<item>
test
</item>
</catalog>
可以看出,它是將每個結點後面都加入了斷行符號符,並且自動處理縮近。但對於每一個元素,如果元素只有常值內容,則我希望元素的tag與文本是在一起的,如:
<item>test</item>
而不想是分開的格式,但minidom本身是不支援這樣的處理。關於如何?形如:
<catalog>
<item>test</item>
<item>test</item>
</catalog>
這樣的XML格式,後面我們再說。
三、產生各種結點對象
dom對象擁有各種產生結點的方法,下面列出文本結點,CDATA結點和元素結點的產生過程。
1. 文本結點的產生
>>> text=dom.createTextNode('test')
test
要注意的是,在產生結點時,minidom並不對文本字元進行檢查,象文本中如果出現了'<','&'之類的字元,應該轉換為相應的實體符號'<','&'才可以,這裡沒有做這個處理。
2. CDATA結點的產生
>>> data = dom.createCDATASection('aaaaaa\nbbbbbb')
>>> data.toxml()
'<![CDATA[aaaaaa\nbbbbbb]]>'
CDATA是用於包括大塊文本,同時可以不用轉換'<','&'字元的標記,它是用<![CDATA[文本]]>來包括的。但文本中不可以有"]]>"這樣的串存在。產生結點時minidom不作這些檢查,只有當你輸出時才有可能發現有錯。
3. 元素結點的產生
>>> item = dom.createElement('caption')
>>> item.toxml()
'<caption/>'