python xml.etree.ElementTree 学习小结

这两天看了下python对xml的解析,发现原来有这么多的方法,这么多的类库,可以做这件事情,光是看官方的xml文档,头都看大了。可是在实际的使用中,至少对我来说,性能不是最重要的,简单易用才是最重要的,于是毫无疑问xml.etree.ElementTree这个模块,最符合我的要求。

赤裸裸的复制大神的文章段落:

应该使用哪个 XML 库?

Python 有非常非常多的工具来处理 XML。在这个部分我想对 Python 所提供的包进行一个简单的浏览,并且解释为什么 ElementTree 是你最应该用的那一个。

xml.dom.* 模块 - 是 W3C DOM API 的实现。如果你有处理 DOM API 的需要,那么这个模块适合你。注意:在 xml.dom 包里面有许多模块,注意它们之间的不同。

xml.sax.* 模块 - 是 SAX API 的实现。这个模块牺牲了便捷性来换取速度和内存占用。SAX 是一个基于事件的 API,这就意味着它可以“在空中”(on the fly)处理庞大数量的的文档,不用完全加载进内存(见注释1)。

xml.parser.expat - 是一个直接的,低级一点的基于 C 的 expat 的语法分析器(见注释2)。 expat 接口基于事件反馈,有点像 SAX 但又不太像,因为它的接口并不是完全规范于 expat 库的。

最后,我们来看看 xml.etree.ElementTree (以下简称 ET)。它提供了轻量级的 Python 式的 API ,它由一个 C 实现来提供。相对于 DOM 来说,ET 快了很多(见注释3)而且有很多令人愉悦的 API 可以使用。相对于 SAX 来说,ET 也有 ET.iterparse 提供了 “在空中” 的处理方式,没有必要加载整个文档到内存。ET 的性能的平均值和 SAX 差不多,但是 API 的效率更高一点而且使用起来很方便。我一会儿会给你们看演示。

我的建议 是尽可能的使用 ET 来处理 XML ,除非你有什么非常特别的需要。

这篇文章,没什么原创的东西,主要是我看官方文档以及各个博客的简要总结,建议直接跳过文章内容,点击文章最后的参考链接。

本例中使用的xml内容如下:

cat country_data.xml

<?xml version="1.0"?>
<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>

1. 解析xml

In [53]: import xml.etree.ElementTree as ET

In [54]: tree = ET.parse('country_data.xml')

In [55]: root = tree.getroot()

In [56]: root
Out[56]: <Element 'data' at 0x111074990>

#fromstring()可以直接得到root元素
In [57]: root = ET.fromstri
ET.fromstring      ET.fromstringlist

In [57]: root = ET.fromstring(open('country'))
country           country_data.xml

In [57]: root = ET.fromstring(open('country_data.xml').read())

In [58]: root
Out[58]: <Element data' at 0x111074f90>

#作为Element类型,取root的标签和属性
In [59]: root.tag
Out[59]: 'data'

In [60]: root.attrib
Out[60]: {}

#迭代root的子元素
In [61]: for child in root:
   ....:     print child.tag,child.attrib
   ....:
country {'name': 'Liechtenstein'}
country {'name': 'Singapore'}
country {'name': 'Panama'}

#可以使用索引访问root的子元素
In [62]: root[0][1].text
Out[62]: '2008'

In [63]:

2.找到感兴趣的元素

#iter()函数可以迭代所有标签为neighbor的元素
In [63]: for neighbor in root.iter('neighbor'):
   ....:     print neighbor.attrib
   ....:
{'direction': 'E', 'name': 'Austria'}
{'direction': 'W', 'name': 'Switzerland'}
{'direction': 'N', 'name': 'Malaysia'}
{'direction': 'W', 'name': 'Costa Rica'}
{'direction': 'E', 'name': 'Colombia'}

#findall()只可以迭代root的子元素,不可以迭代孙元素;find()是找到第一个标签为rank的元素
In [64]: for country in root.findall('country'):
   ....:     rank = country.find('rank').text
   ....:     name = country.get('name')
   ....:     print name,rank
   ....:
Liechtenstein 1
Singapore 4
Panama 68

In [65]:

3. 修改xml

#把每个rank的值加1,增加一个updated属性
In [69]: for rank in root.iter('rank'):
   ....:     new_rank = int(rank.text) + 1
   ....:     rank.text = str(new_rank)
   ....:     rank.set('updated','yes')
   ....:

In [70]: tree.write(output.xml')

生成的xml是这个样子

<data>
    <country name="Liechtenstein">
        <rank updated="yes">2</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor direction="E" name="Austria" />
        <neighbor direction="W" name="Switzerland" />
    </country>
    <country name="Singapore">
        <rank updated="yes">5</rank>
        <year>2011</year>
        <gdppc>59900</gdppc>
        <neighbor direction="N" name="Malaysia" />
    </country>
    <country name="Panama">
        <rank updated="yes">69</rank>
        <year>2011</year>
        <gdppc>13600</gdppc>
        <neighbor direction="W" name="Costa Rica" />
        <neighbor direction="E" name="Colombia" />
    </country>
</data>
#删除子元素rank值大于50的country
In [75]: for country in root.findall('country'):
   ....:     rank = int(country.find('rank').text)
   ....:     if rank > 50:
   ....:         root.remove(country)
   ....:

In [76]: tree.write('output.xml')

In [77]:

生成的xml是这个样子

<data>
    <country name="Liechtenstein">
        <rank updated="yes">2</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor direction="E" name="Austria" />
        <neighbor direction="W" name="Switzerland" />
    </country>
    <country name="Singapore">
        <rank updated="yes">5</rank>
        <year>2011</year>
        <gdppc>59900</gdppc>
        <neighbor direction="N" name="Malaysia" />
    </country>
</data>

4.构建一个xml文档

#SubElement()函数可以方便的生成给定元素的一个子元素
In [77]: a = ET.Element('a')

In [78]: b = ET.SubElement(a, 'b')

In [79]: c = ET.SubElement(a, 'c')

In [80]: d = ET.SubElement(c, 'd')

In [81]:  ET.dump(a)
<a><b /><c><d /></c></a>

In [82]:

官网剩下的内容一直在讲对XPath的支持,实在是不感兴趣,跳过。

恩,就这样了,对,就这样了。


参考资料:

xml.etree.ElementTree:https://docs.python.org/2/library/xml.etree.elementtree.html

深入 Python 3 : http://dipyzh.bitbucket.org/xml.html

python xml解析:https://gist.github.com/ronaldhan/77531c9d2cc3c0ee1b93

python对XML的解析:http://blog.csdn.net/yueguanghaidao/article/details/7265246

Python XML解析:http://www.runoob.com/python/python-xml.html

用 ElementTree 在 Python 中解析 XML:http://pycoders-weekly-chinese.readthedocs.io/en/latest/issue6/processing-xml-in-python-with-element-tree.html

深入解读Python解析XML的几种方式:http://codingpy.com/article/parsing-xml-using-python/