xml
xml 在软件领域用途非常广泛,有名人曰:
对于 xml 如果要做一个定义式的说明,就不得不引用 w3school 里面简洁而明快的说明:
如果读者要详细了解和学习有关 xml,可以阅读w3school的教程 xml 的重要,关键在于它是用来传输数据,因为传输数据,特别是在 web 编程中,经常要用到的。有了这样一种东西,就让数据传输变得简单了。对于这么重要的,Python 当然有支持。 一般来讲,一个引人关注的东西,总会有很多人从不同侧面去关注。在编程语言中也是如此,所以,对 xml 这个明星式的东西,Python 提供了多种模块来处理。
所以,我用 xml.etree.ElementTree ElementTree 在标准库中有两种实现。一种是纯 Python 实现:xml.etree.ElementTree ,另外一种是速度快一点:xml.etree.cElementTree 。 如果读者使用的是 Python2.x,可以像这样引入模块: try: import xml.etree.cElementTree as ET except ImportError: import xml.etree.ElementTree as ET 如果是 Python3.3 以上,就没有这个必要了,只需要一句话 遍历查询先要搞一个 xml 文档。为了图省事,我就用 w3school 中的一个例子: 这是一个 xml 树,只不过是用图来表示的,还没有用 ET 解析呢。把这棵树写成 xml 文档格式: <bookstore> <book category="COOKING"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price>30.00</price> </book> <book category="CHILDREN"> <title lang="en">Harry Potter</title> <author>J K. Rowling</author> <year>2005</year> <price>29.99</price> </book> <book category="WEB"> <title lang="en">Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price>39.95</price> </book> </bookstore> 将 xml 保存为名为 22601.xml 的文件,然后对其进行如下操作: >>> import xml.etree.cElementTree as ET 为了简化,我用这种方式引入,如果在编程实践中,推荐读者使用 try...except...方式。 >>> tree = ET.ElementTree(file="22601.xml") >>> tree <ElementTree object at 0xb724cc2c> 建立起 xml 解析树。然后可以通过根节点向下开始读取各个元素(element 对象)。 在上述 xml 文档中,根元素是
>>> root = tree.getroot() #获得根 >>> root.tag 'bookstore' >>> root.attrib {} 要想将根下面的元素都读出来,可以: >>> for child in root: ... print child.tag,child.attrib ... book {'category': 'COOKING'} book {'category': 'CHILDREN'} book {'category': 'WEB'} 也可以这样读取指定元素的信息: >>> root[0].tag 'book' >>> root[0].attrib {'category': 'COOKING'} >>> root[0].text #无内容 'n ' 再深点,就有感觉了: >>> root[0][0].tag 'title' >>> root[0][0].attrib {'lang': 'en'} >>> root[0][0].text 'Everyday Italian' 对于 ElementTree 对象,有一个 iter 方法可以对指定名称的子节点进行深度优先遍历。例如: >>> for ele in tree.iter(tag="book"): #遍历名称为 book 的节点 ... print ele.tag,ele.attrib ... book {'category': 'COOKING'} book {'category': 'CHILDREN'} book {'category': 'WEB'} >>> for ele in tree.iter(tag="title"): #遍历名称为 title 的节点 ... print ele.tag,ele.attrib,ele.text ... title {'lang': 'en'} Everyday Italian title {'lang': 'en'} Harry Potter title {'lang': 'en'} Learning XML 如果不指定元素名称,就是将所有的元素遍历一边。 >>> for ele in tree.iter(): ... print ele.tag,ele.attrib ... bookstore {} book {'category': 'COOKING'} title {'lang': 'en'} author {} year {} price {} book {'category': 'CHILDREN'} title {'lang': 'en'} author {} year {} price {} book {'category': 'WEB'} title {'lang': 'en'} author {} year {} price {} 除了上面的方法,还可以通过路径,搜索到指定的元素,读取其内容。这就是 xpath。此处对 xpath 不详解,如果要了解可以到网上搜索有关信息。 >>> for ele in tree.iterfind("book/title"): ... print ele.text ... Everyday Italian Harry Potter Learning XML 利用 findall() 方法,也可以是实现查找功能: >>> for ele in tree.findall("book"): ... title = ele.find('title').text ... price = ele.find('price').text ... lang = ele.find('title').attrib ... print title,price,lang ... Everyday Italian 30.00 {'lang': 'en'} Harry Potter 29.99 {'lang': 'en'} Learning XML 39.95 {'lang': 'en'} 编辑除了读取有关数据之外,还能对 xml 进行编辑,即增删改查功能。还是以上面的 xml 文档为例: >>> root[1].tag 'book' >>> del root[1] >>> for ele in root: ... print ele.tag ... book book 如此,成功删除了一个节点。原来有三个 book 节点,现在就还剩两个了。打开源文件再看看,是不是正好少了第二个节点呢?一定很让你失望,源文件居然没有变化。 的确如此,源文件没有变化,这就对了。因为至此的修改动作,还是停留在内存中,还没有将修改结果输出到文件。不要忘记,我们是在内存中建立的 ElementTree 对象。再这样做: >>> import os >>> outpath = os.getcwd() >>> file = outpath + "/22601.xml" 把当前文件路径拼装好。然后: >>> tree.write(file) 再看源文件,已经变成两个节点了。 除了删除,也能够修改: >>> for price in root.iter("price"): #原来每本书的价格 ... print price.text ... 30.00 39.95 >>> for price in root.iter("price"): #每本上涨 7 元,并且增加属性标记 ... new_price = float(price.text) + 7 ... price.text = str(new_price) ... price.set("updated","up") ... >>> tree.write(file) 查看源文件: <bookstore> <book category="COOKING"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price updated="up">37.0</price> </book> <book category="WEB"> <title lang="en">Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price updated="up">46.95</price> </book> </bookstore> 不仅价格修改了,而且在 price 标签里面增加了属性标记。干得不错。 上面用 >>> for book in root.findall("book"): ... price = book.find("price").text ... if float(price) > 40.0: ... root.remove(book) ... >>> tree.write(file) 于是就这样了: <bookstore> <book category="COOKING"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price updated="up">37.0</price> </book> </bookstore> 接下来就要增加元素了。 >>> import xml.etree.cElementTree as ET >>> tree = ET.ElementTree(file="22601.xml") >>> root = tree.getroot() >>> ET.SubElement(root,"book") #在 root 里面添加 book 节点 <Element 'book' at 0xb71c7578> >>> for ele in root: ... print ele.tag ... book book >>> b2 = root[1] #得到新增的 book 节点 >>> b2.text = "Python" #添加内容 >>> tree.write("22601.xml") 查看源文件: <bookstore> <book category="COOKING"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price updated="up">37.0</price> </book> <book>python</book> </bookstore> 常用属性和方法总结ET 里面的属性和方法不少,这里列出常用的,供使用中备查。 Element 对象 常用属性:
针对属性的操作
针对后代的操作
ElementTree 对象
一个实例最后,提供一个参考,这是一篇来自网络的文章:Python xml 属性、节点、文本的增删改,本文的源码我也复制到下面,请读者参考:
#!/usr/bin/Python # -*- coding=utf-8 -*- # author : wklken@yeah.net # date: 2012-05-25 # version: 0.1 from xml.etree.ElementTree import ElementTree,Element def read_xml(in_path): ''' 读取并解析 xml 文件 in_path: xml 路径 return: ElementTree ''' tree = ElementTree() tree.parse(in_path) return tree def write_xml(tree,out_path): ''' 将 xml 文件写出 tree: xml 树 out_path: 写出路径 ''' tree.write(out_path,encoding="utf-8",xml_declaration=True) def if_match(node,kv_map): ''' 判断某个节点是否包含所有传入参数属性 node: 节点 kv_map: 属性及属性值组成的 map ''' for key in kv_map: if node.get(key) != kv_map.get(key): return False return True #---------------search ----- def find_nodes(tree,path): ''' 查找某个路径匹配的所有节点 tree: xml 树 path: 节点路径 ''' return tree.findall(path) def get_node_by_keyvalue(nodelist,kv_map): ''' 根据属性及属性值定位符合的节点,返回节点 nodelist: 节点列表 kv_map: 匹配属性及属性值 map ''' result_nodes = [] for node in nodelist: if if_match(node,kv_map): result_nodes.append(node) return result_nodes #---------------change ----- def change_node_properties(nodelist,kv_map,is_delete=False): ''' 修改/增加 /删除 节点的属性及属性值 nodelist: 节点列表 kv_map:属性及属性值 map ''' for node in nodelist: for key in kv_map: if is_delete: if key in node.attrib: del node.attrib[key] else: node.set(key,kv_map.get(key)) def change_node_text(nodelist,text,is_add=False,is_delete=False): ''' 改变/增加/删除一个节点的文本 nodelist:节点列表 text : 更新后的文本 ''' for node in nodelist: if is_add: node.text += text elif is_delete: node.text = "" else: node.text = text def create_node(tag,property_map,content): ''' 新造一个节点 tag:节点标签 property_map:属性及属性值 map content: 节点闭合标签里的文本内容 return 新节点 ''' element = Element(tag,property_map) element.text = content return element def add_child_node(nodelist,element): ''' 给一个节点添加子节点 nodelist: 节点列表 element: 子节点 ''' for node in nodelist: node.append(element) def del_node_by_tagkeyvalue(nodelist,tag,kv_map): ''' 同过属性及属性值定位一个节点,并删除之 nodelist: 父节点列表 tag:子节点标签 kv_map: 属性及属性值列表 ''' for parent_node in nodelist: children = parent_node.getchildren() for child in children: if child.tag == tag and if_match(child,kv_map): parent_node.remove(child) if __name__ == "__main__": #1. 读取 xml 文件 tree = read_xml("./test.xml") #2. 属性修改 #A. 找到父节点 nodes = find_nodes(tree,"processers/processer") #B. 通过属性准确定位子节点 result_nodes = get_node_by_keyvalue(nodes,{"name":"BProcesser"}) #C. 修改节点属性 change_node_properties(result_nodes,{"age": "1"}) #D. 删除节点属性 change_node_properties(result_nodes,{"value":""},True) #3. 节点修改 #A.新建节点 a = create_node("person",{"age":"15","money":"200000"},"this is the firest content") #B.插入到父节点之下 add_child_node(result_nodes,a) #4. 删除节点 #定位父节点 del_parent_nodes = find_nodes(tree,"processers/services/service") #准确定位子节点并删除之 target_del_node = del_node_by_tagkeyvalue(del_parent_nodes,"chain",{"sequency" : "chain1"}) #5. 修改节点文本 #定位节点 text_nodes = get_node_by_keyvalue(find_nodes(tree,"processers/services/service/chain"),{"sequency":"chain3"}) change_node_text(text_nodes,"new text") #6. 输出到结果文件 write_xml(tree,"./out.xml") 操作对象(原始 xml 文件): <?xml version="1.0" encoding="UTF-8"?> <framework> <processers> <processer name="AProcesser" file="lib64/A.so" path="/tmp"> </processer> <processer name="BProcesser" file="lib64/B.so" value="fordelete"> </processer> <processer name="BProcesser" file="lib64/B.so2222222"/> <services> <service name="search" prefix="/bin/search?" output_formatter="OutPutFormatter:service_inc"> <chain sequency="chain1"/> <chain sequency="chain2"></chain> </service> <service name="update" prefix="/bin/update?"> <chain sequency="chain3" value="fordelete"/> </service> </services> </processers> </framework> 执行程序之后,得到的结果文件: <?xml version='1.0' encoding='utf-8'?> <framework> <processers> <processer file="lib64/A.so" name="AProcesser" path="/tmp"> </processer> <processer age="1" file="lib64/B.so" name="BProcesser"> <person age="15" money="200000">this is the firest content</person> </processer> <processer age="1" file="lib64/B.so2222222" name="BProcesser"> <person age="15" money="200000">this is the firest content</person> </processer> <services> <service name="search" output_formatter="OutPutFormatter:service_inc" prefix="/bin/search?"> <chain sequency="chain2" /> </service> <service name="update" prefix="/bin/update?"> <chain sequency="chain3" value="fordelete">new text</chain> </service> </services> </processers> </framework> 总目录???|???上节:标准库(6)???|???下节:标准库(8) 如果你认为有必要打赏我,请通过支付宝:qiwsir@126.com,不胜感激。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |