4. 实例 实例1:生成XML数据
生成上面表示植物列表XML数据:
import xml.etree.ElementTree as ET # 创建root element catalog = ET.Element("CATALOG") # 直接通过SubElement类为root element添加一个子元素 plant01 = ET.SubElement(catalog, "PLANT", attrib={"id": "001"}) name01 = ET.SubElement(plant01, "NAME") name01.text = "Sanguinaria canadensis" light01 = ET.SubElement(plant01, "LIGHT") light01.text = "Mostly Shady" # 通过Element.append()方法为root element添加一个子元素 plant02 = ET.Element("PLANT", id="002") name02 = ET.Element("NAME") name02.text = "Aquilegia canadensis" light02 = ET.Element("LIGHT") light02.text = "Mostly Shady" plant02.append(name02) plant02.append(light02) catalog.append(plant02) # 通过SubElement类和Element.append()方法为root element添加一个子元素 plant03 = ET.Element("PLANT", id="003") name03 = ET.SubElement(plant03, "NAME") name03.text = "Phlox divaricata" light03 = ET.SubElement(plant03, "LIGHT") light03.text = "Sun or Shade" catalog.append(plant03) # 以指定的root element创建一个ElementTree实例 et = ET.ElementTree(element=catalog) # 将创建的ElementTree对应的XML数据写入(序列化)到本地文件 et.write("plants.xml", encoding="utf-8", xml_declaration=True)此时会在当前目录生成一个名为"plants.xml"的文件,内容和上面表示植物列表的XML数据一致。另外,通过上面的实例可知,使用SubElement创建和添加子元素是最方便的。
<?xml version='1.0' encoding='utf-8'?> <CATALOG> <PLANT id="001"> <NAME>Sanguinaria canadensis</NAME> <LIGHT>Mostly Shady</LIGHT> </PLANT> <PLANT id="002"> <NAME>Aquilegia canadensis</NAME> <LIGHT>Mostly Shady</LIGHT> </PLANT> <PLANT id="003"> <NAME>Phlox divaricata</NAME> <LIGHT>Sun or Shade</LIGHT> </PLANT> </CATALOG> 实例2:解析XML数据解析上面生成的XML数据
import xml.etree.ElementTree as ET # 由以下两种方式可以从一个包含XML数据的文件创建一个ElementTree实例 # et = ET.ElementTree(file="plants.xml") et = ET.parse("plants.xml") # 获取root element elem01 = et.getroot() print(elem01.tag) # CATALOG # 获取第一个标签为"PLANT"的“直接” subelement elem02 = et.find("PLANT") print(elem02.tag) print(elem02.attrib) print(elem02.items()) print(elem02.keys()) print(elem02.get("id")) # 遍历指定element的所有subelement for e in elem02: ET.dump(e) # 获取所有标签为"PLANT"的“直接” subelement for e in et.findall("PLANT"): print(ET.tostring(e, encoding="unicode")) print(e.items()) # 遍历XML中所有的element for e in et.iter(): print(ET.tostring(e))输出结果为:
CATALOG PLANT {'id': '001'} [('id', '001')] ['id'] 001 <NAME>Sanguinaria canadensis</NAME> <LIGHT>Mostly Shady</LIGHT> <PLANT id="001"><NAME>Sanguinaria canadensis</NAME><LIGHT>Mostly Shady</LIGHT></PLANT> [('id', '001')] <PLANT id="002"><NAME>Aquilegia canadensis</NAME><LIGHT>Mostly Shady</LIGHT></PLANT> [('id', '002')] <PLANT id="003"><NAME>Phlox divaricata</NAME><LIGHT>Sun or Shade</LIGHT></PLANT> [('id', '003')] <CATALOG><PLANT id="001"><NAME>Sanguinaria canadensis</NAME><LIGHT>Mostly Shady</LIGHT></PLANT><PLANT id="002"><NAME>Aquilegia canadensis</NAME><LIGHT>Mostly Shady</LIGHT></PLANT><PLANT id="003"><NAME>Phlox divaricata</NAME><LIGHT>Sun or Shade</LIGHT></PLANT></CATALOG> <PLANT id="001"><NAME>Sanguinaria canadensis</NAME><LIGHT>Mostly Shady</LIGHT></PLANT> <NAME>Sanguinaria canadensis</NAME> <LIGHT>Mostly Shady</LIGHT> <PLANT id="002"><NAME>Aquilegia canadensis</NAME><LIGHT>Mostly Shady</LIGHT></PLANT> <NAME>Aquilegia canadensis</NAME> <LIGHT>Mostly Shady</LIGHT> <PLANT id="003"><NAME>Phlox divaricata</NAME><LIGHT>Sun or Shade</LIGHT></PLANT> <NAME>Phlox divaricata</NAME> <LIGHT>Sun or Shade</LIGHT> 实例3:修改与删除XML数据 import xml.etree.ElementTree as ET # 从plants.xml文件初始化一个ElementTree实例 et = ET.parse("plants.xml") # 获取第一个标签为PLANT的element elem = et.find("PLANT") print(ET.tostring(elem, encoding="unicode")) # 为这个element设置一个新的标签属性 elem.set("color", "red") print(ET.tostring(elem, encoding="unicode")) # 清空这个element的所有属性、文本和 subelement elem.clear() print(ET.tostring(elem, encoding="unicode")) print(ET.tostring(elem, encoding="unicode", short_empty_elements=False)) namelist = ET.Element("NameList") name = ET.SubElement(namelist, "name", attrib={"name": "Tom"}) age = ET.SubElement(name, "age") age.text = '22' role = ET.SubElement(name, "role") role.text = 'cat' name = ET.SubElement(namelist, "name", attrib={"name": "Jerry"}) age = ET.SubElement(name, "age") age.text = '20' role = ET.SubElement(name, "role") role.text = 'mouse' # 替换整个XML属性结构的内容为一个名字列表 et._setroot(namelist) print(ET.tostring(namelist, encoding="unicode")) # 将修改过的ElementTree实例以XML的形式序列化到新的文件中 et.write("name_list.xml", encoding="utf-8", xml_declaration=True)输出结果为:
<PLANT id="001"><NAME>Sanguinaria canadensis</NAME><LIGHT>Mostly Shady</LIGHT></PLANT> <PLANT color="red" id="001"><NAME>Sanguinaria canadensis</NAME><LIGHT>Mostly Shady</LIGHT></PLANT> <PLANT /> <PLANT></PLANT> <NameList><name name="Tom"><age>22</age><role>cat</role></name><name name="Jerry"><age>20</age><role>mouse</role></name></NameList>同时,会在当前目录下生成一个新的名为"name_list.xml"的文件:
<?xml version='1.0' encoding='utf-8'?> <NameList> <name name="Tom"> <age>22</age> <role>cat</role> </name> <name name="Jerry"> <age>20</age> <role>mouse</role> </name> </NameList> 5. 补充说明需要说明的是,Python中用于处理和操作XML数据的模块不仅仅是这里介绍的xml.etree.ElementTree模块,下面这张图是Python 3.5.2中xml包(package)下的所有模块。
Python处理XML数据的4种方法总体来讲,这些模块对应的是对XML进行操作的种中方法:
DOM: DOM解析器在进行任何处理之前,必须把XML文件生成的树形结构数据一次性完全放到内存中,所以DOM解析器的内存使用量完全是由要处理的XML数据的大小决定的。
SAX: SAX是Simple API for XML的缩写,它牺牲了便捷性来获取内存占用量的降低。它是事件驱动的,并需要一次性读入整个XML文档,文档的读入过程就是SAX的解析过程。所谓事件驱动,是指一种基于回调机制的程序运行方法,通常我们需要提前写好相应的处理函数等待被回调(比如,当读取到一个开始标签时、读取到一个结束标签时,这些都是一种事件)。
Expat: expat接口与SAX类似,也是基于事件回调机制,但是该接口并不是标准化的,只适用于expat库。
ElementTree: ElementTree是一个轻量级的DOM实现,它提供了Pythonic的API,同时还有一个高效的C语言实现,即 xml.etree.cElementTree。但是从Python 3.3开始cElementTree模块已经被废弃了,从官方文档上的说明来看,应该是与ElementTree合并了,解释器会在尽可能多的情况下自动启动更高效的处理方式。
以上几种方式的对比与DOM相比,ET的速度更快,API使用也更直观、便捷。
与SAX相比,ET.iterparse()函数同样提供了按需解析XML数据的功能,而可以不用一次性在内存中读入整个文档。ET的性能与SAX模块大致相仿,但是它的API抽象层次更高,使用更加方便。
可见,ET与SAX和DOM相比更加有优势,因此我们推荐使用ET处理XML数据。当然,如果在某种特定的情况下需要使用其它API也是可以的。
注意: 解析XML的这几种API并不是Python独创的,Python是通过借鉴其它语言或直接从其它语言引入进来的。例如expat就是一个用C语言开发的、用来解析XML文档的开发库;SAX最初是由DavidMegginson使用java语言开发的;而DOM可以以一种独立于平台和语言的方式访问和修改一个文档的内容和结构,也就是说它可以应用于任何编程语言。