Python 中解析 XML 的库有很多,例如比较常用的主要的这几个:sax、etree、minidom、pulldom、xmlrpc。这些库各有各的特点,各有取舍,例如 sax 就是不仅能够稳定处理大的xml,还兼顾解析安全,而 minidom 以 dom 的方式解析,比较符合人的思维。但是这篇文章要说的却是 etree 中的 ElementTree,既不同于 sax 也不同于 dom。


一些库的比较

解析比较

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)


Reference