第二十四天学Python:文件(3)XML格式文件的建立,用SAX解析

尽管北方的春天比南方要晚很多,尽管这里经历两次气温骤降,尽管过程起伏跌宕,但是春天的脚步不会有丝毫地停顿,阵阵花香终会飘入房中。
该来的总会来的。
/doge
没啥,就是感慨一下苦等许久的春天终于来了而已。
在这里插入图片描述


昨天介绍了JSON格式文件的建立与读写,今天来讲另一种格式的文件:

什么是XML文件?

表格

在了解XML文件之前,我们首先来看一下这个表格:
在这里插入图片描述
这是一个非常简单的任务表,现在我们想要用程序把它记录下来,可是用昨天的类似键值对的JSON格式保存的话,一对一对的方式明显是不能满足我们的要求的,更不用说txt文件保存了。
所以,这个时候,我们就需要用到一种新的方式来保存。

XML格式

XML格式是一种标记语言,它定义了一种保存数据的规则,使得机器与人类都可读。用XML格式保存如上列表的方式如下:
在这里插入图片描述
上图是直接打开了一个xml文件后显示的样子。
下图则是用电子表格打开xml文件的样子:
在这里插入图片描述
在这里插入图片描述
在了解了XML会以什么形式显示后,我们再来看一下它的结构。

XML数据的结构

在这里插入图片描述

  • 根元素:如图中的Date…/Date
  • 子元素:包含在根元素内成对出现的元素都是子元素,而且子元素可以嵌套子元素,如上图中蓝色与紫色的子元素
  • 标签:带“<>”的是标签。如Date是元素开始标签,/Date则是元素结束标签
  • 属性:提供了关于元素的额外信息,如蓝色子元素中的week=“Mon"与"Tues”,说明接下来要记录的是"Mon"或"Tues"的任务
  • 缩进:XML同样有缩进的要求,一般也都是4个空格4个空格这样。

生成XML文件

昨天讲JSON文件的时候,是按照三个步骤进行的:1.写函数 2.读函数 3.主函数
今天我们在昨天的基础上拓展一下:把生成文件与写操作封装到一个类里面。

自定义类

  • 初始化实例相关的参数
class New_XML():  #自定义建立XML文件类
    def __init__(self,file = None): 
        self.file = file  #自定义属性file
        self.__get = None #自定义内部专用属性

我们定义了一个 file ,作为这个XML类的参数。而__get 是这个类内部使用的属性,会在随后的内容里用到

  • 打开/建立文件
    def open_X(self): #自定义打开XML文件函数
        if self.file == None:
            print('请输入一个文件!') #检测是否输入文件
            return False
        try:
            self.__get = open(self.file,'a',encoding='utf-8')
            #encoding='utf-8'是为了让输入的中文可供后续读取
            #在不写时默认为 None————ASCII码
            #类似昨天写JSON文件时的 ensure_ascii默认为 True时仅接受ASCII码
            #等于False时可以接受汉字
        except:
            print('%s打开出错'%(self.file)) #异常处理
            return False

encoding='utf-8’的解释在程序里的注释已经写得很清楚了,就不多说了。

  • 写函数
    def write_X(self,n,ele): #ele是元素的缩写
        try:
            if n == 0: #写入根元素
                self.__get.write(ele+'\n')
            else: #写入子元素
                self.__get.write(''*n+ele+'\n')
        except:
            print('%s写入%s出错'%(self.file,ele)) #异常处理
  • 关闭文件
    def close_X(self): #关闭文件函数
        if self.__get: #正常关闭文件
            self.__get.close()

程序中的XML

在写程序的时候要严格保证格式的正确,否则生成的XML文件无法正常打开,或者后续的解析会报错,就很闹心:)

content={1:[0,'<Date date="0511">'],    #日期
         2:[4,'<task time="AM">'], #任务1开始
         3:[8,'<sub>Math</sub>'],       #数学
         4:[8,'<S_hour>2</S_hour>'],    #学习时间
         5:[8,'<T_hour>1</T_hour>'],    #练习时间
         6:[4,'</task>'],          #任务1结束
         7:[4,'<task time="PM">'], #任务2开始
         8:[8,'<sub>English</sub>'],    #英语
         9:[8,'<S_hour>2</S_hour>'],    #学习时间
         10:[8,'<T_hour>1.5</T_hour>'], #练习时间
         11:[4,'</task>'],         #任务2结束
         12:[0,'</Date>']
         }

在程序中,“0”,“4”,“8”分别代表了缩进的格数,如图:
在这里插入图片描述

主函数

file_test =  r'f:\Python_Le\New.xml' #文件名称
flag = False #标志位
try:
    New3.open_X()
    for get in content.items():#字典转元组 
        New3.write_X(get[1][0],get[1][1])#把元组的第一个和第二个元素写入
    flag = True
except:
    print('写入文件出错')
finally:
    if flag:
        New3.close_X()
        print('OK')
    else:
        print('over')

如此我们便生成了一个xml文件,打开后如图:
在这里插入图片描述

XML模块——SAX

