python3 xml;python ElementTree;cElementTree;

ElementTree

注意,ET在解析是将xml以tree的形式加载到内存中(in-memory tree),在进行处理,因此存在内存消耗的问题。为了解决这个问题,ET提供了类似SAX的工具iterparse。使用方法参考博客园 - python3解析XML的5、利用iterparse解析XML流。

1. 官方文档和相关教程

https://docs.python.org/3/library/xml.etree.elementtree.html
https://www.runoob.com/python/python-xml.html

2. 导入

ElementTree是python内置的包,cElementTree是用C语言实现的,速度更快,占用内存更小,因此优先使用cElementTree

  1. # python3.3+版本的ElemenTree直接导入ElementTree会自动优先选C语言。
  2. import xml.etree.ElementTree as ET
  3. # python3.3之前可以使用下面方法导入ElementTree
  4. try:
  5. import xml.etree.cElementTree as ET
  6. except ImportError:
  7. import xml.etree.ElementTree as ET

3. 使用(挖坑)

有空自己整理一个example,结合下面复制过的就够了。
这里以下面的xml文档讲解ElementTree的增删改查,主要参考:博客园 - python3解析XML。注意有时候xml会被表示成一行,没有格式化,可以去XML在线格式化|菜鸟工具在线格式化xml方便阅读。

  1. <?xml version="1.0"?>
  2. <doc>
  3. <branch name="codingpy.com" hash="1cdf045c">
  4. source
  5. </branch>
  6. <branch name="release01" hash="f200013e">
  7. <sub-branch name="subrelease01">
  8. xml,sgml
  9. </sub-branch>
  10. </branch>
  11. <branch name="invalid"></branch>
  12. </doc>

读取、查找

读取文档

  1. import xml.etree.ElementTree as ET
  2. # 加载本地`test.xml`文档
  3. tree = ET.ElementTree(file='test.xml')
  4. # 获取root元素
  5. root = tree.getroot()
  6. print(root)
  7. '<Element 'doc' at 0x11eb780>'

遍历

  1. # 遍历全部元素(DFS)
  2. for elem in tree.iter():
  3. print(elem.tag, elem.attrib)
  4. '''
  5. doc {}
  6. branch {'hash': '1cdf045c', 'name': 'codingpy.com'}
  7. branch {'hash': 'f200013e', 'name': 'release01'}
  8. sub-branch {'name': 'subrelease01'}
  9. branch {'name': 'invalid'}
  10. '''
  11. # 遍历指定tag的元素
  12. for elem in tree.iter(tag='branch'):
  13. print(elem.tag, elem.attrib)
  14. '''
  15. branch {'hash': '1cdf045c', 'name': 'codingpy.com'}
  16. branch {'hash': 'f200013e', 'name': 'release01'}
  17. branch {'name': 'invalid'}
  18. '''
  19. # 遍历节点子元素
  20. for child in root:
  21. print(child.tag, child.attrib)
  22. '''
  23. branch {'hash': '1cdf045c', 'name': 'codingpy.com'}
  24. branch {'hash': 'f200013e', 'name': 'release01'}
  25. branch {'name': 'invalid'}
  26. '''

索引、查找
支持index和XPath

  1. # 通过索引来访问特定子元素
  2. print(root[0].tag, root[0].text)
  3. 'branch', '\n source\n '
  4. # 通过XPath查找元素
  5. # 查找branch元素之下所有tag为sub-branch的元素
  6. for elem in tree.iterfind('branch/sub-branch'):
  7. print(elem.tag, elem.attrib)
  8. '''
  9. sub-branch {'name': 'subrelease01'}
  10. '''
  11. # 通过XPath查找所有具备某个name属性的branch元素
  12. for elem in tree.iterfind('branch[@name="release01"]'):
  13. print(elem.tag, elem.attrib)
  14. '''
  15. branch {'hash': 'f200013e', 'name': 'release01'}
  16. '''

增删改

