使用Python解析XML

XML是可拓展标记语言,用来传输和储存数据

解析XML的三种方法

常见的XML编程接口有DOM和SAX,Python有三种方法解析XML:SAX, DOM,ElementTree。

  • SAX means simple API for XML:
    python标准库包含SAX解析器,用事件驱动模型,通过在解析XML过程中触发一个个事件并调用用户定义的回调函数来处理XML文件。
  • DOM
    将XML数据在内存中解析成一个树,通过对树的操作来操作XML
  • ElementTree:
    就像一个轻量级的DOM,具有很好的API,代码可用性好,速度快,消耗的内存小

!!!这里我们首选使用xml.etree.ElementTree模块


使用ElementTree解析XML:

xml.etree.ElementTree模块提供了一个轻量级API,与DOM相比,ET的速度更快,API使用更直接方便。与SAX相比,ET.iterparse函数同样提供了按需解析的功能,不会一次性在内存中读入整个文档。ET的性能与SAX模块大致相仿,但是它的API更加高层次,用户使用起来更加便捷。

在标准库中提供了对ET的两种实现,一种是纯python版本,一种是c语言实现的版本,这里使用c语言版本更好,因为它的速度更快,消耗内存更少,所以这样导入模块:

try:
    import xml.etree.cElementTree as ET
except ImportError:
    import xml.etree.ElementTree as ET

Python3.3之后,不需要这样导入,因为ET模块会自动优先使用C加速器

将XML文档解析成树:
!!!这里有两种对象,一个为ElementTree对象,另一个为Element对象
XML文档例子:

<?xml version="1.0"?>
<doc>
    <branch name="codingpy.com" hash="1cdf045c">
        text,source
    </branch>
    <branch name="release01" hash="f200013e">
        <sub-branch name="subrelease01">
            xml,sgml
        </sub-branch>
    </branch>
    <branch name="invalid">
    </branch>
</doc>

加载这个文档并且解析:

>>> import xml.etree.ElementTree as ET
>>> tree = ET.ElementTree(file='doc1.xml')  # 加载这个文档并且解析,赋值为tree
---------------------------
>>> tree.getroot()  # 获取这个树的根元素
<Element 'doc' at 0x11eb780>
---------------------------
>>> root = tree.getroot()
>>> root.tag, root.attrib  # 查看这个根元素的属性,根元素为一个Element对象
('doc', {})  # 根元素并没有属性
---------------------------
>>> for child_of_root in root:  # 根元素具备遍历其直接子元素的接口
...   print child_of_root.tag, child_of_root.attrib  # .tag就是标签名
...
branch {'hash': '1cdf045c', 'name': 'codingpy.com'}
branch {'hash': 'f200013e', 'name': 'release01'}
branch {'name': 'invalid'}
---------------------------
>>> root[0].tag, root[0].text  # 也可以通过索引值来访问特定的子元素
('branch', '\n        text,source\n    ')

查找元素:
ElementElementTree对象都有iter方法,可以对对象之下的所有子元素进行深度优先遍历DFS,所以这里最简单的办法是:

>>> for elem in tree.iter():
...   print elem.tag, elem.attrib
...
doc {}
branch {'hash': '1cdf045c', 'name': 'codingpy.com'}
branch {'hash': 'f200013e', 'name': 'release01'}
sub-branch {'name': 'subrelease01'}  # 这个是上面一条的子元素,所以这是深度优先遍历
branch {'name': 'invalid'}

这个方法还能接受tag参数,然后遍历标签为这个tag的元素:

>>> for elem in tree.iter(tag='branch'):
...   print elem.tag, elem.attrib

使用XPath查找元素更加方便:
Element对象中有一些find方法可以接受Xpath路径作为参数,find方法会返回第一个匹配的子元素,findall会以列表的形式返回所有匹配的子元素,iterfind则返回一个所有匹配元素的迭代器。
ElementTree也有上述方法,查找就是从根节点开始的。

>>> for elem in tree.iterfind('branch/sub-branch'):
...   print elem.tag, elem.attrib
...
sub-branch {'name': 'subrelease01'}

上面是根据路径查找
下面是查找所有具备某个name属性的元素:

>>> for elem in tree.iterfind('branch[@name="release01"]'):
...   print elem.tag, elem.attrib
...
branch {'hash': 'f200013e', 'name': 'release01'}

修改或者创建XML文档:
修改文档可以通过调整Element对象来完成:

>>> root = tree.getroot()
>>> del root[2]   # 相当于删除了元素
>>> root[0].set('foo', 'bar')  # 相当于增加了新的属性
>>> for subelem in root:
...   print subelem.tag, subelem.attrib
...
branch {'foo': 'bar', 'hash': '1cdf045c', 'name': 'codingpy.com'}
branch {'hash': 'f200013e', 'name': 'release01'}

创建XML文档使用SubElement工厂函数:

>>> a = ET.Element('elem')
>>> c = ET.SubElement(a, 'child1')
>>> c.text = "some text"
>>> d = ET.SubElement(a, 'child2')
>>> b = ET.Element('elem_b')
>>> root = ET.Element('root')
>>> root.extend((a, b))
>>> tree = ET.ElementTree(root)
>>> tree.write(sys.stdout)
<root><elem><child1>some text</child1><child2 /></elem><elem_b /></root>


使用iterparse解析XML:

因为ET是将文档加载成树保存到内存里面,所以一旦XML很大,也会遇到内存消耗太大的问题,这里需要用到ET里面类似SAX的特殊工具iterparse,它可以循序的解析XML。

这里只是介绍有这么个东西,暂时不介绍如何使用,笔者用到了再更新~

猜你喜欢

转载自blog.csdn.net/qq_43355223/article/details/83899467