Python解析XML的三种主流方法:DOM、ElementTree与SAX详解

纸上星河
纸上星河
发布时间:2026-10-13 | 1人浏览过
原创

本文详细介绍Python中解析XML文件的三种常用方法:xml.dom.*、xml.etree.ElementTree以及xml.sax.*。通过对比DOM API、轻量级ET API及基于事件驱动的SAX API在性能、内存占用及适用场景上的差异,结合具体代码示例,展示如何获取标签、属性及文本数据,并演示文件的遍历、查找与修改操作,帮助开发者根据实际需求选择最优解析方案。

1. XML简介

XML(eXtensible Markup Language)即可扩展标记语言,主要设计用于数据的传输与存储。随着技术发展,XML已成为众多新兴技术的核心组件,广泛应用于不同领域。它是Web演进过程中的重要产物,既保留了SGML的核心特征,又兼具HTML的简洁性,同时具备定义明确、结构良好等新增特性。

test.XML文件

<?xml version="1.0" encoding="utf-8"?>
<catalog>
  <maxid>4</maxid>
  <login username="pytest" passwd='123456'>
    <caption>Python</caption>
    <item id="4">
      <caption>测试</caption>
    </item>
  </login>
  <item id="2">
    <caption>Zope</caption>
  </item>
</catalog>

关于XML的更详细说明,可参考: http://www.w3school.com.cn/xmldom/dom_nodetype.asp

2. XML文件解析

在Python中,解析XML通常有三种方式:第一种是xml.dom.*模块,它实现了W3C DOM API,适合需要处理DOM API的场景;第二种是xml.sax.*模块,实现了SAX API,该方式以牺牲便捷性为代价换取了更高的速度和更低的内存占用。SAX是一种基于事件的API,允许在处理庞大文档时“边加载边处理”,无需将整个文档加载至内存;第三种是xml.etree.ElementTree模块(简称ET),它提供了轻量级且符合Python风格的API。相比DOM,ET的速度显著提升,且拥有众多便捷的API;与SAX相比,ET的iterparse方法同样支持“边加载边处理”,无需加载完整文档。虽然ET的性能平均值与SAX相近,但其API效率更高且使用更为简便。

2.1 xml.dom.*

文件对象模型(Document Object Model,简称DOM)是W3C推荐的处理可扩展置标语言的标准编程接口。DOM解析器在解析XML文档时,会一次性读取整个文档,并将所有元素保存在内存中的树形结构里。随后,开发者可以利用DOM提供的不同函数来读取或修改文档的内容与结构,也可将修改后的内容写回XML文件。在Python中,通常使用xml.dom.minidom来解析XML文件。

a. 获得子标签

b. 区分相同标签名的标签

c. 获取标签属性值

d. 获取标签对之间的数据

#coding=utf-8

#通过minidom解析xml文件
import xml.dom.minidom as xmldom
import os
''' 
XML文件读取 
<?xml version="1.0" encoding="utf-8"?>
<catalog>
  <maxid>4</maxid>
  <login username="pytest" passwd='123456'>dasdas
    <caption>Python</caption>
    <item id="4">
      <caption>测试</caption>
    </item>
  </login>
  <item id="2">
    <caption>Zope</caption>
  </item>
</catalog>

'''

xmlfilepath = os.path.abspath("test.xml")
print ("xml文件路径:", xmlfilepath)

# 得到文档对象
domobj = xmldom.parse(xmlfilepath)
print("xmldom.parse:", type(domobj))
# 得到元素对象
elementobj = domobj.documentElement
print ("domobj.documentElement:", type(elementobj))

#获得子标签
subElementObj = elementobj.getElementsByTagName("login")
print ("getElementsByTagName:", type(subElementObj))

print (len(subElementObj))
# 获得标签属性值
print (subElementObj[0].getAttribute("username"))
print (subElementObj[0].getAttribute("passwd"))

#区分相同标签名的标签
subElementObj1 = elementobj.getElementsByTagName("caption")
for i in range(len(subElementObj1)):
  print ("subElementObj1[i]:", type(subElementObj1[i]))
  print (subElementObj1[i].firstChild.data) #显示标签对之间的数据

输出结果:

>>> D:\Pystu>python xml_instance.py >>> xml文件路径: D:\Pystu\test.xml >>> xmldom.parse: <class 'xml.dom.minidom.Document'> >>> domobj.documentElement: <class 'xml.dom.minidom.Element'> >>> getElementsByTagName: <class 'xml.dom.minicompat.NodeList'> >>> username: pytest >>> passwd: 123456 >>> subElementObj1[i]: <class 'xml.dom.minidom.Element'> >>> Python >>> subElementObj1[i]: <class 'xml.dom.minidom.Element'> >>> 测试 >>> subElementObj1[i]: <class 'xml.dom.minidom.Element'> >>> Zope

2.2 xml.etree.ElementTree

ElementTree专为处理XML而生。在Python标准库中,它有两种实现:一种是纯Python实现的xml.etree.ElementTree,另一种是速度更快的xml.etree.cElementTree。建议优先使用C语言实现的版本,因其执行速度更快且内存消耗更少。

a. 遍历根节点的下一层

b. 下标访问各个标签、属性、文本

c. 查找root下的指定标签

d. 遍历XML文件

e. 修改XML文件

