lxml.etree

翻译自:https://lxml.de/tutorial.html
lxml.etree提供了原ElementTree API定义的接口,以及一些简单的enhancements。

基本


from lxml import etree
root = etree.Element("root")
>>> print(root.tag)
root

添加子元素:

 root.append( etree.Element("child1") )
 child2 = etree.SubElement(root, "child2")

打印:

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

子元素作为列表

 child = root[0]
 root.index(root[1])  &nbsp;&nbsp; # lxml.etree only!
 root.insert(0, etree.Element("child0")
 root[1:3]
 for child in root:  print(child.tag)

特殊情况(可略过):
同一个元素一般只能存在于一个地方(不同于original ElementTree API)

>>> for child in root:  print(child.tag)
child0
child1
child2
child3
>>> root[0] = root[-1]       # this moves the element in lxml.etree!
>>> for child in root: print(child.tag)
child3
child1
child2

Note that in the original ElementTree, a single Element object can sit in any number of places in any number of trees, which allows for the same copy operation as with lists. The obvious drawback is that modifications to such an Element will apply to all places where it appears in a tree, which may or may not be intended.
The upside of this difference is that an Element in lxml.etree always has exactly one parent, which can be queried through the getparent() method. This is not supported in the original ElementTree.

>>> root is root[0].getparent() &nbsp;&nbsp;  # lxml.etree only!
True

If you want to copy an element to a different position in lxml.etree, consider creating an independent deep copy using the copy module from Python's standard library: from copy import deepcopy.

属性作为字典

 root = etree.Element("root", interesting="totally")
 root.get("hello")
 root.set("hello", "Huhu")
 sorted(root.keys())
 for name, value in sorted(root.items()):  print('%s = %r' % (name, value))

Element的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(root.attrib) 可以得到一个独立的字典。

元素中的文本

>>> root = etree.Element("root")
>>> root.text = "TEXT"
>>> etree.tostring(root)
b'<root>TEXT</root>'

数据型XML一般只会在叶子节点包含文本,但是在超文本文档里,文本可能出现在元素之间。
这可以通过tail成员获得支持(可略过):

>>> html = etree.Element("html")
>>> body = etree.SubElement(html, "body")
>>> body.text = "TEXT"
>>> br = etree.SubElement(body, "span")
>>> br.tail = "TAIL"
>>> br.text = "MIDDLE"
>>> etree.tostring(html)
b'<html><body>TEXT<span>MIDDLE</span>TAIL</body></html>'
>>> body.text, br.text, br.tail
('TEXT', 'MIDDLE', 'TAIL')

注意.text成员只包含元素子文本中紧贴开头的部分, 而.tail成员包含紧跟在该元素后面的文本。
使用tostring可以提取出xml中所含的全部文本:

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

iter方法

元素的.iiter方法会产生一个文档树顺序的迭代器(注意和直接迭代元素本身的不同)。

>>> root = etree.Element("root")
>>> etree.SubElement(root, "child").text = "Child 1"
>>> etree.SubElement(root, "child").text = "Child 2"
>>> etree.SubElement(root, "another").text = "Child 3"
>>> etree.SubElement(root[1], "grandchild").text = "Grandchild"
>>> print(etree.tostring(root, pretty_print=True))
<root>
  <child>Child 1</child>
  <child>Child 2<grandchild>Grandchild</grandchild></child>
  <another>Child 3</another>
</root>

>>> for element in root.iter():
...     print("%s - %s" % (element.tag, element.text))
root - None
child - Child 1
child - Child 2
grandchild - Grandchild
another - Child 3

给iter方法指定tag时会仅迭代指定的元素。

>>> for element in root.iter("child"):
...     print("%s - %s" % (element.tag, element.text))
child - Child 1
child - Child 2
>>> for element in root.iter("another", "child"):
...     print("%s - %s" % (element.tag, element.text))
child - Child 1
child - Child 2
another - Child 3

ElementTree 类

ElementTree类包含完整的文档信息,如DOCTYPE和DTD。

>>> root = etree.XML('''\
... <?xml version="1.0"?>
... <!DOCTYPE root SYSTEM "test" [ <!ENTITY tasty "parsnips"> ]>
... <root>
...   <a>&tasty;</a>
... </root>
... ''')
>>> tree = etree.ElementTree(root)
>>> print(tree.docinfo.xml_version)
1.0
>>> print(tree.docinfo.doctype)
<!DOCTYPE root SYSTEM "test">
>>> tree.docinfo.public_id = '-//W3C//DTD XHTML 1.0 Transitional//EN'
>>> tree.docinfo.system_url = 'file://local.dtd'
>>> print(tree.docinfo.doctype)
<!DOCTYPE root PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "file://local.dtd">

ElementTree是使用parse()函数来解析文件的返回值类型。
注意序列化时ElementTree和它的根节点的不同

>>> print(etree.tostring(tree).decode())
<!DOCTYPE root PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "file://local.dtd" [
<!ENTITY tasty "parsnips">
]>
<root>
<a>parsnips</a>
</root>
>>> tree.getroot() is root
True
>>> print(etree.tostring(root).decode())
<root>
<a>parsnips</a>
</root>

Parsing from strings and files


fromstring()

fromstring函数可以把一串xml解析为一个xml元素(返回值类型和etree.Element一样是lxml.etree._Element类)。

>>> some_xml_data = "<root>data</root>"
>>> root = etree.fromstring(some_xml_data)
>>> etree.tostring(root)
b'<root>data</root>'

XML()

XML函数的行为基本和fromstring一致,也是返回Element类。

>>> root = etree.XML("<root>data</root>")
>>> etree.tostring(root)
b'<root>data</root>'

还有一个HTML函数,会自动加上html和body元素(如果原字符串没有的话)(同样是返回Element类)。

>>> root = etree.HTML("<p>data</p>")
>>> etree.tostring(root)
b'<html><body><p>data</p></body></html>'

注意:HTML函数的返回值依然会被当成标准XML处理。

>>> root = etree.HTML('<head/><p>Hello<br/>World</p>')
>>> etree.tostring(root)
b'<html><head/><body><p>Hello<br/>World</p></body></html>'
>>> etree.tostring(root, method='html') 
b'<html><head></head><body><p>Hello<br>World</p></body></html>'

parse()

parse函数主要用于解析完整的文档,而上述几个字符串解析函数主要用于解析文档碎片。
注意:parse函数返回ElementTree对象,而不是Element对象。

>>> from io import BytesIO
>>> tree = etree.parse(BytesIO(b"<root>data</root>"))
>>> etree.tostring(tree)
b'<root>data</root>'
>>> etree.tostring(tree.getroot())
b'<root>data</root>'

parse函数支持以下参数:

  • 打开的文件或文件型对象(建议以二进制模式打开)
  • 文件名字符串
  • HTTP或者FTP的url

注意从文件名或者url解析通常比从文件对象解析要快。

Parser对象

暂无,见原链接。

Incremental parsing

暂无,见原链接。
lxml.etree provides two ways for incremental step-by-step parsing. One is through file-like objects, where it calls the read() method repeatedly. The second way is through a feed parser interface, given by the feed(data) and close() methods:

Event-driven parsing

暂无,见原链接。
Sometimes, all you need from a document is a small fraction somewhere deep inside the tree, so parsing the whole tree into memory, traversing it and dropping it can be too much overhead. lxml.etree supports this use case with two event-driven parser interfaces.

Namespaces

暂无,见原链接。

The E-factory

暂无,见原链接。
The E-factory provides a simple and compact syntax for generating XML and HTML. Element creation based on attribute access makes it easy to build up a simple vocabulary for an XML language:

ElementPath

暂无,见原链接。
The ElementTree library comes with a simple XPath-like path language called ElementPath. The API provides four methods here that you can find on Elements and ElementTrees:

  • iterfind() iterates over all Elements that match the path expression
  • findall() returns a list of matching Elements
  • find() efficiently returns only the first match
  • findtext() returns the .text content of the first match
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容