【譯】:lxml.etree官方文檔


本文翻譯自:http://lxml.de/tutorial.html, 作者:Stefan Behnel

這是一個關於使用lxml.etree進行XML處理的教程。它簡要介紹了ElementTree API的主要概念,以及一些簡單的增強功能,使你的編程更容易。

有關API的完整參考,請參考生成的API文檔

內容:

  • 元素類

    · 元素是列表

    · 元素以屬性為特征

    · 元素包含文本

    · 使用XPath查找文本

    · 樹迭代

    · 序列化

  • ElementTree類

  • 從字符串和文件解析

    · fromstring()函數

    · XML()函數

    · parse()函數

    · 解析器對象

    · 增量解析

    · 事件驅動解析

  • Namespaces

  • The E-factory

  • ElementPath

 導入lxml.etree的常見方法如下:

from lxml import etree

如果你的代碼僅使用ElementTree API,並不依賴於特定的lxml.etree的任何功能,你還可以利用下面的導入方法:

try:
    from lxml import etree
    print("running with lxml.etree")
except ImportError:
    try:
        #Python 2.5
        import xml.etree.cElementTree as etree
        print("running with cElementTree on Python 2.5+")
    except ImportError:
        try:
            #Python 2.5
            import xml.etree.ElementTree as etree
            print("running with ElementTree on Python 2.5+")
        except ImportError:
            try:
                #正常的cElementTree安裝
                import cElementTree as etree
                print("running with cElementTree")
            except ImportError:
                try:
                    #正常的ElementTree安裝
                    import elementtree.ElementTree as etree
                    print("running with ElementTree")
                except ImportError:
                    print("Failed to import ElementTree from any known place")

為了編寫可移植代碼,本教程在例子中說明了API的哪一部分是由Fredrik Lundh的ElementTree庫定義的原始ElementTree API的lxml.etree的擴展。

» 元素類

單個元素是ElementTree API的主要的容器對象。大多數XML樹功能都是通過這個類訪問的。元素可以通過Element factory輕松創建:

>>> root = etree.Element("root")

元素的XML標簽名通過tag屬性訪問:

>>> print (root.tag)
root

元素以XML樹結構組織。要添加子元素並將其添加到父元素中,可以使用append()方法:

>>> root.append( etree.Element("child1") )

然而,這是很常見的。有一個更短更有效的方法做到這一點:SubElement factory。它接受與Element factory相同的參數,但要求父元素作為第一個參數:

>>> child2 = etree.SubElement(root, "child2")
>>> child3 = etree.SubElement(root, "child3")

要看到真正的XML,你可以序列化創建的樹:

>>> print (etree.tostring(root, pretty_print = True))
<root>
    <child1/>
    <child2/>
    <child3/>
</root>

元素是列表

為了更容易、更直接的訪問這些子元素,元素盡可能地模仿python列表的行為:

>>> child = root[0]
>>> print (child.tag)
child1

>>> print (len(root))
3

>>> root.index(root[1])
1

>>> children = list(root)

>>> for child in root:
...           print (child.tag)
child1
child2
child3

>>> root.insert(0, etree.Element("child0"))
>>> start = root[:1]
>>> end = root[-1:]

>>> print (start[0].tag)
child0
>>> print (end[0].tag)
child3

 在ElementTree 1.3和lxml 2.0之前,你還可以檢查一個元素的真值,看它是否有子代,即如果子列表為空:

if root:
    print ("The root element has children")

這不再受支持,因為人們傾向於期待"something“被評估為True,期待元素成為"something”,它們可能有子代嗎?所以很多用戶驚奇的發現任何元素都會在上面的if語句中被評估為False。相反的,使用len(element)更明確,更少出錯。

>>> print (etree.iselement(root))   #測試它是否是element類型
True
>>> if len(root):                   #測試它是否有子代
...          print ("The root element has children")
The root element has children

還有一種重要的情況,其中lxml(2.0及以上版本)中Elements的行為偏離了列表和原始的ElementTree(1.3之前的版本或Python2.7/3.2):

>>> for child in root:
...           print (child.tag)
child0
child1
child2
child3
>>> root[0] = root[-1]
>>> for child in root:
...           print (child.tag)
child3
child1
child2

在這個例子中,最后一個元素被剪切到一個不同的位置,而不是復制,即當它被放在不同的位置時,它被自動從它前一個位置移除。在列表中,對象可以同時出現在多個位置,上述分配只會將item引用復制到第一個位置,以便兩者都包含相同的item。

>>> 1 = [0, 1, 2, 3]
>>> 1[0] = 1[-1]
>>> 1
[3, 1, 2, 3]

 注意在原始的ElementTree中,單個的Element對象可以位於任意數量的樹中的任意數量位置,這允許與列表相同的復制操作,明顯的缺點是對這種元素的修改將會適用於它出現樹中的所有地方,這可能是也可能不是初衷。

這個區別的優點是,lxml.etree中的Element總是具有一個父對象,可以通過getparent()方法進行查詢。這在原始的ElementTree中是不支持的。

>>> root is root[0].getparent()
True

如果要將單個元素復制到lxml.etree中的不同位置,請考慮使用Python標准庫中的復制模塊來創建一個獨立的深層副本:

>>> from copy import deepcopy

>>> element = etree.Element("neu")
>>> element.append( deepcopy(root[1]) )

>>> print (element[0].tag)
child1
>>> print ([ c.tag for c in root ])
['child3', 'child1', 'child2']

元素的同胞(或鄰居)作為下一個和前一個元素被訪問:

>>> root[0] is root[1].getprevious()
True
>>> root[1] is root[0].getnext()
True

元素以屬性為特征

XML元素支持屬性。你可以在Element factory直接創建它們:

>>> root = etree.Element("root", interesting = "totally")
>>> etree.tostring(root)
b'<root interesting = "totally"/>'

 屬性只是無序的name-value對,所以處理它們非常方便的方法是通過Elements的類似字典的界面:

>>> print (root.get("interesting"))
totally

>>> print (root.get("hello"))
None
>>> root.set("hello", "Huhu"))
>>> print (root.get("hello"))
Huhu

>>> etree.tostring(root)
b'<root insteresting = "totally" hello = "Huhu"/>'

>>> sorted(root.keys())
['hello', 'insteresting']

>>> for name, value in sorted(root.items()):
...           print ('%s = %r' % (name, value))
hello = 'Huhu'
interesting = 'totally'

對於你想查找item或其他原因來獲取一個'real'類似字典對象的情況,例如傳遞給它,你可以使用attrib屬性:

>>> attributes = root.attrib

>>> print (attributes["interesting"])
totally
>>> print (attributes.get("no-such-attribute"))
None

>>> attributes["Hello"] = "Guten Tag"
>>> print (attributes["hello"])
Guten Tag
>>> print (root.get("hello"))
Guten Tag

注意attrib是由Element本身支持的類似dict的對象。這意味着對元素的任何修改都反映在屬性中,反之亦然。這也意味着,只要一個元素的attrib在使用,XML樹就活躍在內存中。要獲取不依賴XML樹的屬性的獨立快照,將其復制到dict中:

>>> d = dict(root.attrib)
>>> sorted(d.items())
[('hello', 'Guten Tag'), ('insteresting', 'totally')]

元素包含文本

元素可以包含文本:

>>> root = etree.Element("root")
>>> root.text = "TEXT"

>>> print (root.text)
TEXT

>>> etree.tostring(root)
b'<root>TEXT</root>'

 在許多XML文檔(以數據為中心的文檔)中,這是唯一可以找到文本的地方。它由葉子標簽封裝在樹層次結構的底部。

然而,如果XML用於標記的文本文檔,例如(X)HTML,文本也可以出現在不同元素之間,就在樹的中間:

<html><body>Hello</br>World</body></html>

這里,</br>標簽由文本環繞。這通常被稱為文本樣式或混合內容XML。元素通過尾部屬性來支持它。它包含直接跟隨元素的文本,直到XML樹中的下一個元素:

>>> html = etree.Element("html")
>>> body = etree.SubElement(html, "body")
>>> body.text = "TEXT"

>>> etree.tostring(html)
b'<html><body>TEXT</body></html>'

>>> br = etree.SubElement(body, "br")
>>> etree.tostring(html)
b'<html><body>TEXT<br/></body></html>'

>>> br.tail = "TAIL"
>>> etree.tostring(html)
b'<html><body>TEXT<br/>TAIL</body></html>'

兩個屬性 .text和 .tail足以表示XML文檔中的任何文本內容。這樣,除了Element類之外,ElementTree API不需要任何特殊的文本節點,它往往會得到一些方法(正如你從傳統的的DOM API中知道的那樣)。

然而,有些情況下尾部文本也會妨礙。例如,當你從樹中序列化一個元素時,你並不總是希望在結果中顯示尾部文本(盡管你仍然希望其子代碼的尾部文本)。為此,tostring()函數接受關鍵字參數with_tail

>>> etree.tostring(br)
b'<br/>TAIL'
>>> etree.tostring(br, with_tail=False) # lxml.etree only!
b'<br/>'

如果你想讀的只有文字,即沒有任何中間變量,你必須遞歸串聯所有文字和以正確的順序屬性。再次使用tostring()函數來救援,這次使用method關鍵字:

>>> etree.tostring(html, method="text")
b'TEXTTAIL'

 


免責聲明!

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



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