Python 中解析 XML 的库有很多,例如比较常用的主要的这几个:sax、etree、minidom、pulldom、xmlrpc。这些库各有各的特点,各有取舍,例如 sax 就是不仅能够稳定处理大的xml,还兼顾解析安全,而 minidom 以 dom 的方式解析,比较符合人的思维。但是这篇文章要说的却是 etree 中的 ElementTree,既不同于 sax 也不同于 dom。
一些库的比较
xml.dom.*: 是 W3C DOM API 的实现,需要注意的一点是这个包里面包含多个处理 DOM 的模块,但是又不一致,所以使用的时候需要小心。
xml.sax.* : 是 SAX API 的实现,SAX 是以时间换空间的常见日志,SAX 是基于事件的 API,这就意味着它可以边加载边解析得处理 XML 了。
xml.parser.expat: 是一个直接的,低级一点的基于 C 的 expat 的语法分析器。 expat 接口基于事件反馈,有点像 SAX 但又不太像,因为它的接口并不是完全规范于 expat 库的。
xml.etree.ElementTree: 是一种灵活的容器对象,用于在内存中存储结构化数据。每个对象都包含 tag、attrib、text 、 tail 以及一些子元素,从而构成了一个 XML 树。
解析比较
lib | pythonic | scurity | speed | memory |
---|---|---|---|---|
minidom | B | C | B | C |
sax | C | A | C | A |
expat | C | B | B | A |
ET | A | C | A | B |
解析 XML
和很多 Python 内置库一样,ElementsTree 也有两种实现,分别是 C 实现 和 Python实现,那既然有 C实现,肯定为了效率着想,肯定优先选 C实现,然而就 API 来说都一样,都比较 pythonic。
下面来举个例子,用 ET 来解析这段 xml:
xml_content = """
<data>
<country name="Liechtenstein">
<rank>1</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E"/>
<neighbor name="Switzerland" direction="W"/>
</country>
<country name="Singapore">
<rank>4</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor name="Malaysia" direction="N"/>
</country>
<country name="Panama">
<rank>68</rank>
<year>2011</year>
<gdppc>13600</gdppc>
<neighbor name="Costa Rica" direction="W"/>
<neighbor name="Colombia" direction="E"/>
</country>
</data>
"""
因为我们优先使用 C实现,所以 import 语句可以这么写:
try:
import xml.etree.cElementTree as ET
except ImportError:
import xml.etree.ElementTree as ET
然后正文的话,我们直接写出来:
try:
import xml.etree.cElementTree as ET
except ImportError:
import xml.etree.ElementTree as ET
# 从字符串解析 xml
root = ET.fromstring(xml_content)
# 从文件解析 xml
# tree = ET.parse('country_data.xml')
# root = tree.getroot()
# 每个 ET 都包含 tag、attrib、text、tail 以及 子元素。
print "tag: {}".format(root.tag)
print "attri: {}".format(root.attrib)
print "text: {}".format(root.text)
print "tail: {}".format(root.tail)
for elm in root.getchildren():
print "\ttag: {}".format(elm.tag)
for sub in elm.getchildren():
print "\t\t{:8} = {}".format(sub.tag, sub.text)
使用这是这么简单友好。
创建 XML
很多时候不仅仅是要读取 XML,我们还需要写出 XML,这里就演示一个写出 XML 的简单例子,我们的目标写出的 XML 是这样的:
<User>
<name>tyrael</name>
<age>18</age>
</User>
那么代码可以简约得这么写:
try:
import xml.etree.cElementTree as ET
except ImportError:
import xml.etree.ElementTree as ET
# 创建一个 root 元素
root = ET.Element('User')
# 添加子元素
name = ET.SubElement(root, 'name')
name.text="tyrael"
age = ET.SubElement(root, 'age')
age.text="18"
# 输出 XML 格式
print ET.dump(root)