创建xml文档

  1. a = ET.Element('elem')
  2. c = ET.SubElement(a, 'child1')
  3. c.text = "some text"
  4. d = ET.SubElement(a, 'child2')
  5. b = ET.Element('elem_b')
  6. root = ET.Element('root')
  7. root.extend((a, b))# 也可以是root.append(a), root.append(b)
  8. tree = ET.ElementTree(root)
  9. ET.dump(tree)
  10. '''
  11. <root>
  12. <elem>
  13. <child1>some text</child1>
  14. <child2 />
  15. </elem>
  16. <elem_b />
  17. </root>
  18. '''

删除节点

修改节点

  1. root = tree.getroot()
  2. del root[2]
  3. root[0].set('foo', 'bar')
  4. for subelem in root:
  5. print(subelem.tag, subelem.attrib)
  6. '''
  7. branch {'foo': 'bar', 'hash': '1cdf045c', 'name': 'codingpy.com'}
  8. branch {'hash': 'f200013e', 'name': 'release01'}
  9. '''
  10. ET.dump(root)
  11. # 请注意,文档中元素的属性顺序与原文档不同。这是因为ET是以字典的形式保存属性的,而字典是一个无序的数据结构。当然,XML也不关注属性的顺序。
  12. '''
  13. <doc>
  14. <branch foo="bar" hash="1cdf045c" name="codingpy.com">
  15. text,source
  16. </branch>
  17. <branch hash="f200013e" name="release01">
  18. <sub-branch name="subrelease01">
  19. xml,sgml
  20. </sub-branch>
  21. </branch>
  22. </doc>
  23. '''

删改查

  1. import xml.etree.ElementTree as ET
  2. """
  3. ElementTree.write() 将构建的XML文档写入(更新)文件。
  4. Element.set(key, value) 添加和修改属性
  5. Element.text = '' 直接改变字段内容
  6. Element.remove(Element) 删除Element节点
  7. Element.append(Element) 为当前的Elment对象添加子对象
  8. ET.SubElement(Element,tag)创建子节点
  9. """
  10. # 增加自动缩进换行
  11. def indent(elem, level=0):
  12. i = "\n" + level*" "
  13. if len(elem):
  14. if not elem.text or not elem.text.strip():
  15. elem.text = i + " "
  16. if not elem.tail or not elem.tail.strip():
  17. elem.tail = i
  18. for elem in elem:
  19. indent(elem, level+1)
  20. if not elem.tail or not elem.tail.strip():
  21. elem.tail = i
  22. else:
  23. if level and (not elem.tail or not elem.tail.strip()):
  24. elem.tail = i
  25. #------------新增XML----------
  26. #创建根节点
  27. a = ET.Element("student")
  28. #创建子节点,并添加属性
  29. b = ET.SubElement(a,"name")
  30. b.attrib = {"NO.":"001"}
  31. #添加数据
  32. b.text = "张三"
  33. #创建elementtree对象,写文件
  34. indent(a,0)
  35. tree = ET.ElementTree(a)
  36. tree.write("writeXml.xml",encoding="utf-8")
  37. #----------编辑XML--------
  38. # 读取待修改文件
  39. updateTree = ET.parse("writeXml.xml")
  40. root = updateTree.getroot()
  41. # --新增--
  42. # 创建新节点并添加为root的子节点
  43. newnode = ET.Element("name")
  44. newnode.attrib = {"NO.":"003"}
  45. newnode.text = "张三水"
  46. root.append(newnode)
  47. #---修改---
  48. sub1 = root.findall("name")[2]
  49. # --修改节点的属性
  50. sub1.set("NO.","100")
  51. # --修改节点内文本
  52. sub1.text="陈真"
  53. #----删除---
  54. #--删除标签内文本
  55. sub1.text = ""
  56. #--删除标签的属性
  57. del sub1.attrib["NO."]
  58. #--删除一个节点
  59. root.remove(sub1)
  60. # 写回原文件
  61. indent(root,0)
  62. updateTree.write("writeXml.xml",encoding="utf-8", xml_declaration=True)

参考链接