lxml.etree 入门
2016-06-24 17:33
686 查看
来源 http://lxml.de/tutorial.html
作者: Stefan Behnel
这个教学覆盖lxml 处理的主要几个方面,其中的一些功能也许能使你的码农生涯好过一点。
完整的API 请看 http://lxml.de/api/index.html 。
通常像下面这样导入 lxml.etree 模块:
访问标签名,用tag属性。
添加子节点的方法之一,append方法:
更有效的方法是SubElement工厂函数,使用如下:
这个方法,建立元素,添加子节点一步完成。
使用tostring 方法,可以看到刚才建立的 xml文件全貌。
节点本身就是列表
节点在努力模拟Python中list的样子:
可以使用索引来获取元素
对于上面建立的xml,
在ElementTree 1.3 and lxml 2.0 以前的版本中,可以使用下面的代码来判断,一个节点是否有子节点。
但这个已经不再支持了。因为有些人认为,节点也是“某种东西”,所以对节点判断,本来就应该是True。即使这个节点没有子节点。 代替方案是用 len(element) 。
在lxml和Python原生的list之间,还要一点不同。请看代码
它把最后一个元素移动到第一个位置了。
可是在原生的list中,只是把最后一个对象的引用拷贝到第一个位置 。也就是说同一个对象可以同时出现在不同的地方。这一点在lxml中不一样,他用的是移动,而不是拷贝。
注意在原生的ElementTree中,节点就像list一样可以复制在许多不同的地方,可这样也有一个明显的缺点,就是改变这个节点后,所有引用这个节点的地方都会一个改变,这可能不是你想要的。
Element 总是有一个确切的父节点,可以通过getparent() 方法来查询,这在原生ElementTree中并不支持。
既然,在lxml中的节点无法复制都是移动的形式,如果你真的是想复制,那怎么办呢?
请使用copy库的deepcopy方法。
上面这个例子展示的是,用deepcopy复制了root[1]这个元素后,并没有移动它。所有还是能在原来的root中打印出来的。
相邻元素之间的访问
元素像字典一样携带属性。
XML节点支持属性,可以在Element函数中直接创建属性。
属性即是无序的键值对,所以用字典可以方便的处理。
如果你想获取字典这样的结构,就用attrib属性获取。
attrib 是Element中支持类似字典的对象, 这意味着任何对节点的改变会反映到attrib属性,反之亦然。
只要节点的一个属性在使用中,XML就在内存中活跃着。为了得到一个独立的属性的快照,不要依赖xml tree,用copy复制一个。
在节点中包含文本
在节点中可以携带文字,
在许多XML文档中,这是文本能存放的唯一地方,文本被包裹在节点的标签中。
然而,像XHTML这样的,文本也可能出现在不同的节点之间,或者在节点的右边。
像这个例子,
灵活使用 .text 和 .tail 这两个属性,就可以满足任何文本插入的需要。这样,API就不需要专门的文本节点了。
然而,当你序列化一个xml时,可能并不想要tail的文本,这时,你只需要在用tostring方法时, 注意指定with_tail的值为False即可,下面是示例代码:
下面有个强大的功能,如果你只想要xml中间的文本,而不要任何的标签。这个有个方法可以快速搞定。
还是tostring方法,传入method关键字为 text 即可。
比如要把word中的文本读出来,又不需要大堆的标签时。这个就派上用场了。
另一个提取文本的方法是 XPath ,并且还能把提取的文本,放入一个list中间。
如果你要经常用这个功能, 还可以把它封装成一个函数
通过XPath返回的对象有些聪明,它能够知道自己的来源。你可以通过getparent()方法,来知道它来自哪个节点。就像你通过节点直接查看那样。
你还可以知道,这个文本是普通文本,还是tail文本。
While this works for the results of the text() function, lxml will not tell you the origin of a string value that was constructed by the XPath functions string() or concat():
当使用text()函数来获取文本时, 是可以获取parent的关系的。但是如果是用string()和concat方法,就不能获取这样的特性了。示例代码
未完
作者: Stefan Behnel
这个教学覆盖lxml 处理的主要几个方面,其中的一些功能也许能使你的码农生涯好过一点。
完整的API 请看 http://lxml.de/api/index.html 。
通常像下面这样导入 lxml.etree 模块:
from lxml import etree
Element 类
这个一个主要的类,大部分函数都通过它来进行。使用Element工厂函数很容易建立起一个xml元素。访问标签名,用tag属性。
root = etree.Element("root") print(root.tag) #root
添加子节点的方法之一,append方法:
root.append( etree.Element("child1") )
更有效的方法是SubElement工厂函数,使用如下:
child2 = etree.SubElement(root, "child2") child3 = etree.SubElement(root, "child3")
这个方法,建立元素,添加子节点一步完成。
使用tostring 方法,可以看到刚才建立的 xml文件全貌。
>>>print(etree.tostring(root, pretty_print=True)) <root> <child1/> <child2/> <child3/> </root>
节点本身就是列表
节点在努力模拟Python中list的样子:
可以使用索引来获取元素
对于上面建立的xml,
child = root[0] print(child.tag) #child1 print(len(root)) #3 root.index(root[1]) # lxml.etree only! #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 and lxml 2.0 以前的版本中,可以使用下面的代码来判断,一个节点是否有子节点。
if root: # this no longer works! print("The root element has children")
但这个已经不再支持了。因为有些人认为,节点也是“某种东西”,所以对节点判断,本来就应该是True。即使这个节点没有子节点。 代替方案是用 len(element) 。
print(etree.iselement(root)) # test if it's some kind of Element True if len(root): # test if it has children print("The root element has children") #The root element has children
在lxml和Python原生的list之间,还要一点不同。请看代码
>>> 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
它把最后一个元素移动到第一个位置了。
>>> l = [0, 1, 2, 3] >>> l[0] = l[-1] >>> l [3, 1, 2, 3]
可是在原生的list中,只是把最后一个对象的引用拷贝到第一个位置 。也就是说同一个对象可以同时出现在不同的地方。这一点在lxml中不一样,他用的是移动,而不是拷贝。
注意在原生的ElementTree中,节点就像list一样可以复制在许多不同的地方,可这样也有一个明显的缺点,就是改变这个节点后,所有引用这个节点的地方都会一个改变,这可能不是你想要的。
Element 总是有一个确切的父节点,可以通过getparent() 方法来查询,这在原生ElementTree中并不支持。
>>> root is root[0].getparent() # lxml.etree only! True
既然,在lxml中的节点无法复制都是移动的形式,如果你真的是想复制,那怎么办呢?
请使用copy库的deepcopy方法。
>>> 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']
上面这个例子展示的是,用deepcopy复制了root[1]这个元素后,并没有移动它。所有还是能在原来的root中打印出来的。
相邻元素之间的访问
>>> root[0] is root[1].getprevious() # lxml.etree only! True >>> root[1] is root[0].getnext() # lxml.etree only! True
元素像字典一样携带属性。
XML节点支持属性,可以在Element函数中直接创建属性。
>>> root = etree.Element("root", interesting="totally") >>> etree.tostring(root) b'<root interesting="totally"/>'
属性即是无序的键值对,所以用字典可以方便的处理。
>>> print(root.get("interesting")) totally >>> print(root.get("hello")) None >>> root.set("hello", "Huhu") >>> print(root.get("hello")) Huhu >>> etree.tostring(root) b'<root interesting="totally" hello="Huhu"/>' >>> sorted(root.keys()) ['hello', 'interesting'] >>> for name, value in sorted(root.items()): ... print('%s = %r' % (name, value)) hello = 'Huhu' interesting = 'totally'
如果你想获取字典这样的结构,就用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中支持类似字典的对象, 这意味着任何对节点的改变会反映到attrib属性,反之亦然。
只要节点的一个属性在使用中,XML就在内存中活跃着。为了得到一个独立的属性的快照,不要依赖xml tree,用copy复制一个。
>>> d = dict(root.attrib) >>> sorted(d.items()) [('hello', 'Guten Tag'), ('interesting', 'totally')]
在节点中包含文本
在节点中可以携带文字,
>>> root = etree.Element("root") >>> root.text = "TEXT" >>> print(root.text) TEXT >>> etree.tostring(root) b'<root>TEXT</root>'
在许多XML文档中,这是文本能存放的唯一地方,文本被包裹在节点的标签中。
然而,像XHTML这样的,文本也可能出现在不同的节点之间,或者在节点的右边。
<html><body>Hello<br/>World</body></html>
像这个例子,
<br>这个标签被文本包围。 节点为了支持这个特性,使用了tail属性。 它包含的文本直接跟在节点后面,并且在下一个节点之前。下面是例子:
>>> 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 这两个属性,就可以满足任何文本插入的需要。这样,API就不需要专门的文本节点了。
然而,当你序列化一个xml时,可能并不想要tail的文本,这时,你只需要在用tostring方法时, 注意指定with_tail的值为False即可,下面是示例代码:
>>> etree.tostring(br) b'<br/>TAIL' >>> etree.tostring(br, with_tail=False) # lxml.etree only! b'<br/>'
下面有个强大的功能,如果你只想要xml中间的文本,而不要任何的标签。这个有个方法可以快速搞定。
还是tostring方法,传入method关键字为 text 即可。
>>> etree.tostring(html, method="text") b'TEXTTAIL'
比如要把word中的文本读出来,又不需要大堆的标签时。这个就派上用场了。
另一个提取文本的方法是 XPath ,并且还能把提取的文本,放入一个list中间。
>>> print(html.xpath("string()")) # lxml.etree only! TEXTTAIL >>> print(html.xpath("//text()")) # lxml.etree only! ['TEXT', 'TAIL']
如果你要经常用这个功能, 还可以把它封装成一个函数
>>> build_text_list = etree.XPath("//text()") # lxml.etree only! >>> print(build_text_list(html)) ['TEXT', 'TAIL']
通过XPath返回的对象有些聪明,它能够知道自己的来源。你可以通过getparent()方法,来知道它来自哪个节点。就像你通过节点直接查看那样。
>>> texts = build_text_list(html) >>> print(texts[0]) TEXT >>> parent = texts[0].getparent() >>> print(parent.tag) body >>> print(texts[1]) TAIL >>> print(texts[1].getparent().tag) br
你还可以知道,这个文本是普通文本,还是tail文本。
>>> print(texts[0].is_text) True >>> print(texts[1].is_text) False >>> print(texts[1].is_tail) True
While this works for the results of the text() function, lxml will not tell you the origin of a string value that was constructed by the XPath functions string() or concat():
当使用text()函数来获取文本时, 是可以获取parent的关系的。但是如果是用string()和concat方法,就不能获取这样的特性了。示例代码
#!/usr/local/python2.7/bin/python #encoding=UTF-8 from lxml import etree html = etree.Element("html") html.text= 'abc' html.tail= 'xyz' ch1 =etree.SubElement(html, "child1") ch1.text="child1" print etree.tostring(html,pretty_print=True) #string方法,无法获取getparent的信息 t = html.xpath("string()") # lxml.etree only! print t.getparent() #下面可以获取getparent的信息 t2 = html.xpath("//text()") # lxml.etree only! print t2 for a in t2: print a.getparent().tag
未完
相关文章推荐
- 如何修改系统默认字体大小
- 7------cocos2dx 3.1.1 在线热更新 自动更新(AssetsManager)
- Android Studio快捷键和使用技巧
- Notification详解
- MDD:使用模型驱动开发方式进行快速开发(多图预警)
- eq,neq,gt,lt等表达式缩写
- phpcms(1)phpcms V9 MVC模式 与 URL访问解析(转)
- 安卓第一天,配置环境变量,安装sdk
- 进入界面的时候Scrollview自动滚动
- HttpClient 的使用
- static&&final
- window下的Vim-常见配置
- ORACLE 11G 备库传备库级联传递(cascade dg) 的配置方法
- python 批量修改图片大小
- libevent学习笔记
- 分布式业务Redis安装与集群配置
- 在Mac下使用OpenCV, 在Xcode下使用OpenCV (非常基础,详细)
- Neural Networks and Deep Learning 学习笔记(七)
- Linux mail 命令参数
- JAVA Servlet API简介及接口与类的用法