ElementTree XML 模块用来处理 XML 格式文档。包括读取、解析、修改、生成等等。 xml.etree.ElementTree 库里主要使用的是两个类: ElementTree 是对整个文档树(document tree)的抽象,操作文件、文档时需要。比如读取、写入、查找。 Element 是对文档中单个节点(document node)的抽象,操作单个节点时需要。比如修改属性、查找子节点。 读入 xml 文件 有两种途径,各自得到不同的结果。 返回 xml 树 使用库函数: xml.etree.ElementTree 库内的 parse() 函数。 返回的是一个 ElementTree 树对象 >>> from xml.etree.ElementTree import parse >>> parse('a.xml') >>> 如果想得到树的根节点,还需要使用 getroot() 函数: >>> from xml.etree.ElementTree import parse >>> parse('a.xml').getroot() >>> 返回 xml 根节点 使用类方法: xml.etree.ElementTree 库内的 ElementTree 类的实例方法。 可以读入文件名或者文件对象。 例子:从文件名读入: >>> from xml.etree.ElementTree import ElementTree >>> ElementTree().parse('a.xml') 可以看出,返回的是 Element 对象,这个对象是文档树的根。 例子:从文件对象读入 >>> with open('a.xml','r') as x: ... ElementTree().parse(x) ... >>> 从字符串读入 使用库函数: xml.etree.ElementTree 库内的 fromstring() 函数。 >>> import xml.etree.ElementTree as ET >>> ET.fromstring('') >>> 返回根节点。 输出字符串 使用类方法:xml.etree.ElementTree 库内的 dump() 和 tostring()函数。 dump() 向标准输出打印出字符串,函数不返回字符串,仅用于调试。参数是节点对象 Element。 >>> import xml.etree.ElementTree as ET >>> t=ET.fromstring('1') >>> ET.dump(t) 1 >>> tostring() 用来返回格式化后的 xml字符串,参数列表有: tostring(element, encoding='us-ascii', method='xml', * xml_declaration=None, default_namespace=None, short_empty_elements=True) 参数中,element 是个 Element 节点对象。例子: >>> import xml.etree.ElementTree as ET >>> t=ET.fromstring('1') >>> s=ET.tostring(t) >>> s b'1' >>> 得到字符串后,就可以编写代码输出到文件。 encoding 参数指定编码,默认是 ascii 的字节编码。如果要输出 UTF-8 编码,可以赋值:“unicode”。例子: >>> import xml.etree.ElementTree as ET >>> t=ET.fromstring('1') >>> s=ET.tostring(t, encoding="unicode") >>> s '1' >>> xml_declaration 参数控制是否同时输出xml 格式声明。例子: >>> import xml.etree.ElementTree as ET >>> t=ET.fromstring('1') >>> s=ET.tostring(t, encoding="unicode", xml_declaration=True) >>> s "\n1" >>> s=ET.tostring(t, xml_declaration=True) >>> s b"\n1" >>> 或者直接使用 XML 树对象自带的方法:write(),在下节介绍。 写入 xml 文件 函数的参数有: write(file, encoding='us-ascii', xml_declaration=None, default_namespace=None, method='xml', *, short_empty_elements=True) file: 和 读入 xml 文件 一样,可以提供文件名或者文件对象。 其他参数和 tostring() 相同。 处理 xml 命名空间 声明命名空间的方法是声明一个 prefix 到 uri 的映射: xmlns:prefix=uri 这里 prefix 是个临时替代字符串,用于替换 uri。解析 xml 时,所有tag 前面的 prefix 会被自动替换为 uri 如果没有 prefix,而采用下面形式 xmlns:uri 就是默认命名空间,default namespace,所有没有 prefix 的前缀会被自动替换为 uri 如果原始的 xml 声明了命名空间,在解析的时候会自动将扩展tag。 借用 这里的例子 说明命名空间的处理。 下面一个 xml 文件里,同时声明了 html 类型的 table 和家具类型的 table, 然后用命名空间区分。 Apples Bananas African Coffee Table 80 120 上面文件的例子中,default namespace 声明为 nothing,另外声明了两种 namespace 分别为: h="html" 和 f="furniture" 所有 h: 开头的tag都会被替换为 html:,比如h:table会被替换为html:table。同样道理,f:table会被替换为furniture:table。而没有前缀的则会添加 default namespace 的值。 扩展版本的 xml如下: Apples Bananas African Coffee Table 80 120 因为 prefix 是中间临时替代品,所以更改 prefix 并不会影响最终扩展出的xml。经过 ElementTree.parse() 后会统一替换 prefix 为统一编号的 ns,从ns0、ns1…… >>> import xml.etree.ElementTree as ET >>> a=ET.ElementTree() >>> a.parse('a.xml') >>> ET.dump(a.getroot()) Apples Bananas African Coffee Table 80 120 当我们查看元素 tag 的名称时,会看到放置在大括号中的 uri: >>> r=a.getroot() >>> r.tag '{nothing}root' 当用 find() 寻找子元素时,需要提供扩展版的 tag 名称, 如下例子: >>> r.find('{html}table') 这样并不方便,应该使用 find() 函数的第二个参数:ns,来指定命名空间,形式是从 prefix 到 uri 的映射。比如: >>> r.find('h:table', {'h':'html'}) 格式化 默认情况下,tostring() 和 write() 的结果将保留原始文件的缩进格式,不会对空行、缩进做统一的格式化。 比如:如果原文件是这样: ApplesBananas African Coffee Table80120 那么经 ElementTree.parse() 处理后再输出是这样: >>> import xml.etree.ElementTree as ET >>> a=ET.ElementTree() >>> a.parse('a.xml') >>> ET.dump(a.getroot()) ApplesBananas African Coffee Table80120 >>> 如果想得到如下的两种格式化,就要使用 ElementTree.indent() 函数,这个函数将整棵 xml 文档树重新整理,参数就是文档树的对象 ElementTree。还是上面的例子: >>> import xml.etree.ElementTree as ET >>> a=ET.ElementTree() >>> a.parse('a.xml') >>> ET.indent(a) >>> ET.dump(a.getroot()) Apples Bananas African Coffee Table 80 120 >>> indent() 做了两件事情: 每个节点独占一行 每一级节点增加一级缩进