zoukankan      html  css  js  c++  java
  • Python xml 模块

    Python xml 模块

    TOC

    • 什么是xml?
    • xml和json的区别
    • xml现今的应用
    • xml的解析方式
      • xml.etree.ElementTree
      • SAX(xml.parsers.expat)
      • DOM
    • 修改xml
    • 构建xml

    什么是xml?
    我的理解是,xml存储着数据,是一种数据结构,结构化的存储着数据(已标签为节点的树形结构)
    就像字典、列表一样,都是一种特定的数据结构。
    只不过字典、列表是python解释器在内存中使用的一种数据结构,而xml是文件这种载体中的一种数据结构。
    标签节点(Element):包含名字tag,属性attrib, 值text。

    xml和json的区别
    都说了xml是一种在文本中的一种数据结构,json是内存中数据序列化方式中的一种,序列化为json后可以写入文本中。json也可以看做一种数据结构,但是json可以表示的数据结构可以有很多如对象,列表,整数,字符串,布尔,所以说json是一种数据交换格式。

    xml 现今的应用

    由于json数据表达格式的出现,当今不同系统程序间的数据交换大多都是使用json。因为json是足够的轻量级,易读易写易解析,所以json是非常的流行。
    而xml则廉颇老矣,应该很多老的系统程序还在延续使用了。因为xml解析和创建都很繁琐,解析访问修改xml的方式也很多,所以导致了xml在新开发的软件中很少使用了。大多传统软件公司还在使用,新兴互联网公司都是用json进行数据文件话,或者数据传递。

    xml的解析方式

    主要有:

    1. xml.etree.ElementTree 子模块 提供简单有效的解析xml的API以及创建xml
    2. DOM——The Document Object Model 缺点将整个xml加载到内存,占用内存大,解析慢。优点,可以任意遍历树节点。
    3. SAX——The Simple API For Xml 因为是流模式读取解析,所以缺点就是需要自己写代码对每个节点的开始、内容、结尾进行处理。不是任意的遍历,是从头到尾。

    1. xml.etree.ElementTree

    两个主要类:
    1 .1. ElementTree 代表整个xml 树。

    • 怎么实例ElementTree对象
      • ElementTree.parse('xmlfile')
      • 如果xml形式已经是字符串,那么可能就直接将xml字符串实例为Element对象
    • ElementTree level涉及到读xml文件和写xml文件

    1 .2. Element 代表一个标签节点,可迭代,可索引访问,可包含子Element对象。有tag,attrib,text属性,分别代表标签名,属性字典,内容(如果内容是一个子Element,那么返回' ')

    • 怎么实例Element对象
      • ElementTreeInstance.getroot()
      • ElementTree.fromstring(string) 这就是上面提到的从xml字符串中处理xml内容,这就不必先得到ElementTree对象再得到Element对象。
    • Element是用于处理节点相关的任何操作
    • 需要注意,如果节点的tag有引用命名空间,那么tag明就要带上指定命名空间的值。

    <yeather:forecast xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0" code="39" date="23 Apr 2018" day="Mon" high="68" low="51" text="Scattered Showers"/>
    xmlns就是命名空间,yweather就是命名空间中的一个变量,会在tag中解析这个变量

    • Element常用方法
      Element.findall(match, namespace=None) 匹配上match的所有直属子element
      Element.find(match, namespace=None) 至匹配第一个直属子element

    Element.iter(tag=None) 迭代器中存在等于参数tag的所有节点的子节点,包括子节点的子节点,一直递归下去,所以这个很方便。区别域find和findall是正则匹配并且只在直属子节点。
    例如test.xml

    <?xml version="1.0"?>
    <data>
        <country name="Liechtenstein">
            <rank>1</rank>
            <year>2008</year>
            <gdppc>141100</gdppc>
            <neighbor name="Austria" direction="E"/>
            <neighbor name="Switzerland" direction="W"/>
        </country>
        <country name="Singapore">
            <rank>4</rank>
            <year>2011</year>
            <gdppc>59900</gdppc>
            <neighbor name="Malaysia" direction="N"/>
        </country>
        <country name="Panama">
            <rank>68</rank>
            <year>2011</year>
            <gdppc>13600</gdppc>
            <neighbor name="Costa Rica" direction="W"/>
            <neighbor name="Colombia" direction="E"/>
        </country>
    </data>
    

    解析xml

    import xml.etree.ElementTree as ET
    eletree = ET.parse('test.xml')  # 打开test.xml得到ElementTree对象
    root_node = eletree.getroot()  # 通过ElementTree对象的getroot得到root标签Element对象
    child1 = root_node[0]  # Element对象可迭代,支持索引访问协议,返回子节点
    child2 = root_node[1]
    atrrdict1 = child1.attrib  # 获取child1标签的属性,已字典方式返回
    child1ofchild1 = child1[0]  # 说明如果节点的内容还是节点,那么这个节点是可迭代的,如果节点能获取到text内容,那么这个节点就不能迭代访问了。
    print(child1ofchild1.text)  # 1
    
    # 还可以遍历节点
    for inode in root_node:
    	print(inode)
    

    2. SAX

    使用xml.parsers.expat
    使用里面的类ParserCreate()将返回一个xmlparser object,这个对象可以解析xml通过像数据流一样,一个节点一个节点的处理,处理方式是已事件触发式,即遇到节点的事件,调用事件提前做好的处理方法进行处理。
    所以这种方式解析xml,需要自己定义事件的处理器,并保存每种事件处理的结果。
    主要事件Event有三种:
    * StartElement Event
    * EndElement Event
    * CharactorData Event
    要处理哪种事件,就要相应handler赋给ParserCreate
    如:

    import re
    import datetime
    from urllib import request
    from xml.parsers.expat import ParserCreate
    import xml.etree.ElementTree as et
    
    with request.urlopen('https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%'
                         '20%3D%202151330&format=xml') as fp:
        wther_cont = fp.read().decode('utf-8')
    
    
    # 已SAX方式解析xml
    def parsexml(xml_str):
        wth_dict = dict()
        wth_dict.setdefault('city', re.search(r'Conditions fors(?P<city>w+),', xml_str).group('city'))  # 没找到city具体的标签或者属性,替代着用re来处理。
        wth_dict.setdefault('forecast', list())
        xml_parser = ParserCreate()  # a instance of ParserCreate, it is a xml processor.
    
        def start_ele(name, attrs):  # 定义start_element事件的处理
            if name == 'yweather:forecast':
                del attrs['xmlns:yweather']
                del attrs['code']
                del attrs['text']
                del attrs['day']
                # attrs['date'] = datetime.
                wth_dict['forecast'].append(attrs)
    
        xml_parser.StartElementHandler = start_ele  # 这里只定义了StartElement事件的处理方式
        xml_parser.Parse(xml_str)
        return wth_dict
    print(parsexml(wther_cont))
    
    • xmlparser.Parse() 与 xmlparser.ParseFile(file) 分别是xml字符串和xml文件作为参数进行解析
    • 因为每种事件的处理,所以最好自己在定义一个类,提供事件的处理方法,和存储事件处理想要从xml中得到的数据。

    3. DOM

    修改XML

    提供修改主要使用xml.etree.ElementTree模块
    模块的ElementTree对象提供写入和读取xml,所以修改xml后,通过ElementTree.write(file)方法将修改后的xml写入xml文件中。
    其实修改内容就是修改element对象的各种属性的值,如tag,attrib,text。
    例如test.xml进行修改

    import xml.etree.ElementTree as ET
    eletree = ET.parse('./test.xml')
    root_ele = eletree.getroot()
    root_ele[0].attrib.pop('name')
    eletree.write('./test.xml')
    

    结果test.xml变为

    <data>
        <country>   # 没有了name
            <rank>1</rank>
            <year>2008</year>
            <gdppc>141100</gdppc>
            <neighbor direction="E" name="Austria" />
            <neighbor direction="W" name="Switzerland" />
        </country>
        <country name="Singapore">
            <rank>4</rank>
            <year>2011</year>
            <gdppc>59900</gdppc>
            <neighbor direction="N" name="Malaysia" />
        </country>
        <country name="Panama">
            <rank>68</rank>
            <year>2011</year>
            <gdppc>13600</gdppc>
            <neighbor direction="W" name="Costa Rica" />
            <neighbor direction="E" name="Colombia" />
        </country>
    </data>
    

    还可以删除某节点的子节点,element.remove(subelement)

    import xml.etree.ElementTree as ET
    eletree = ET.parse('./test.xml')
    root_ele = eletree.getroot()
    root_ele.remove(root_ele[2])
    eletree.write('./test.xml')
    

    test.xml变为

    <data>
        <country>
            <rank>1</rank>
            <year>2008</year>
            <gdppc>141100</gdppc>
            <neighbor direction="E" name="Austria" />
            <neighbor direction="W" name="Switzerland" />
        </country>
        <country name="Singapore">
            <rank>4</rank>
            <year>2011</year>
            <gdppc>59900</gdppc>
            <neighbor direction="N" name="Malaysia" />
        </country>
        </data>
    

    构建XML

    1. 最简单方式,直接拼接字符串
    2. 通过ElementTree对象的方法构建

    a = ET.Element('a')
    b = ET.SubElement(a, 'b')
    c = ET.SubElement(a, 'c')
    d = ET.SubElement(c, 'd')
    ET.dump(a)

    <a><b /><c><d /></c></a>
    

    可以通过Element操作丰富内容
    给test.xml的root节点添加一个节点

    import xml.etree.ElementTree as ET
    eletree = ET.parse('./test.xml')
    root_ele = eletree.getroot()
    haha = ET.SubElement(root_ele, 'haha')
    haha.attrib.setdefault('test','testvalue')
    haha.text = 'hellworld'
    eletree.write('./test.xml')
    

    结果:

    <data>
        <country>
            <rank>1</rank>
            <year>2008</year>
            <gdppc>141100</gdppc>
            <neighbor direction="E" name="Austria" />
            <neighbor direction="W" name="Switzerland" />
        </country>
        <country name="Singapore">
            <rank>4</rank>
            <year>2011</year>
            <gdppc>59900</gdppc>
            <neighbor direction="N" name="Malaysia" />
        </country>
        <haha test="testvalue">
            hellworld
        </haha>
    </data>
    

    这次算是终于理解了xml的结构和解析。注意xml中的namespace。

  • 相关阅读:
    Instant Python 中文缩减版
    《Java疯狂讲义》(第3版)学习笔记 2
    《Java疯狂讲义》(第3版)学习笔记 1
    NXP Mifare S50标准IC卡- 访问位(Access Bits) 分析
    Python中获取异常(Exception)信息
    支持向量机(SVM)入门
    棋类游戏中人机博弈的设计
    (翻译)如何对python dict 类型按键(keys)或值(values)排序
    Python实现打印二叉树某一层的所有节点
    FIFA halts 2026 bids amid scandal 国际足联在丑闻期间停止2026年足球世界杯申请
  • 原文地址:https://www.cnblogs.com/ZJiQi/p/8926774.html
Copyright © 2011-2022 走看看