【Python】解析 XML

1、Python 对 XML 的解析

1.1 SAX (simple API for XML )

SAX 解析器使用事件驱动模型,通过在解析XML的过程中触发一个个的事件并调用用户定义的回调函数来处理XML文件。

xml.sax 模块牺牲了便捷性来换取速度和内存占用。

事件驱动指一种基于回调(callback)机制的程序运行方法。

利用SAX解析XML文档牵涉到两个部分:

  • 解析器:负责读取XML文档,并向事件处理器发送事件,如元素开始跟元素结束事件。
  • 事件处理器:负责对事件作出响应,对传递的XML数据进行处理。

SAX适用场景:

  • 对大型文件进行处理;
  • 只需要文件的部分内容,或者只需从文件中得到特定信息。
  • 想建立自己的对象模型的时候。

1.2 DOM(Document Object Model)

DOM 解析器在任何处理开始之前,必须把基于XML文件生成的树状数据放在内存,所以DOM解析器的内存使用量完全根据输入资料的大小。

  • xml.dom.minidom
    minidom 是DOM API的极简化实现,比完整版的DOM要简单的多,而且这个包也小的多。
  • xml.dom.pulldom
    pulldom模块提供的是一个"pull解析器",其背后的基本概念指的是从XML流中pull事件,然后进行处理。虽然与SAX一样采用事件驱动模型(event-driven processing model),但是不同的是,使用pull解析器时,使用者需要明确地从XML流中pull事件,并对这些事件遍历处理,直到处理完成或者出现错误。

1.3 ElementTree(元素树)

xml.etree.ElementTree 模块提供了一个轻量级、Pythonic的API,同时还有一个高效的C语言实现,即 xml.etree.cElementTree

与 DOM 相比,ET的速度更快,API使用更直接、方便。

与 SAX 相比,ET.iterparse 函数同样提供了按需解析的功能,不会一次性在内存中读入整个文档。ET的性能与SAX模块大致相仿,但是它的API更加高层次,用户使用起来更加便捷。

1.4 xml.parser.expat

xml.parser.expat 提供了对C语言编写的expat解析器的一个直接的、底层API接口。expat接口与SAX类似,也是基于事件回调机制,但是这个接口并不是标准化的,只适用于expat库。

expat是一个面向流的解析器。您注册的解析器回调(或handler)功能,然后开始搜索它的文档。当解析器识别该文件的指定的位置,它会调用该部分相应的处理程序(如果您已经注册的一个)。该文件被输送到解析器,会被分割成多个片断,并分段装到内存中。因此expat可以解析那些巨大的文件。

1.5 lxml

lxml 是一个第三方库,它提供了更强大的XML处理功能,包括XPath支持、XML Schema验证、HTML支持等。

1.6 xmltodict

xmltodict是一个第三方库,它提供了一个功能,将Python的字典对象转换为XML,反之亦然。

2、示例

XML 实例文件 movies.xml 内容如下:

xml 复制代码
<collection shelf="New Arrivals">
<movie title="Enemy Behind">
   <type>War, Thriller</type>
   <format>DVD</format>
   <year>2003</year>
   <rating>PG</rating>
   <stars>10</stars>
   <description>Talk about a US-Japan war</description>
</movie>
<movie title="Transformers">
   <type>Anime, Science Fiction</type>
   <format>DVD</format>
   <year>1989</year>
   <rating>R</rating>
   <stars>8</stars>
   <description>A schientific fiction</description>
</movie>
   <movie title="Trigun">
   <type>Anime, Action</type>
   <format>DVD</format>
   <episodes>4</episodes>
   <rating>PG</rating>
   <stars>10</stars>
   <description>Vash the Stampede!</description>
</movie>
<movie title="Ishtar">
   <type>Comedy</type>
   <format>VHS</format>
   <rating>PG</rating>
   <stars>2</stars>
   <description>Viewable boredom</description>
</movie>
</collection>

2.1 xml.sax

python 复制代码
#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
import xml.sax
 
class MovieHandler( xml.sax.ContentHandler ):
   def __init__(self):
      self.CurrentData = ""
      self.type = ""
      self.format = ""
      self.year = ""
      self.rating = ""
      self.stars = ""
      self.description = ""
 
   # 元素开始事件处理
   def startElement(self, tag, attributes):
      self.CurrentData = tag
      if tag == "movie":
         print "*****Movie*****"
         title = attributes["title"]
         print "Title:", title
 
   # 元素结束事件处理
   def endElement(self, tag):
      if self.CurrentData == "type":
         print "Type:", self.type
      elif self.CurrentData == "format":
         print "Format:", self.format
      elif self.CurrentData == "year":
         print "Year:", self.year
      elif self.CurrentData == "rating":
         print "Rating:", self.rating
      elif self.CurrentData == "stars":
         print "Stars:", self.stars
      elif self.CurrentData == "description":
         print "Description:", self.description
      self.CurrentData = ""
 
   # 内容事件处理
   def characters(self, content):
      if self.CurrentData == "type":
         self.type = content
      elif self.CurrentData == "format":
         self.format = content
      elif self.CurrentData == "year":
         self.year = content
      elif self.CurrentData == "rating":
         self.rating = content
      elif self.CurrentData == "stars":
         self.stars = content
      elif self.CurrentData == "description":
         self.description = content
  
if ( __name__ == "__main__"):
   
   # 创建一个 XMLReader
   parser = xml.sax.make_parser()
   # turn off namepsaces
   parser.setFeature(xml.sax.handler.feature_namespaces, 0)
 
   # 重写 ContextHandler
   Handler = MovieHandler()
   parser.setContentHandler( Handler )
   
   parser.parse("movies.xml")

运行结果:

powershell 复制代码
*****Movie*****
Title: Enemy Behind
Type: War, Thriller
Format: DVD
Year: 2003
Rating: PG
Stars: 10
Description: Talk about a US-Japan war
*****Movie*****
Title: Transformers
Type: Anime, Science Fiction
Format: DVD
Year: 1989
Rating: R
Stars: 8
Description: A schientific fiction
*****Movie*****
Title: Trigun
Type: Anime, Action
Format: DVD
Rating: PG
Stars: 10
Description: Vash the Stampede!
*****Movie*****
Title: Ishtar
Type: Comedy
Format: VHS
Rating: PG
Stars: 2
Description: Viewable boredom

2.2 xml.dom

python 复制代码
#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
from xml.dom.minidom import parse
import xml.dom.minidom
 
# 使用minidom解析器打开 XML 文档
DOMTree = xml.dom.minidom.parse("movies.xml")
collection = DOMTree.documentElement
if collection.hasAttribute("shelf"):
   print "Root element : %s" % collection.getAttribute("shelf")
 
# 在集合中获取所有电影
movies = collection.getElementsByTagName("movie")
 
# 打印每部电影的详细信息
for movie in movies:
   print "*****Movie*****"
   if movie.hasAttribute("title"):
      print "Title: %s" % movie.getAttribute("title")
 
   type = movie.getElementsByTagName('type')[0]
   print "Type: %s" % type.childNodes[0].data
   format = movie.getElementsByTagName('format')[0]
   print "Format: %s" % format.childNodes[0].data
   rating = movie.getElementsByTagName('rating')[0]
   print "Rating: %s" % rating.childNodes[0].data
   description = movie.getElementsByTagName('description')[0]
   print "Description: %s" % description.childNodes[0].data

运行结果:

powershell 复制代码
Root element : New Arrivals
*****Movie*****
Title: Enemy Behind
Type: War, Thriller
Format: DVD
Rating: PG
Description: Talk about a US-Japan war
*****Movie*****
Title: Transformers
Type: Anime, Science Fiction
Format: DVD
Rating: R
Description: A schientific fiction
*****Movie*****
Title: Trigun
Type: Anime, Action
Format: DVD
Rating: PG
Description: Vash the Stampede!
*****Movie*****
Title: Ishtar
Type: Comedy
Format: VHS
Rating: PG
Description: Viewable boredom

2.3 xml.etree.ElementTree

python 复制代码
import xml.etree.ElementTree as ET

xml_string = '''
        <book id="10086">
            <title lang="en">Good Omens</title>
            <authors>
                <name>Neil Gaiman</name>
                <name>Terry Pratchett</name>
            </authors>
            <year>1990</year>
        </book>
    '''

root = ET.fromstring(xml_string)

# 获取根元素的标签
print(root.tag)

# 获取根元素的文本内容
print(root.text)

# 获取根元素的属性
print(root.attrib)

# 查找第一个title元素
print(root.find("title").text)

# 查找所有author元素
names = root.find("authors").findall("name")
for name in names:
    print(name.text)

# 修改title元素的文本内容
root.find("title").text = "The Nice and Accurate Prophecies of Agnes Nutter, Witch"

# 添加一个新的元素
new_year = ET.SubElement(root, "year")
new_year.text = "2024"

# 将修改后的元素转换为字符串
new_xml_string = ET.tostring(root, encoding="unicode")
print(new_xml_string)

运行结果:

powershell 复制代码
book

            
{'id': '10086'}
Good Omens
Neil Gaiman
Terry Pratchett
<book id="10086">
            <title lang="en">The Nice and Accurate Prophecies of Agnes Nutter, Witch</title>
            <authors>
                <name>Neil Gaiman</name>
                <name>Terry Pratchett</name>
            </authors>
            <year>1990</year>
        <year>2024</year></book>     

10、资料

相关推荐
沃洛德.辛肯8 分钟前
PyTorch 的 F.scaled_dot_product_attention 返回Nan
人工智能·pytorch·python
noravinsc20 分钟前
人大金仓数据库 与django结合
数据库·python·django
豌豆花下猫27 分钟前
Python 潮流周刊#102:微软裁员 Faster CPython 团队(摘要)
后端·python·ai
yzx9910131 小时前
Gensim 是一个专为 Python 设计的开源库
开发语言·python·开源
麻雀无能为力1 小时前
python自学笔记2 数据类型
开发语言·笔记·python
Ndmzi1 小时前
matlab与python问题解析
python·matlab
懒大王爱吃狼1 小时前
怎么使用python进行PostgreSQL 数据库连接?
数据库·python·postgresql
猫猫村晨总1 小时前
网络爬虫学习之httpx的使用
爬虫·python·httpx
web150854159351 小时前
Python线性回归:从理论到实践的完整指南
python·机器学习·线性回归
ayiya_Oese2 小时前
[训练和优化] 3. 模型优化
人工智能·python·深度学习·神经网络·机器学习