建立完文件不是就意味着结束了,还要对他进行各种操作。这时候就需要用到Python自带的xml模块。
xml模块包含两个最基本的API接口,SAX和DOM。(API:应用程序编程接口,是一些预先定义的函数,)

  • SAX:只读,在解析XML的过程中触发一个个事件,并调用用户自己建立的函数来处理它。

与SAX不同的是,DOM允许更改XML文件。二者在功能上互相补充。DOM就不在此文细说了,以后如果有机会的话再说。

用SAX读XML文件

用SAX解析XML文档有两个部分:解析器和事件处理器
解析器:读取XML文件,并向时间处理器发送事件,如元素开始与元素结束等。
事件处理器:对解析器传来的时间做出响应,由ContentHandler类实现

我们在模块里找到这个类,发现其提供了各种方法,
如:startElement、endElement、characters等等等等,这些会在稍后的程序里写明。

继承ContentHandler类

ContentHandler类用于处理解析器传来的事件。但是为了适用于我们自己的xml文件,我们应稍微改造一下这个类。

  • 初始化实例相关的参数
import xml.sax

class MyMission(xml.sax.ContentHandler): #继承ContentHandler父类
    def __init__(self):#初始化
        self.CurrentData=""#中间量
        self.task=""   #工作
        self.sub =""   #科目
        self.S_hour="" #学习时间
        self.T_hour="" #练习时间
  • 元素开始事件

为了便于对比,在这里回顾一下我们之前的XML文件
在这里插入图片描述

    def startElement(self,label,att): #元素开始事件 label:标签 att:属性
        self.CurrentData = label
        if label=="task":
            time = att["time"]
            print(time)

task为开始的标签

  • 元素结束事件
    def endElement(self,label): #元素结束事件
        if self.CurrentData=="sub":
            print("sub:"+self.sub)
            
        elif self.CurrentData=="S_hour":
            print("S_hour:"+self.S_hour)
            
        elif self.CurrentData=="T_hour":
            print("T_hour:"+self.T_hour)
            
        self.CurrentData=""

在打印了task以后,在这里分别打印sub,S与T。
这里的print只是为了演示,也可以在最初定义一个列表,然后在这里把各个元素都添加到列表里,最后打印列表等等等等操作。(记得用global声明全局变量

  • 把值赋给类实例
    def characters(self,content): #content:对应元素里的内容
        if self.CurrentData=="sub":
            self.sub=content
        elif self.CurrentData=="S_hour":
            self.S_hour=content
        elif self.CurrentData=="T_hour":
            self.T_hour=content

这个类就算是继承完了/doge,现在它已经具备了基本的解析xml文件的功能。

主函数

file_test =  r'f:\Python_Le\New.xml' #文件名称

parser=xml.sax.make_parser() #创建一个解析器的XMLReader对象
parser.setFeature(xml.sax.handler.feature_namespaces,0)#关闭解析命令空间

Handler = MyMission() #实例化
parser.setContentHandler(Handler) #为解析器建立时间处理实例

parser.parse(file_test) #解析指定XML文件

其中用到的make_parser()等均是在xml.sax下的函数,感兴趣的话可以自己在模块中查看源码以及用法/doge
F5运行:
在这里插入图片描述

再次强调一遍,一定要严格检查自己写的XML的格式是否正确以及是否前后一致,今凌晨现写的程序,怎么执行都报错,一遍遍检查也没看出来哪里写错了:)
后来太困了就睡觉了。早晨醒来,仔细想了想,觉得可能是创建的xml文件有问题,一看果然:)
果然不能半夜写程序,半夜脑袋混:(
在这里插入图片描述


该来的总会来的/doge
这个Python的基础系列到此就算是结束了。但是,学习永无止境,旧的结束也意味着新的开始。Python不会停,但不会再使用这个“第n天”的主题,而是以某某应用的形式陆续发布,目前计划在下周开启新的短篇系列,敬请期待/doge
——————
算上第零期,这个系列正好更新了25天,总算是凑了个还算整的数= =
其实25天前,自己压根就没觉得能坚持下来,毕竟又要上课还有考试还要云调车还要锻炼身体还要复习(高数[,线代[,概率论]])英语等等等等事情,讲道理,作为一个普通的学生,我是真的不明白该如何去合理分配一天的时间QAQ,总感觉24小时不够用= =
可能这就是眼高手低吧
可能这就是我学不过学霸的原因吧

不过,不光这个Python基础系列更完了,我甚至还在五一假期加更了一个3天让车跑起来的系列。其实这个3天跑车只是临时起意,没想到我真的完成它了233333
——————
新人初来乍到,第一次写系列文。无论是在python方面,还是在排版与写文方面,我都只是个菜鸟(这一点可以从这么长这么啰嗦的后话里看出来啊哈哈)如果有大佬惠临我这个小白留下的笔记,也请不要嫌弃我的低水平,就当是看个笑话,若是您愿意对我的文章提出宝贵的建议或者批评,我将不胜荣幸,并一定会吸取教训,深刻反思。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/k_ksy/article/details/106037430