【Python】 xml解析與生成 xml


xml

  *之前用的時候也沒想到。。其實用BeautifulSoup就可以解析xml啊。。因為html只是xml的一種實現方式吧。但是很蛋疼的一點就是,bs不提供獲取對象的方法,其find大多獲取的都是字符串,這就導致不得不一遍遍地連續通過bs總對象來定位元素再輸出這樣子。挺麻煩的。

  xml是一種常用的網絡通訊格式,也是一種文件的格式。xml包里有多種不同的可用於解析&生成文件的模塊,比如:

    xml.dom.minidom

    xml.etree.ElementTree

    xml.aix等等。這三者比較起來,minidom最貼近底層代碼,但是寫起來也最煩。本文主要通過ElementTree來解析&生成。盡管ElementTree也有很多不合理的地方,但是可以通過修改源碼,重載源碼的部分方法來解決。

  ■  ElementTree基本用法

from xml.etree import ElementTree

doc = ElementTree.parse("文件路徑"or"文件對象"[,parser=...])
'''
雖然也可用ElementTree直接來生成文件對象,但是用parse來生成的話可以指定parser。這個parser后面會講到有什么作用
'''

  所得到的doc對象就是文件的根節點對象。所謂根節點,就是整個文件第一對有效的標簽所指代的節點。

  ●  對於每個節點,都有:

    .text  代表該節點的文本內容(和bs一樣,那些有子孫元素但是本身沒有內容的節點的這個屬性是空串,需要注意)

    .attrib  代表該節點的屬性(字典形式)

    .tag  代表該節點的tag名

  ●  而對於包括根節點在內的所有節點都有以下節點可調用的方法:

    .find("tag名")  找出其子節點中第一個指定tag名的節點

    .findall("tag名")  找出所有子節點which是指定的tag名,返回一個列表

    .findtext("tag名")  找出相應子節點的文本內容,相當於上面的find找到對象之后再訪問其.text屬性

    //以上三個方法都是只檢索子節點,不檢索孫節點以及更加后輩的節點

    .getiterator([tag])  從當前節點開始,生成一個迭代器,里面是遍歷了包括當前節點在內的所有后輩節點。tag參數相當於一個filter,指定tag的話迭代器只返回tag名和給出值一致的節點。

    *以上的那些find啥啥的方法,里面的tag名其實是有語法的。單純的"tag"就只檢索當前節點的子節點中名為tag的節點。如果是'.//tag'的話就是搜索所有后輩節點中的tag節點了。更多具體的語法可以參見python參考手冊,就不多說了

  ●  另外,ElementTree也在節點對象中實現了幾個magic method,所以節點(這次不包括根節點了)也有了如下借口:

    elem[n]  節點elem的第n個子節點(不是n+1個!

    del elem[n]  刪除elem的第n個子節點

    len(elem)  子節點的個數

    elem[n] = newElement  將某個子節點替換成另外一個element

 

   ●  對於非根節點,還有以下的一些方法:

    clear()  清空所有后輩節點

    append(Element)  加入一個新子節點

    get(key)  獲取某個屬性的值

    insert(index,Element)  將子節點插入某個特定的位置

    remove(Element)  從該節點中移除一個子節點

    set(key,value)  設置某個節點的屬性值

  ●  關於Element的構造方法

    上面很多方法都用element作為參數,那么element是怎么來的,就要用到Element構造方法了。

    ElementTree.Element(tag[,attrib])  構造一個Element,但是沒有文本內容

    ElementTree.XML("xmlcode")  將一段xml代碼轉化為一個Element對象,比較實用

    ElementTree.Comment("text")  生成一段注釋的Element對象

   ●  最后,ElementTree還提供了幾個類方法

    ElementTree.dump(Element)  把相關element的內容打印出來,主要用於調試。因為element對象普遍沒有實現__repr__方法

    ElementTree.iselement(element)  判斷某個對象是不是有效的element對象

 

 以上的所有操作都是對存儲在內存中的一個XMLTree對象的改動,要想保存成文件,只要根節點調用方法write即可

doc.write("文件路徑"or"w模式文件對象"[,encoding=xxx])

 這里面的encoding參數也有點意思。encoding的默認值是utf-8,當encoding被指定且不是utf-8或者ascii的時候,在新生成的文件頭上自動會加一條<?xml version="1.0" encoding="xxx">

 

  *ElementTree有一個很大的問題,就是在默認情況下,會吃掉所有注釋內容。

   這種現象的原因是因為,源碼中默認的TreeBuilder(這個類的作用是構建一個對象,這個對象用來存儲抽象化后的文件內容。)在建立Tree對象的時候沒有寫處理注釋的方法。

   解決方法是自己寫個CommentedTreeBuilder類來重載處理注釋:

class CommentedTreeBuilder(XMLTreeBuilder):
    
    def __init__(self, html=0, target=None):
        XMLTreeBuilder.__init__(self, html, target)
        self._parser.CommentHandler = self.handle_comment    #指定處理comment的方法。

    def handle_comment(self, data):
        '''
        默認的處理comment的方法是什么都不做直接pass,而在這個方法里,通過start,data和end三個方法,相當於把注釋的內容原封不動地復制到創建的Tree對象里去,使得注釋得以保存
        '''
        self._target.start(Comment, {})
        self._target.data(data)
        self._target.end(Comment)

  handle_comment方法接受的參數data是一個ascii字符串或者unicode字符串。當有中文字符時無疑data是unicode。如果在write的時候不指明encoding類型的話可能會出現寫入中文字符出錯,變成其編碼的格式了。解決辦法就是在write的時候指出encoding參數如encoding='UTF-8'


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM