精华内容
下载资源
问答
  • Python XML 解析

    2021-01-03 03:47:38
    Python XML 解析 什么是 XMLXML 指可扩展标记语言(eXtensible Markup Language)。 你可以通过本站学习 XML 教程 XML 被设计用来传输和存储数据。 XML 是一套定义语义标记的规则,这些标记将文档分成许多部件并...
  • python xml解析实例详解

    2021-01-20 04:36:26
    python xml解析 first.xml  <id>1 <name>fsy <age>24 <id>2 <name>jianjian <age>24 <count id ='1'>1000 from xml.etree import ElementTree as etree  读入 def read_xml(file): # parse()函数会返回...
  • xml_stream 一个 Python XML 解析器,一个从流中读取的生成器。
  • 主要介绍了Python中使用ElementTree解析XML示例,本文同时讲解了XML基本概念介绍、XML几种解析方法和ElementTree解析实例,需要的朋友可以参考下
  • xmlr:用于解析非常大的XML文件的Python
  • Python XML解析

    2017-07-03 21:28:30
    下面我们来一起看下 python 中对 xml解析 1.python 解析 xml 的三种方式 python中有三种方法解析xml,分别为:SAX、DOM、ElementTree SAX用事件驱动模型,通过在解析XML的过程中触发对应的事件并调用用户定义...

    xml 是一种扩展标记语言,实际开发中应用也比较广泛,经常用来在服务端与客户端间进行数据传输。下面我们来一起看下 python 中对 xml 的解析

    1.python 解析 xml 的三种方式

    python中有三种方法解析xml,分别为:SAX、DOM、ElementTree,建议使用第三种 ElementTree 解析 xml。

    SAX用事件驱动模型,通过在解析XML的过程中触发对应的事件并调用用户定义的回调函数来处理XML文件。SAX是一种基于事件驱动的API,使用SAX解析XML会涉及到两个部分:解析器和事件处理器,解析器主要用于解析XML数据,并向事件处理器发送事件(startElement、endElement、characters等),而事件处理器主要用于对触发事件后作响应,对传递的XML数据进行处理。
    优点:SAX使用流来读取xml数据,效率快,占用内存少
    缺点:需要用户实现回调函数(Handler)

    DOM是一次性将xml数据全部读取并解析成一个树放到内存中,通过对树的操作来操作XML。在解析时,一次性读取整个xml文档并把文档中所有的元素存放到内存中的一个树结构中,然后利用DOM提供的函数来读取或修改文档的内容和结构
    优点:使用DOM的好处是不用对状态进行追踪,因为每一个节点都知道谁是它的父节点,谁是它的子节点
    缺点:一次性将xml数据全部读取映射到内存中的树,效率低、占用内存

    ElementTree类似一个轻量级的DOM,具有方便友好的API,代码可用性好,速度快,消耗内存少,推荐使用。

    下面我们通过一个案例,分别用这三种方式来解析xml,看下每种方式是如何操作的。

    有一个people.xml文件,内容如下

    <?xml version="1.0" encoding="utf-8" ?>
    <people>
        <person id="zhangsna">
            <name>张三</name>
            <age>18</age>
            <tel>18511908765</tel>
        </person>
        <person id="lisi">
            <name>李四</name>
            <age>20</age>
            <tel>15018984728</tel>
        </person>
        <person id="wangwu">
            <name>王五</name>
            <age>22</age>
            <tel>13067894532</tel>
        </person>
        <person id="zhaoliu">
            <name>赵六</name>
            <age>23</age>
            <tel>13067894532</tel>
        </person>
    </people>

    解析people文件中的内容,解析完成后将数据封装到一个Person对象中然后在控制台打印,打印时分别按年龄升序和按中文降序。Person 类如下

    class Person:
        name=None
        age=None
        tel=None
        def __init__(self,name=None,age=None,tel=None):
            self.name=name
            self.age=age
            self.tel=tel
    
        def __repr__(self):  # 类似 java 中 的 toString()
            return '{0:20}{1:<5}{2:15}'.format(self.name, self.age, self.tel)

    2.SAX 解析

    sax 解析需要继承ContentHandler并重写其中的方法,ContentHandler类中常用方法如下

    方法参数作用
    startDocument()self文档启动时调用
    endDocument()self解析器到达文档结尾时调用
    startElement()self,name:元素名称,attrs:元素属性遇到XML开始标签时调用
    endElement()self,name:元素名称遇到XML结束标签时调用
    charactersself,content:文本内容读取元素内容时调用


    sax 模块常用方法

    方法作用
    make_parser()创建一个新的解析器对象并返回
    parse()创建一个 SAX 解析器并解析xml文档
    parseString()创建一个XML解析器并解析xml字符串


    代码:

    import xml.sax  # 导入sax模块
    from Person import Person   # 导入Person类
    
    # 继承ContentHandler
    class PeopleHandler(xml.sax.ContentHandler):
        # 初始化函数
        def __init__(self):
            self.person = None
            self.tag = None
    
        # 元素开始调用(name:元素名称,attrs:元素属性)
        def startElement(self, name, attrs):
            self.tag = name
            if name == 'person':
                self.person = Person()
    
        # 元素结束调用(name:元素名称)
        def endElement(self, name):
            if name == 'person':
                global people   # 引用外部的全局变量
                people.append(self.person)
                self.person = None
            self.tag = None
    
        # 读取元素内容时调用(content:文本内容)
        def characters(self, content):
            if "name" == self.tag:
                self.person.name = content
            if "age" == self.tag:
                self.person.age = int(content)
            if "tel" == self.tag:
                self.person.tel = content
    
    
    people = []
    
    # 创建一个 XMLReader
    parser = xml.sax.make_parser()
    
    # 关闭命名空间(不验证命名空间)
    parser.setFeature(xml.sax.handler.feature_namespaces, 0)
    
    # 重写 ContextHandler
    parser.setContentHandler(PeopleHandler())
    
    # 解析xml文档
    parser.parse("people.xml")
    
    print('{0:20}{1:<5}{2:15}'.format("姓名", "年龄", "手机号"))
    print("--------------按年龄升序--------------")
    for p in sorted(people, key=lambda x:x.age, reverse=False):
        print(p)
    print("--------------按中文降序--------------")
    people.sort(key=lambda x:x.name.encode("gbk"), reverse=True)  # 中文排序,需要进行编码为gbk或gb2312
    for p in people:
        print(p)

    运行结果:

    姓名                  年龄   手机号            
    --------------按年龄升序--------------
    张三                  18   18511908765    
    李四                  20   15018984728    
    王五                  22   13067894532    
    赵六                  23   13067894532    
    --------------按中文降序--------------
    赵六                  23   13067894532    
    张三                  18   18511908765    
    王五                  22   13067894532    
    李四                  20   15018984728    

    3.DOM 解析

    # 导入模块
    from xml.dom.minidom import parse
    from Person import Person
    
    people = []
    
    # 使用minidom解析器打开 XML 文档
    domTree = parse("people.xml")
    
    # 获取文档元素
    collection = domTree.documentElement;
    
    # 获取集合中的 person 元素
    person = collection.getElementsByTagName("person")
    for e in person:
        # 获取所有的id元素的属性
        # idAttrs = e.attributes['id']
        # print(idAttrs)
    
        # 获取所有的name元素
        # elements = e.getElementsByTagName("name")[0]
        # print(elements)
    
        # 获取所有的name元素的文本值
        # text = e.getElementsByTagName("name")[0].childNodes[0].data;
        # print(text)
    
        name = e.getElementsByTagName("name")[0].childNodes[0].data
        age = e.getElementsByTagName("age")[0].childNodes[0].data
        tel = e.getElementsByTagName("tel")[0].childNodes[0].data
    
        p = Person(name, age, tel)
        people.append(p)
    
    print('{0:20}{1:<5}{2:15}'.format("姓名", "年龄", "手机号"))
    print("--------------按年龄升序--------------")
    for p in sorted(people, key=lambda x:x.age, reverse=False):
        print(p)
    print("--------------按中文降序--------------")
    # 中文排序,需要进行编码为gbk或gb2312
    people.sort(key=lambda x:x.name.encode("gbk"), reverse=True)  
    for p in people:
        print(p)

    运行结果与SAX相同

    4.ElementTree

    ElementTree 在 Python 中有两种实现
    一种是纯 Python 实现:xml.etree.ElementTree
    另一种是 C 语言实现:xml.etree.cElementTree
    建议使用 C 语言 实现的 ElementTree,因为它速度更快,占用内存更少
    在程序中导入模块时这样写(如果C语言实现的不能使用再使用纯Python实现的)

    try:
        import xml.etree.cElementTree as ET
    except ImportError:
        import xml.etree.ElementTree as ET

    ElementTree 中 常用方法

    方法作用
    parse(xmlfile)加载xml文件
    fromstring(xmltext)加载xml文件
    findall()获取指定的所有节点
    find()获取指定的节点
    getchildren()获取儿子节点
    getiterator()获取指定的所有节点,与findall()类似


    示例:

    root = ET.parse("people.xml")
    print("------------findall()------------")
    persons1 = root.findall("person")
    print(persons1)
    
    print("----------getiterator()----------")
    persons2 = root.getiterator("person")
    print(persons2)
    
    print("----------getchildren()----------")
    for node in persons2:
        node_child = node.getchildren()[0]
        print(node_child.tag + " => " + node_child.text)

    运行结果:

    ------------findall()------------
    [<Element 'person' at 0x00000000020F02C8>, <Element 'person' at 0x0000000002585908>, <Element 'person' at 0x00000000025A1138>, <Element 'person' at 0x00000000025A1278>]
    ----------getiterator()----------
    [<Element 'person' at 0x00000000020F02C8>, <Element 'person' at 0x0000000002585908>, <Element 'person' at 0x00000000025A1138>, <Element 'person' at 0x00000000025A1278>]
    ----------getchildren()----------
    name => 张三
    name => 李四
    name => 王五
    name => 赵六

    ElementTree 中 常用属性

    属性作用
    attrib获取节点的属性及属性值(以元祖的形式返回)
    tag获取节点名称
    text获取节点的文本值


    示例

    root = ET.parse("people.xml")
    
    persons = root.findall("person")
    
    for node in persons:
        print(node.attrib)
        print(node.tag)
        name = node.find("name")
        print(name.text)

    运行结果:

    {'id': 'zhangsna'}
    person
    张三
    --------------------
    {'id': 'lisi'}
    person
    李四
    --------------------
    {'id': 'wangwu'}
    person
    王五
    --------------------
    {'id': 'zhaoliu'}
    person
    赵六
    --------------------

    ElementTree 的常用方法及属性我们了解后,接着实现我们最开始的案例,代码如下,运行结果与 SAX 相同

    from Person import Person
    try:
        import xml.etree.cElementTree as  ET
    except ImportError:
        import xml.etree.ElementTree as ET
    
    people = []
    
    # 加载people.xml文件
    root = ET.parse("people.xml")
    
    # 获取所有person节点
    persons = root.findall("person")
    
    for node in persons:
        name = node.find("name").text
        age = node.find("age").text
        tel = node.find("tel").text
    
        p = Person(name, age, tel)
        people.append(p)
    
    print('{0:20}{1:<5}{2:15}'.format("姓名", "年龄", "手机号"))
    print("--------------按年龄升序--------------")
    for p in sorted(people, key=lambda x:x.age, reverse=False):
        print(p)
    print("--------------按中文降序--------------")
    # 中文排序,需要进行编码为gbk或gb2312
    people.sort(key=lambda x:x.name.encode("gbk"), reverse=True)  
    for p in people:
        print(p)
    展开全文
  • 本篇文章主要介绍了Python实现XML文件解析的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 本文实例讲述了python基于xml parse实现解析cdatasection数据的方法,分享给大家供大家参考。 具体实现方法如下: from xml.dom.minidom import * implementation = DOMImplementation() print Core:%s % ...
  • 这篇文章主要介绍了用Python解析XML的几种常见方法,包括快速的使用ElementTree模块等方法的实例介绍,需要的朋友可以参考下 一、简介 XML(eXtensible Markup Language)指可扩展标记语言,被设计用来传输和存储数据...
  • XML解析方面,Python贯彻了自己“开箱即用”(batteriesincluded)的原则。在自带的标准库中,Python提供了大量可以用于处理XML语言的包和工具,数量之多,甚至让Python编程新手无从选择。本文将介绍深入解读利用...
  • 主要介绍了Python3基于sax解析xml操作,结合实例形式分析了Python3使用sax解析xml文档的相关原理与实现技巧,需要的朋友可以参考下
  • Python解析xml数据

    万次阅读 多人点赞 2018-12-12 01:02:09
    文章目录xmlxml数据结构python中的xml模块 xml xml(Extensible Markup Language,可扩展标记语言),它是一种标记语言,定义了一组规则。 xml没有什么特别的,仅仅是纯文本内容,只是和json定义的规则不一样而已...

    xml

    xml(Extensible Markup Language,可扩展标记语言),它是一种标记语言,定义了一组规则。
    xml没有什么特别的,仅仅是纯文本内容,只是和json定义的规则不一样而已。

    xml数据结构

    <data info="student">
    	<name>小明</name>
    	<age>18</age>
    	<gender>男</gender>
    </data>
    

    上述就是一个简单的xml数据,这里有几个概念,包括:

    • 根元素 <data>
    • 子元素 <name><age>…
    • 标签 带<>都是标签<data>是开始标签,</data>是结束标签
    • 属性 开始标签中有其它信息的是属性如data标签中的info
    • 文本 被开始标签和结束标签包含的是文本,如小明

    这里就简单的复习了下xml数据。下面使用Python来解析xml数据。

    python中的xml模块

    python自带xml模块方便开发者解析xml数据。xml模块中包含了广泛使用的API接口--------SAX和DOM。

    • SAX(Simple API for XML)解析xml数据
      xml简单处理API,通过解析XML的过程来触发事件来处理XML文件。不会将整个文件读取到内存中,只读取需要部分的内容。

      xml.sax下提供的函数:

    函数名功能
    make_parser(parser_list=[])创建并返回SAX解析器
    parse(filename_or_strease,handler,error_handler=handler.ErrorHandler())解析xml文件,filename_or_stream为指定解析的文件或流,handler为处理XML的回调,通过setContentHandler设置,error_handler为错误回调处理
    parseString(string,handler,error_handler=handler.ErrorHandler()与parse一样,只是从string中解析xml
    SAXException(msg,exception=None)XML操作相关的错误或警告

    ContentHandler主要事件回调:

    方法名说明
    startDocument()文档解析开始调用一次
    endDocument()解析到文档结尾调用一次
    startElement(name,attrs)文件模式下,遇到开始标签调用该方法,name是标签名,attrs是属性值字典
    endElement(name)文件模式下,遇到结束标签调用该方法,name是标签名
    characters(content)核心方法,1.从行开始,遇到标签之前存在字符,content的值为这些字符。2.从一个标签开始到一个标签结束,content为标签中包含的字符。3.从一个标签到行结束,存在字符,content为这些字符

    xml.sax解析代码:

    # coding=utf-8
    import xml.sax
    
    data_list = []
    
    
    class MyContentHandler(xml.sax.ContentHandler):
    
        def __init__(self):
            super().__init__()
            self.currentData = ""
            self.name = ""
            self.age = ""
            self.gender = ""
    
        def startDocument(self):
            print("开始解析xml")
    
        def endDocument(self):
            print("解析xml结束")
    
        def startElement(self, name, attrs):
            self.currentData = name
    
        def endElement(self, name):
            global data_list
            if name == 'name':
                data_list.append(self.name)
            elif name == 'age':
                data_list.append(self.age)
            elif name == 'gender':
                data_list.append(self.gender)
    
        def characters(self, content):
            if self.currentData == "name":
                self.name = content
            elif self.currentData == "age":
                self.age = content
            elif self.currentData == "gender":
                self.gender = content
    
    
    if __name__ == '__main__':
        saxParse = xml.sax.make_parser()
        saxParse.setFeature(xml.sax.handler.feature_namespaces, 0)  # 关闭命名解析
        handler = MyContentHandler()
        saxParse.setContentHandler(handler)
        saxParse.parse('xml_data.xml')
        print(data_list)
    
    

    运行结果:
    运行结果

    • DOM(Document Object Model,文档对象模型)解析xml数据

    DOM(文档对象模型)是W3C组织推荐处理可扩展标记语言的标准编程接口。
    DOM读取xml文件内容的基本操作:1.parse解析器(读取内容),2.DOM函数处理xml数据。

    DOM对象的相关函数

    接口对象名说明
    DOMImplementationDOM对象底层实现
    Node文档中大多数对象的基本接口
    NodeList节点列表接口
    DocumentType文档声明信息
    Document整个文档对象
    Element元素节点
    Attr属性节点
    Comment在源文档中表示评论
    Text节点中包含的文本内容
    ProcessingInstruction处理指令

    dom解析xml数据示例代码:

    # coding=utf-8
    import xml.dom.minidom
    
    data_list = []
    
    if __name__ == '__main__':
        document_tree = xml.dom.minidom.parse('xml_data.xml')
        collection = document_tree.documentElement # 获取所有元素
        print(collection.toxml())
        name_node = document_tree.getElementsByTagName("name")[0]
        name = name_node.childNodes[0].data
        data_list.append(name)
        age_node = document_tree.getElementsByTagName("age")[0]
        age = age_node.childNodes[0].data
        data_list.append(age)
        gender_node = document_tree.getElementsByTagName("gender")[0]
        gender = gender_node.childNodes[0].data
        data_list.append(gender)
        print(data_list)
    

    运行结果:
    在这里插入图片描述

    展开全文
  • 这篇文章主要介绍了python实现XML解析的方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 三种方法:一是xml.dom.*模块,它是W3C DOM API的实现,若需要...
  • python解析xml文件(解析、更新、写入)

    万次阅读 多人点赞 2019-04-24 11:24:36
    这篇博客内容将包括对XML文件的解析、追加新元素后写入到XML,以及更新原XML文件中某结点的值。使用的是pythonxml.dom.minidom包,详情可见其官方文档:xml.dom.minidom官方文档。全文都将围绕以下的customer.xml...

    Overview

    这篇博客内容将包括对XML文件的解析、追加新元素后写入到XML,以及更新原XML文件中某结点的值。使用的是python的xml.dom.minidom包,详情可见其官方文档:xml.dom.minidom官方文档。全文都将围绕以下的customer.xml进行操作:

    <?xml version="1.0" encoding="utf-8" ?>
    <!-- This is list of customers -->
    <customers>
      <customer ID="C001">
        <name>Acme Inc.</name>
        <phone>12345</phone>
        <comments>
          <![CDATA[Regular customer since 1995]]>
        </comments>
      </customer>
      <customer ID="C002">
        <name>Star Wars Inc.</name>
        <phone>23456</phone>
        <comments>
          <![CDATA[A small but healthy company.]]>
        </comments>
      </customer>
    </customers>
    

    CDATA:在XML中,不会被解析器解析的部分数据。

    声明:在本文中,结点和节点被视为了同一个概念,你可以在全文的任何地方替换它,我个人感觉区别不是很大,当然,你也可以看做是我的打字输入错误。

    1. 解析XML文件

    在解析XML时,所有的文本都是储存在文本节点中的,且该文本节点被视为元素结点的子结点,例如:2005,元素节点 ,拥有一个值为 “2005” 的文本节点,“2005” 不是 元素的值,最常用的方法就是getElementsByTagName()方法了,获取到结点后再进一步根据文档结构解析即可。

    具体的理论就不过多描述,配合上述XML文件和下面的代码,你将清楚的看到操作方法,下面的代码执行的工作是将所有的结点名称以及结点信息输出一下:

    # -*- coding: utf-8 -*-
    """
        @Author  : LiuZhian
        @Time    : 2019/4/24 0024 上午 9:19
        @Comment : 
    """
    from xml.dom.minidom import parse
    def readXML():
    	domTree = parse("./customer.xml")
    	# 文档根元素
    	rootNode = domTree.documentElement
    	print(rootNode.nodeName)
    
    	# 所有顾客
    	customers = rootNode.getElementsByTagName("customer")
    	print("****所有顾客信息****")
    	for customer in customers:
    		if customer.hasAttribute("ID"):
    			print("ID:", customer.getAttribute("ID"))
    			# name 元素
    			name = customer.getElementsByTagName("name")[0]
    			print(name.nodeName, ":", name.childNodes[0].data)
    			# phone 元素
    			phone = customer.getElementsByTagName("phone")[0]
    			print(phone.nodeName, ":", phone.childNodes[0].data)
    			# comments 元素
    			comments = customer.getElementsByTagName("comments")[0]
    			print(comments.nodeName, ":", comments.childNodes[0].data)
    
    if __name__ == '__main__':
    	readXML()
    

    在这里插入图片描述

    2. 写入XML文件

    在写入时,我觉得可分为两种方式:

    • 新建一个全新的XML文件
    • 在已有XML文件基础上追加一些元素信息

    至于以上两种情况,其实创建元素结点的方法类似,你必须要做的都是先创建/得到一个DOM对象,再在DOM基础上创建new一个新的结点。

    如果是第一种情况,你可以通过dom=minidom.Document()来创建;如果是第二种情况,直接可以通过解析已有XML文件来得到dom对象,例如dom = parse("./customer.xml")

    在具体创建元素/文本结点时,你大致会写出像以下这样的“四部曲”代码:

    • ①创建一个新元素结点createElement()
    • ②创建一个文本节点createTextNode()
    • ③将文本节点挂载元素结点上
    • ④将元素结点挂载到其父元素上。

    现在,我需要新建一个customer节点,信息如下:

    <customer ID="C003">
        <name>kavin</name>
        <phone>32467</phone>
        <comments>
          <![CDATA[A small but healthy company.]]>
        </comments>
      </customer>
    

    代码如下:

    def writeXML():
    	domTree = parse("./customer.xml")
    	# 文档根元素
    	rootNode = domTree.documentElement
    
    	# 新建一个customer节点
    	customer_node = domTree.createElement("customer")
    	customer_node.setAttribute("ID", "C003")
    
    	# 创建name节点,并设置textValue
    	name_node = domTree.createElement("name")
    	name_text_value = domTree.createTextNode("kavin")
    	name_node.appendChild(name_text_value)  # 把文本节点挂到name_node节点
    	customer_node.appendChild(name_node)
    
    	# 创建phone节点,并设置textValue
    	phone_node = domTree.createElement("phone")
    	phone_text_value = domTree.createTextNode("32467")
    	phone_node.appendChild(phone_text_value)  # 把文本节点挂到name_node节点
    	customer_node.appendChild(phone_node)
    
    	# 创建comments节点,这里是CDATA
    	comments_node = domTree.createElement("comments")
    	cdata_text_value = domTree.createCDATASection("A small but healthy company.")
    	comments_node.appendChild(cdata_text_value)
    	customer_node.appendChild(comments_node)
    
    	rootNode.appendChild(customer_node)
    
    	with open('added_customer.xml', 'w') as f:
    		# 缩进 - 换行 - 编码
    		domTree.writexml(f, addindent='  ', encoding='utf-8')
    
    if __name__ == '__main__':
    	writeXML()
    

    在这里插入图片描述

    3. 更新XML文件

    在更新XML时,只需先找到对应的元素结点,然后将其下的文本结点或属性取值更新即可,然后保存到文件,具体我就不多说了,代码中我将思路都注释清楚了,如下:

    def updateXML():
    	domTree = parse("./customer.xml")
    	# 文档根元素
    	rootNode = domTree.documentElement
    
    	names = rootNode.getElementsByTagName("name")
    	for name in names:
    		if name.childNodes[0].data == "Acme Inc.":
    			# 获取到name节点的父节点
    			pn = name.parentNode
    			# 父节点的phone节点,其实也就是name的兄弟节点
    			# 可能有sibNode方法,我没试过,大家可以google一下
    			phone = pn.getElementsByTagName("phone")[0]
    			# 更新phone的取值
    			phone.childNodes[0].data = 99999
    
    	with open('updated_customer.xml', 'w') as f:
    		# 缩进 - 换行 - 编码
    		domTree.writexml(f, addindent='  ', encoding='utf-8')
    
    if __name__ == '__main__':
    	updateXML()
    

    在这里插入图片描述

    如有不对之处,还烦请指教~

    展开全文
  • 主要介绍了Python使用sax模块解析XML文件,结合实例形势分析了Python使用sax模块针对xml文件进行读取、解析、内容处理等相关操作技巧,需要的朋友可以参考下
  • XML解析方面,Python贯彻了自己“开箱即用”(batteries included)的原则。在自带的标准库中,Python提供了大量可以用于处理XML语言的包和工具,数量之多,甚至让Python编程新手无从选择。 本文将介绍深入解读...

    在XML解析方面,Python贯彻了自己“开箱即用”(batteries included)的原则。在自带的标准库中,Python提供了大量可以用于处理XML语言的包和工具,数量之多,甚至让Python编程新手无从选择。

    本文将介绍深入解读利用Python语言解析XML文件的几种方式,并以笔者推荐使用的ElementTree模块为例,演示具体使用方法和场景。文中所使用的Python版本为2.7。

    什么是XML?

    XML是可扩展标记语言(Extensible Markup Language)的缩写,其中的 标记(markup)是关键部分。您可以创建内容,然后使用限定标记标记它,从而使每个单词、短语或块成为可识别、可分类的信息。

    在这里插入图片描述

    标记语言从早期的私有公司和政府制定形式逐渐演变成标准通用标记语言(Standard Generalized Markup Language,SGML)、超文本标记语言(Hypertext Markup Language,HTML),并且最终演变成 XML。XML有以下几个特点。

    • XML的设计宗旨是传输数据,而非显示数据。
    • XML标签没有被预定义。您需要自行定义标签。
    • XML被设计为具有自我描述性。
    • XML是W3C的推荐标准。

    目前,XML在Web中起到的作用不会亚于一直作为Web基石的HTML。XML无所不在。XML是各种应用程序之间进行数据传输的最常用的工具,并且在信息存储和描述领域变得越来越流行。因此,学会如何解析XML文件,对于Web开发来说是十分重要的。

    在这里插入图片描述

    有哪些可以解析XML的Python包?

    Python的标准库中,提供了6种可以用于处理XML的包。

    xml.dom

    xml.dom实现的是W3C制定的DOM API。如果你习惯于使用DOM API或者有人要求这这样做,可以使用这个包。不过要注意,在这个包中,还提供了几个不同的模块,各自的性能有所区别。
    在这里插入图片描述
    DOM解析器在任何处理开始之前,必须把基于XML文件生成的树状数据放在内存,所以DOM解析器的内存使用量完全根据输入资料的大小。

    xml.dom.minidom

    xml.dom.minidom是DOM API的极简化实现,比完整版的DOM要简单的多,而且这个包也小的多。那些不熟悉DOM的朋友,应该考虑使用 xml.etree.ElementTree模块。据lxml的作者评价,这个模块使用起来并不方便,效率也不高,而且还容易出现问题。

    xml.dom.pulldom

    与其他模块不同, xml.dom.pulldom模块提供的是一个“pull解析器”,其背后的基本概念指的是从XML流中pull事件,然后进行处理。虽然与SAX一样采用事件驱动模型(event-driven processing model),但是不同的是,使用pull解析器时,使用者需要明确地从XML流中pull事件,并对这些事件遍历处理,直到处理完成或者出现错误。

    pull解析(pull parsing)是近来兴起的一种XML处理趋势。此前诸如SAX和DOM这些流行的XML解析框架,都是 push-based,也就是说对解析工作的控制权,掌握在解析器的手中。
    xml.sax

    在这里插入图片描述
    xml.sax模块实现的是SAX API,这个模块牺牲了便捷性来换取速度和内存占用。SAX是Simple API for XML的缩写,它并不是由W3C官方所提出的标准。它是事件驱动的,并不需要一次性读入整个文档,而文档的读入过程也就是SAX的解析过程。所谓事件驱动,是指一种基于回调(callback)机制的程序运行方法。

    xml.parser.expat

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

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

    xml.etree.ElementTree(以下简称ET)
    在这里插入图片描述
    xml.etree.ElementTree模块提供了一个轻量级、Pythonic的API,同时还有一个高效的C语言实现,即 xml.etree.cElementTree。与DOM相比,ET的速度更快,API使用更直接、方便。与SAX相比, ET.iterparse函数同样提供了按需解析的功能,不会一次性在内存中读入整个文档。ET的性能与SAX模块大致相仿,但是它的API更加高层次,用户使用起来更加便捷。

    笔者建议,在使用Python进行XML解析时,首选使用ET模块,除非你有其他特别的需求,可能需要另外的模块来满足。

    解析XML的这几种API并不是Python独创的,Python也是通过借鉴其他语言或者直接从其他语言引入进来的。例如expat就是一个用C语言开发的、用来解析XML文档的开发库。而SAX最初是由DavidMegginson采用java语言开发的,DOM可以以一种独立于平台和语言的方式访问和修改一个文档的内容和结构,可以应用于任何编程语言。
    下面,我们以ElementTree模块为例,介绍在Python中如何解析lxml。

    利用ElementTree解析XML

    Python标准库中,提供了ET的两种实现。一个是纯Python实现的 xml.etree.ElementTree,另一个是速度更快的C语言实现 xml.etree.cElementTree。请记住始终使用C语言实现,因为它的速度要快很多,而且内存消耗也要少很多。如果你所使用的Python版本中没有 cElementTree所需的加速模块,你可以这样导入模块:

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助,
    群里还有不错的视频学习教程和PDF电子书!
    '''
    try:
        import xml.etree.cElementTree as ET
    except ImportError:
        import xml.etree.ElementTree as ET
    

    如果某个API存在不同的实现,上面是常见的导入方式。当然,很可能你直接导入第一个模块时,并不会出现问题。请注意,自Python 3.3之后,就不用采用上面的导入方法,因为 ElemenTree模块会自动优先使用C加速器,如果不存在C实现,则会使用Python实现。因此,使用Python 3.3+的朋友,只需要 importxml.etree.ElementTree即可。

    将XML文档解析为树(tree)

    我们先从基础讲起。XML是一种结构化、层级化的数据格式,最适合体现XML的数据结构就是树。ET提供了两个对象:ElementTree将整个XML文档转化为树, Element则代表着树上的单个节点。对整个XML文档的交互(读取,写入,查找需要的元素),一般是在 ElementTree层面进行的。对单个XML元素及其子元素,则是在 Element层面进行的。下面我们举例介绍主要使用方法。

    我们使用下面的XML文档,作为演示数据:

    <?xml version="1.0"?>
    <doc>
        <branch name="codingpy.com" hash="1cdf045c">
            text,source
        </branch>
        <branch name="release01" hash="f200013e">
            <sub-branch name="subrelease01">
                xml,sgml
            </sub-branch>
        </branch>
        <branch name="invalid">
        </branch>
    </doc>
    

    接下来,我们加载这个文档,并进行解析:

    >>> import xml.etree.ElementTree as ET
    >>> tree = ET.ElementTree(file='doc1.xml')
    

    然后,我们获取根元素(root element):

    >>> tree.getroot()
    <Element 'doc' at 0x11eb780>
    

    正如之前所讲的,根元素(root)是一个 Element对象。我们看看根元素都有哪些属性:

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助,
    群里还有不错的视频学习教程和PDF电子书!
    '''
    >>> root = tree.getroot()
    >>> root.tag, root.attrib
    ('doc', {})
    

    没错,根元素并没有属性。与其他 Element对象一样,根元素也具备遍历其直接子元素的接口:

    >>> for child_of_root in root:
    ...   print child_of_root.tag, child_of_root.attrib
    ...
    branch {'hash': '1cdf045c', 'name': 'codingpy.com'}
    branch {'hash': 'f200013e', 'name': 'release01'}
    branch {'name': 'invalid'}
    

    我们还可以通过索引值来访问特定的子元素:

    >>> root[0].tag, root[0].text
    ('branch', '\n        text,source\n    ')
    

    查找需要的元素

    从上面的示例中,可以明显发现我们能够通过简单的递归方法(对每一个元素,递归式访问其所有子元素)获取树中的所有元素。但是,由于这是十分常见的工作,ET提供了一些简便的实现方法。

    Element对象有一个 iter方法,可以对某个元素对象之下所有的子元素进行深度优先遍历(DFS)。ElementTree对象同样也有这个方法。下面是查找XML文档中所有元素的最简单方法:

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助,
    群里还有不错的视频学习教程和PDF电子书!
    '''
    >>> for elem in tree.iter():
    ...   print elem.tag, elem.attrib
    ...
    doc {}
    branch {'hash': '1cdf045c', 'name': 'codingpy.com'}
    branch {'hash': 'f200013e', 'name': 'release01'}
    sub-branch {'name': 'subrelease01'}
    branch {'name': 'invalid'}
    

    在此基础上,我们可以对树进行任意遍历——遍历所有元素,查找出自己感兴趣的属性。但是ET可以让这个工作更加简便、快捷。iter方法可以接受tag名称,然后遍历所有具备所提供tag的元素:

    >>> for elem in tree.iter(tag='branch'):
    ...   print elem.tag, elem.attrib
    ...
    branch {'hash': '1cdf045c', 'name': 'codingpy.com'}
    branch {'hash': 'f200013e', 'name': 'release01'}
    branch {'name': 'invalid'}
    

    支持通过XPath查找元素

    使用XPath查找感兴趣的元素,更加方便。Element对象中有一些 find方法可以接受Xpath路径作为参数, find方法会返回第一个匹配的子元素, findall以列表的形式返回所有匹配的子元素, iterfind则返回一个所有匹配元素的迭代器(iterator)。ElementTree对象也具备这些方法,相应地它的查找是从根节点开始的。

    下面是一个使用XPath查找元素的示例:

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助,
    群里还有不错的视频学习教程和PDF电子书!
    '''
    >>> for elem in tree.iterfind('branch/sub-branch'):
    ...   print elem.tag, elem.attrib
    ...
    sub-branch {'name': 'subrelease01'}
    

    上面的代码返回了 branch元素之下所有tag为 sub-branch的元素。接下来查找所有具备某个 name属性的 branch元素:

    >>> for elem in tree.iterfind('branch[@name="release01"]'):
    ...   print elem.tag, elem.attrib
    ...
    branch {'hash': 'f200013e', 'name': 'release01'}
    

    构建XML文档

    利用ET,很容易就可以完成XML文档构建,并写入保存为文件。ElementTree对象的 write方法就可以实现这个需求。

    一般来说,有两种主要使用场景。一是你先读取一个XML文档,进行修改,然后再将修改写入文档,二是从头创建一个新XML文档。

    修改文档的话,可以通过调整 Element对象来实现。请看下面的例子:

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助,
    群里还有不错的视频学习教程和PDF电子书!
    '''
    >>> root = tree.getroot()
    >>> del root[2]
    >>> root[0].set('foo', 'bar')
    >>> for subelem in root:
    ...   print subelem.tag, subelem.attrib
    ...
    branch {'foo': 'bar', 'hash': '1cdf045c', 'name': 'codingpy.com'}
    branch {'hash': 'f200013e', 'name': 'release01'}
    

    在上面的代码中,我们删除了root元素的第三个子元素,为第一个子元素增加了新属性。这个树可以重新写入至文件中。最终的XML文档应该是下面这样的:

    >>> import sys
    >>> tree.write(sys.stdout)
    <doc>
        <branch foo="bar" hash="1cdf045c" name="codingpy.com">
            text,source
        </branch>
        <branch hash="f200013e" name="release01">
            <sub-branch name="subrelease01">
                xml,sgml
            </sub-branch>
        </branch>
        </doc>
    

    请注意,文档中元素的属性顺序与原文档不同。这是因为ET是以字典的形式保存属性的,而字典是一个无序的数据结构。当然,XML也不关注属性的顺序。

    从头构建一个完整的文档也很容易。ET模块提供了一个 SubElement工厂函数,让创建元素的过程变得很简单:

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助,
    群里还有不错的视频学习教程和PDF电子书!
    '''
    >>> a = ET.Element('elem')
    >>> c = ET.SubElement(a, 'child1')
    >>> c.text = "some text"
    >>> d = ET.SubElement(a, 'child2')
    >>> b = ET.Element('elem_b')
    >>> root = ET.Element('root')
    >>> root.extend((a, b))
    >>> tree = ET.ElementTree(root)
    >>> tree.write(sys.stdout)
    <root><elem><child1>some text</child1><child2 /></elem><elem_b /></root>
    

    利用 iterparse解析XML流

    XML文档通常都会比较大,如何直接将文档读入内存的话,那么进行解析时就会出现问题。这也就是为什么不建议使用DOM,而是SAX API的理由之一。

    我们上面谈到,ET可以将XML文档加载为保存在内存里的树(in-memory tree),然后再进行处理。但是在解析大文件时,这应该也会出现和DOM一样的内存消耗大的问题吧?没错,的确有这个问题。为了解决这个问题,ET提供了一个类似SAX的特殊工具—— iterparse,可以循序地解析XML。

    接下来,笔者为大家展示如何使用 iterparse,并与标准的树解析方式进行对比。我们使用一个自动生成的XML文档,下面是该文档的开头部分:

    <?xml version="1.0" standalone="yes"?>
    <site>
      <regions>
        <africa>
          <item id="item0">
            <location>United States</location>    <!-- Counting locations -->
            <quantity>1</quantity>
            <name>duteous nine eighteen </name>
            <payment>Creditcard</payment>
            <description>
              <parlist>
    [...]
    

    我们来统计一下文档中出现了多少个文本值为Zimbabwe的location元素。下面是使用 ET.parse的标准方法:

    '''
    遇到问题没人解答?小编创建了一个Python学习交流QQ群:857662006 寻找有志同道合的小伙伴,互帮互助,
    群里还有不错的视频学习教程和PDF电子书!
    '''
    tree = ET.parse(sys.argv[2])
     
    count = 0
    for elem in tree.iter(tag='location'):
        if elem.text == 'Zimbabwe':
            count += 1`
    
    print count
    

    上面的代码会将全部元素载入内存,逐一解析。当解析一个约100MB的XML文档时,运行上面脚本的Python进程的内存使用峰值为约560MB,总运行时间问2.9秒。

    请注意,我们其实不需要讲整个树加载到内存里。只要检测出文本为相应值得location元素即可。其他数据都可以废弃。这时,我们就可以用上iterparse方法了:

    count = 0
    for event, elem in ET.iterparse(sys.argv[2]):
        if event == 'end':
            if elem.tag == 'location' and elem.text == 'Zimbabwe':
                count += 1
        elem.clear() # 将元素废弃
    
    print count
    

    上面的for循环会遍历iterparse事件,首先检查事件是否为 end,然后判断元素的tag是否为location,以及其文本值是否符合目标值。另外,调用 elem.clear()非常关键:因为 iterparse仍然会生成一个树,只是循序生成的而已。废弃掉不需要的元素,就相当于废弃了整个树,释放出系统分配的内存。

    当利用上面这个脚本解析同一个文件时,内存使用峰值只有7MB,运行时间为2.5秒。速度提升的原因,是我们这里只在树被构建时,遍历一次。而使用 parse的标准方法是先完成整个树的构建后,才再次遍历查找所需要的元素。

    iterparse的性能与SAX相当,但是其API却更加有用:iterparse会循序地构建树;而利用SAX时,你还得自己完成树的构建工作。

    展开全文
  • Python XML解析之SAX

    2017-07-10 02:48:30
    Python XML解析之SAX SAX,全称Simple API for XML,既是一种接口,也是一种软件包。它是一种XML解析的替代方法。SAX不同于DOM解析,它逐行扫描文档,一边扫描一边解析。由于应用程序只是在读取数据时检查数据,...
  • python解析xml超简单

    千次阅读 多人点赞 2019-06-18 15:51:38
    Python解析XML 软件测试老师布置的实验,解析xml,因为是小白,所以刚做这题很棘手,百度搜了好多python解析xml,都相对而言太基础,举的例子,就是一个父节点带一个子节点,标签屈指可数,直接get标签名就得到了,...
  • 主要介绍了python解析xml文件方式(解析、更新、写入),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • Python解析XML文件入库

    2020-12-07 18:46:07
    Python解析XML文件入库 1. python dom方法解析xml文件 【Q1:2020-12-06T12:00:00字段是否有必要拆分 】 from xml.dom.minidom import parse import xml.dom.minidom # 使用minidom解析器打开 XML 文档 DOMTree = ...
  • pythonxml解析DOM解析(一)

    千次阅读 2018-03-01 19:38:30
    节点可以有属性为什么写程序时使用xml:(1)平台兼容非常好,跨平台,语妄言通用(2)传递数据,保存数据(3)结构化存储,永久存储(4)多应用于配置文件,框架中使用解析xml文件中的内容,也就是读取xml文件内容...
  • 主要介绍了Python实现提取XML内容并保存到Excel中的方法,涉及Python针对xml文件的读取、解析以及Excel文件的写入、保存等相关操作技巧,需要的朋友可以参考下
  • python解析xml生成excel文档,有彩色效果,注释
  • 主要给大家介绍了关于利用python实现xml与数据库读取转换的方法,文中通过示例代码介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
  • Python解析xml字符串

    千次阅读 2020-09-08 09:57:51
    当前需要解析出字符串s中的<RESULT_MSG></RESULT_MSG>标记对中内容,作为程序返回值 代码如下: from xml.dom.minidom import parseString s = "<DATAROOT><DATAROW><BL_CODE>...
  • python xml解析

    千次阅读 2013-06-18 13:03:06
    first.xml 1 fsy 24 2 jianjian 24 1000 from xml.etree import ElementTree as etree 读入def read_xml(file): # parse()函数会返回一个能代表整篇文档的对象。这不是根元素。要获得根元素的引用可以调用get...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 75,292
精华内容 30,116
关键字:

pythonxml解析

python 订阅