#coding=utf-8

#通过解析xml文件
'''
try:
  import xml.etree.CElementTree as ET
except:
  import xml.etree.ElementTree as ET

从Python3.3开始ElementTree模块会自动寻找可用的C库来加快速度  
'''
import xml.etree.ElementTree as ET
import os
import sys
''' 
XML文件读取 
<?xml version="1.0" encoding="utf-8"?>
<catalog>
  <maxid>4</maxid>
  <login username="pytest" passwd='123456'>dasdas
    <caption>Python</caption>
    <item id="4">
      <caption>测试</caption>
    </item>
  </login>
  <item id="2">
    <caption>Zope</caption>
  </item>
</catalog>
'''

#遍历xml文件
def traverseXml(element):
  #print (len(element))
  if len(element)>0:
    for child in element:
      print (child.tag, "----", child.attrib)
      traverseXml(child)
  #else:
    #print (element.tag, "----", element.attrib)
    

if __name__ == "__main__":
  xmlFilePath = os.path.abspath("test.xml")
  print(xmlFilePath)
  try:
    tree = ET.parse(xmlFilePath)
    print ("tree type:", type(tree))
  
    # 获得根节点
    root = tree.getroot()
  except Exception as e: #捕获除与程序退出sys.exit()相关之外的所有异常
    print ("parse test.xml fail!")
    sys.exit()
  print ("root type:", type(root))  
  print (root.tag, "----", root.attrib)
  
  #遍历root的下一层
  for child in root:
    print ("遍历root的下一层", child.tag, "----", child.attrib)

  #使用下标访问
  print (root[0].text)
  print (root[1][1][0].text)

  print (20 * "*")
  #遍历xml文件
  traverseXml(root)
  print (20 * "*")

  #根据标签名查找root下的所有标签
  captionList = root.findall("item") #在当前指定目录下遍历
  print (len(captionList))
  for caption in captionList:
    print (caption.tag, "----", caption.attrib, "----", caption.text)

  #修改xml文件,将passwd修改为999999
  login = root.find("login")
  passwdValue = login.get("passwd")
  print ("not modify passwd:", passwdValue)
  login.set("passwd", "999999")  #修改,若修改text则表示为login.text
  print ("modify passwd:", login.get("passwd"))

输出结果:

>>> D:\Pystu\test.xml >>> tree type: <class 'xml.etree.ElementTree.ElementTree'> >>> root type: <class 'xml.etree.ElementTree.Element'> >>> catalog ---- {} >>> 遍历root的下一层 maxid ---- {} >>> 遍历root的下一层 login ---- {'username': 'pytest', 'passwd': '123456'} >>> 遍历root的下一层 item ---- {'id': '2'} >>> 4 >>> 测试 >>> ******************** >>> maxid ---- {} >>> login ---- {'username': 'pytest', 'passwd': '123456'} >>> caption ---- {} >>> item ---- {'id': '4'} >>> caption ---- {} >>> item ---- {'id': '2'} >>> caption ---- {} >>> ******************** >>> 1 >>> item ---- {'id': '2'} ---- >>> not modify passwd: 123456 >>> modify passwd: 999999

附:

#coding=utf-8

'''
  XML解析类
  @功能-结点的增删改查
'''
import xml.etree.ElementTree as ET
import sys
import os.path

class XmlParse:
  def __init__(self, file_path):
    self.tree = None
    self.root = None
    self.xml_file_path = file_path

  def ReadXml(self):
    try:
      print("xmlfile:", self.xml_file_path)
      self.tree = ET.parse(self.xml_file_path)
      self.root = self.tree.getroot()
    except Exception as e:
      print ("parse xml faild!")
      sys.exit()
    else:
      print ("parse xml success!")      
    finally: 
      return self.tree
        
  def CreateNode(self, tag, attrib, text):
    element = ET.Element(tag, attrib)
    element.text = text
    print ("tag:%s;attrib:%s;text:%s" %(tag, attrib, text))
    return element
       
  def AddNode(self, Parent, tag, attrib, text):
    element = self.CreateNode(tag, attrib, text)
    if Parent:
      Parent.append(element)
      el = self.root.find("lizhi")
      print (el.tag, "----", el.attrib, "----", el.text)
    else:
      print ("parent is none")

  def WriteXml(self, destfile):
    dest_xml_file = os.path.abspath(destfile)
    self.tree.write(dest_xml_file, encoding="utf-8",xml_declaration=True)
    

if __name__ == "__main__":
  xml_file = os.path.abspath("test.xml")
  parse = XmlParse(xml_file)
  tree = parse.ReadXml()
  root = tree.getroot()
  print (root)
  parse.AddNode(root, "Python", {"age":"22", "hello":"world"}, "YES")
  
  parse.WriteXml("testtest.xml")

2.3 xml.sax.*

SAX是一种基于事件驱动的API,使用SAX解析XML涉及两个部分:解析器和事件处理器。

解析器负责读取XML文档,并向事件处理器发送事件,例如元素开始和元素结束事件。

事件处理器负责对接收到的事件做出响应,并对传递的XML数据进行处理。

常用场景:

(1)对大型文件进行处理

(2)只需文件的部分内容,或只需从文件中获取特定信息

(3)希望建立自己的对象模型

基于事件驱动的SAX解析XML内容的知识后续补充!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表