解析xml文件
解析文件
- 在现在的大数据时代,我们可以通过处理这些大量的数据来实现某个目标,那么这些大量的数据应该存储在哪里呢?很多数据都是通过写入一些文本文件中,存储在文本文件中,这种存储数据的文件类型有很多,比如:json,xml,txt等。由于最近接触的比赛的数据集是xml文件,接下来就说说如何用python解析xml文件。
xml(Extensible Markup Language)文件简介
XML指可扩展标记语言,被设计用来传输和存储数据,用于标记电子文件使其具有结构性的标记语言
xml简单易于在任何应用程序中读/写,使得xml很快成为数据交换的唯一公共语言,程序可以更容易的与windows、Mac os、Linux以及其他平台下产生的信息结合,然后可以很容易加载XML数据到程序中并分析它,并以XML格式输出结果
- xml可用作数据的说明、储存、传输
举个“栗子”:假设在一个微信群里面小明发了一条消息“你吃了吗?”,而这条消息发出后会被储存到服务器里,而当你进入微信的时候,这条消息就会从服务器里抓取过来显示到你的手机上。而这个抓取的过程中假设是以xml文件来传输(当然也有json,json和xml用途很相似,json,xml都有自己的格式,只是包装数据的格式不同而已,重要的是其中含有的数据,而不是包装的格式),以我们人的观念来看这些信息是这样表示的:
- 发送者:小喜
- 聊天组:XXXX
- 信息:你吃了吗?
显然上面的形式是我们很容易看懂的,但是机器却看不懂,所以传入之前它是通过xml的格式来让机器能识别出来,它的格式大概是这样:
<msg>
<sender = "小喜"/>
<groupid = 123445/>
<type = test/>
<content = "你吃了吗?"/>
</msg>
- xml文件现在多用于作配置文件,设置文件比较多,很多软件,框架都会采取xml作为配置文件。像在Android Studio中创建一个项目时,像在Andriod Studio中创建一个项目时,开始会弹出一个Configure your project,而你在上面输入的项目名,包名什么的都会帮你存储到AndroidManifest.xml文件里。此xml文件里还会默认配置好项目的一些属性和一个ManinActivity以及这个activity的一些属性,并且在之后一些组件(Activity,service等)都是要在这里面注册并配置的。
xml的优点
- 格式统一,符合标准
- 容易与其他系统进行远程交互,数据共享比较方便
xml的缺点
- xml文件庞大,文件格式复杂,传输占用带宽较大
- 服务器端和客户端都需要花费大量代码来解析,导致服务器端和客户端代码变得异常复杂且不易维护
- 客户端不同浏览器之间解析xml文件的方式不一致,需要重复编写很多代码
- 服务器端和客户端解析xml花费较多的资源和时间
JSON(Javascript Object Notation)文件简介
JSON是一种轻量级的数据交换格式。它基于ECMScript(欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得JSON成为理想的数据交换语言。易于人阅读和编写,同时爷易于机器解析和生成,并有效地提升网络传输效率
- 可读性方面
JSON和XML的数据可读性基本相同,JSON和XML的可读性可谓是不相上下,一边是建议的语法,一边是规范的标签形式,XML可读性较好些 - 可扩展性方面
XML天生有很好的扩展性,JSON当然也有,没有什么是XML能扩展而JSON不能的 - 编码难度方面
JSON的编码明显比XML容易很多,即使不借助工具也能写出JSON的代码,但是要编码XML文件就不太容易了,XML有丰富的编码工具,比如:Dom4j、JDom等 - 解码难度方面
XML的解析得考虑子节点父节点,而JSON得解析难度几乎为0
JSON的优点
- 数据格式比较简单,易于读写,格式都是压缩的,占用的带宽较小
- 易于解析,客户端Javascript可以简单的通过eval()进行JSON数据的读取
- 支持多种语言,便于服务器端解析
JSON的缺点
- 没有XML格式那么强的通用性
- JSON格式目前在Web Service中推广还属于初级阶段
利用Python解析XML文件
- 我在进行数据集的解析时使用Python中的一个库:xml.dom.minidom,解析出图像标注的数据信息,这些信息保存在xml文件中
- xml.dom.minidom是文档对象模型接口额最小实现,其API类似于其他语言,它的目标是比完整的DOM更简单,也更小。
首先调用该库里面的一个函数:parse(filename_or_file[, parser[, bufsize]]),该函数的参数可以是文件名或者是文件对象,一般传入的参数为文件对象名,Document Object Model从给定的输入中被返回,也就是DOM
什么是DOM
我们先来介绍一下什么是DOM,它是由W3C组织定义的一个标准。在前端开发时,我们往往需要在页面某个地方添加或者删除元素,添加或删除元素的操作是通过DOM来实现的。说白了DOM就是一个接口,通过DOM来操作页面中各种元素
W3C中的DOM被分为3个不同的部分/级别:
- 核心 DOM
用于任何结构化文档的标准模型 - XML DOM
用于XML文档的标准模型 - HTML DOM
用于HTML文档的标准模型
DOM的结构
DOM采用树形结构作为分层结构,以树节点形式表示页面总各种元素或内容,只介绍XML DOM,XML DOM是将XML文档作为一个树形结构,XML文件格式如下:
<bookstore>
<book category="children">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="web" cover="paperback">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
<book category="web">
<title lang="en">XQuery Kick Start</title>
<author>James McGovern</author>
<author>Per Bothner</author>
<author>Kurt Cagle</author>
<author>James Linn</author>
<author>Vaidyanathan Nagarajan</author>
<year>2003</year>
<price>49.99</price>
</book>
</bookstore>
可以看到XML文件是由标签对组成:
<book></book>
标签对可以有属性:
<book catagory=“web” cover="paperback"></book>
标签对可以嵌入数据:
<author>James McGovern</author>
标签对可以嵌入子标签:
<book category="web" cover="paperback">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
其树形结构如下图:
在DOM中,每个元素看成一个节点,而每一个节点就是一个“对象” ,在操作元素时,把每个元素节点看成一个对象,然后使用这个对象的属性和方法进行相关操作,每一个节点都有它的nodeName:节点名字,nodeValue:节点的值,只对文本节点有效,nodeType:节点的类型(一般不常用)
在解析XML DOM之前还要引入一些基本概念:
- 根节点(Root element)
每个XML DOM都会有个根节点,上述例子中的根节点就是:bookstore
XML文件都是将数据保存在根节点下的子节点中,若想获取那些信息就先要解析出根节点,就像剥洋葱一样,一层一层地解析出数据。 - 父(子)节点
一个节点之上的节点就是该节点的父节点,一个节点之下就是该节点的子节点,比如:book是bookstore的子节点,也是author的父节点 - 兄弟节点
如果多个节点在同一层次,并拥有相同的父节点,那么这几个节点就是兄弟节点
解析XML文件
函数parse()的功能就是做一个“DOM生成器”,可以从任何SAX解析器(暂时不用去了解)解析接受事件,即:文件夹或文件对象,并将它们转换成DOM树
首先需要引入xml.dom.minidom模块
import xml.dom.minidom
接着调用模块中函数:parse(),传入xml文件名作为参数,来打开这个xml文件,并将这个文件对象转化为dom对象
dom = xml.dom.minidom.parse("sample.xml")
前面说到了,数据一般存储到根节点下的子节点中,因此要先解析出根节点,而documenElement就是用于得到dom对象的文档元素,并把获得的对象给root
root = dom.documentElement
接下来就是要获取根节点下的子节点,对于知道元素名字的子元素,可以使用getElementsByTagName方法来获取,函数返回为List对象,这个列表里面包含了根节点下所有nodeName为"book"的子节点,其索引方式与列表的索引方式完全相同,假如获取得到的子节点下面还有子节点,则需要再次使用getElementsByTagName方法,前提是知道节点的名字
book = root.getElementsByTagName("book")
- 当然有一种比较神奇的xml文件分布,就是对于具有同一个节点名的节点列表,它们的父节点有可能不是在同一个节点列表里,此时getElementsByTagName方法同样会返回具有同一个节点名的列表,因此在解析xml文件时,要看看数据在文件中的分布
标签对中包含着标签的属性值。如何将其获取出来呢?可以用getAttribute方法获得标签的属性所对应的值,传入属性名作为参数,而且只能通过一个元素节点来调用它
catalog = book[0].getAttribute("catalog")
数据一般会存储在标签对之间,获取标签对之间的数据有很多种方法,DOM的成员有很多种比如有:firstChild成员返回被选节点下的第一个子节点,data成员返回该节点或该属性的文本,childNodes返回被选节点下的一个子节点列表,但是这个子节点列表的格式是:子节点信息被Text node给包围,也就是说,子节点信息的位置位于这个childNodes列表的奇数位置。
获取标签对之间的文本信息:
text = book[0].childNodes[1::2].data