Python 标准库之XML

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013486414/article/details/85448863

写在之前

带分隔符的文件仅有两维的数据:行 & 列。如果我们想在程序之间交换数据结构,需要一种方法把层次结构,序列,集合和其它的数据结构编码成文本。

今天要说的 XML 是最突出的处理上述这种转换的标记格式,它使用标签(tag)分隔数据。XML 在软件领域的用途非常广泛。

XML

XML 是什么?如果非要对其做一个定义式的说明,那这里我不得不引用一下 w3school 里面简洁而明快的说明:

XML 指可扩展标记语言(EXtensible Markup Language);

XML 是一种标记语言,类似于 HTML;

XML 的设计宗旨是传输数据,而非显示数据;

XML 标签没有被预定义,需要自行定义标签;

XML 被设计为具有自我描述性;

XML 是 W3C 的推荐标准。

如果你想要详细了解和学习 XML 的话,可以去阅读 w3school 的 XML 教程即可,里面讲述的很详细,在下面我还会引用一些里面的内容。

XML 的重要性在于它是用来传输数据的,因此,特别是在 Web 编程中我们经常会用到它。有了它,让数据传输变的更加简单,这么重要的东西,我大 Python 当然支持。

有大佬曾经说过:“一个引人关注的东西总会有很多人从不同侧面去研究它”。这个在编程中也同样适用,所以对于 XML 这个红得发紫的东西,Python 提供了多种模块来处理。

  • xml.dom.* 模块:Document Object Model。适合用于处理 DOM API。它能够将 XML 数据在内存中解析成一个树,然后通过对树的操作来操作 XML。但是这种方式由于将 XML 数据映射到内存中的树,导致比较慢,且消耗更多内存。

  • xml.sax.* 模块:simple API for XML。由于 SAX 以流式读取 XML 文件,从而速度较快,占用内存少,但是在操作上稍微复杂,需要用户实现回调函数。

当然还有一些别的,比如 xml.parse.expat,xml.etree.ElementTree 等等,我就不在列举了,碰到的时候再去查查,否则光看这些东西头就大了,而且无聊的很。

遍历查询

先要做一个 XML 文档,我自己想也想不出个啥太好的来,所以直接用 w3school 中的一个例子,如下图所示:
在这里插入图片描述
上图表示下面的 XML 中的一本书:

    <bookstore>
    <book category="COOKING">
     <title lang="en">Everyday Italian</title> 
     <author>Giada De Laurentiis</author> 
     <year>2005</year> 
     <price>30.00</price> 
    </book>
    <book category="CHILDREN">
     <title lang="en">Harry Potter</title> 
     <author>J K. Rowling</author> 
     <year>2005</year> 
     <price>29.99</price> 
    </book>
    <book category="WEB">
     <title lang="en">Learning XML</title> 
     <author>Erik T. Ray</author> 
     <year>2003</year> 
     <price>39.95</price> 
    </book>
    </bookstore>

将上述的 XML 保存并且命名为 test.xml 文件,接下来就是以它为对象,练习各种操作了。

>>> import xml.etree.ElementTree as ET
>>> tree = ET.ElementTree(file = 'test.xml')
>>> tree
<xml.etree.ElementTree.ElementTree object at 0x00000000025B8630>

上面建立起 XML 解析树对象,然后通过根节点向下开始读取各个元素(element 对象)。

在上述 XML 文档中,根元素是 bookstore,它没有属性,也可以说是属性为空。

>>> root = tree.getroot()
>>> root.tag
'bookstore'
>>> root.attrib
{}

要想将根下面的元素都读取出来,可以进行如下操作:

>>> for child in root:
...    print(child.tag,child.attrib)
...
('book', {'category': 'COOKING'})
('book', {'category': 'CHILDREN'})
('book', {'category': 'WEB'})

也可以像下面这样读取指定元素的信息:

>>> root[0].tag
'book'
>>> root[0].attrib
{'category': 'COOKING'}
>>> root[0].text
'\n  '

上述的 root[0].text 无内容,再深入一层,我们就可以看到内容了:

>>> root[0][0].tag
'title'
>>> root[0][0].attrib
{'lang': 'en'}
>>> root[0][0].text
'Everyday Italian'

对于 ElementTree 对象,有一个 iter() 方法可以对指定名称的子节点进行深度优先遍历,例如下面这样:

>>> for ele in tree.iter(tag='book'):
...    print(ele.tag,ele.attrib)
...
('book', {'category': 'COOKING'})
('book', {'category': 'CHILDREN'})
('book', {'category': 'WEB'})

上述代码是遍历名称为 book 的节点,如果不指定节点的话,就是将所有的元素遍历一遍:

>>> for ele in tree.iter():
...    print(ele.tag,ele.attrib)
...
('bookstore', {})
('book', {'category': 'COOKING'})
('title', {'lang': 'en'})
('author', {})
('year', {})
('price', {})
('book', {'category': 'CHILDREN'})
('title', {'lang': 'en'})
('author', {})
('year', {})
('price', {})
('book', {'category': 'WEB'})
('title', {'lang': 'en'})
('author', {})
('year', {})
('price', {})

除了上面的方法外,还可以通过路径搜索到指定的元素,然后读取其内容,这就是 xpath,关于 xpath 是什么,在这不多做介绍,感兴趣的可以去 Google。

编辑(增删改查)

我们还是用上面的例子,为了方便查看,我把内容再粘贴过来,下面的内容记得保存并且命名为 test.xml。

<bookstore>
<book category="COOKING">
<title lang="en">Everyday Italian</title> 
<author>Giada De Laurentiis</author> 
<year>2005</year> 
<price>30.00</price> 
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title> 
<author>J K. Rowling</author> 
<year>2005</year> 
<price>29.99</price> 
</book>
<book category="WEB">
<title lang="en">Learning XML</title> 
<author>Erik T. Ray</author> 
<year>2003</year> 
<price>39.95</price> 
</book>
</bookstore>

上一篇文章我们主要是对 xml 进行了读取的有关操作,其实还可以对 XML 进行编辑,也就是增删改查的功能,下面我们来操作一下:

>>> import xml.etree.ElementTree as ET
>>> tree = ET.ElementTree(file = "test.xml")
>>> root = tree.getroot() #获得根
>>> root[1].tag
'book'
>>> del root[1]
>>> for ele in root:
...    print(ele.tag)
...
book
book

如上,我们成功的删除了一个节点,原来有 3 个 book 节点,现在就只剩下两个了。接下来让我们打开源文件看看,是不是正好缺少了第 2 个节点呢?结果让我们很失望,源文件并没有什么变化。

确实如此,源文件并没有变,因为到了这一步的修改动作还只是停留在内存里,还没有将修改的结果输出到文件,不要忘记我们是在内存中建立的 ElementTree 对象。那么该如何做呢?请接着往下看:

>>> import os
>>> outpath = os.getcwd()
>>> file = outpath + "/test.xml"

把当前文件的路径拼装好。

>>> tree.write(file)

做完上面的操作以后再去看源文件,已经变成两个节点了。

除了删除,也是可以修改的:

>>> for price in root.iter('price'): #原来每本书的价格
...    print(price.text)
...
30.00
39.95
>>> for price in root.iter('price'): #每本上涨 10 元并做标记
...    new_price = float(price.text) + 10
...    price.text = str(new_price)
...    price.set("updated","up")
...
>>> tree.write(file)

然后我们来查看一下源文件:

<bookstore>
<book category="COOKING">
 <title lang="en">Everyday Italian</title> 
 <author>Giada De Laurentiis</author> 
 <year>2005</year> 
 <price updated="up">50.0</price> 
</book>
<book category="WEB">
 <title lang="en">Learning XML</title> 
 <author>Erik T. Ray</author> 
 <year>2003</year> 
 <price updated="up">49.95</price> 
</book>
</bookstore>

通过对比我们可以发现,不仅价格改变了,而且在 price 标签里面增加了属性标记。

上面我们是用 del 来删除某个元素,其实这个在编程中我们用的并不多,一般情况下更喜欢用 remove() 方法。比如要删除 price = 50 的书,可以像下面这样操作:

>>> tree.write(file)
>>> for book in root.findall("book"):
...    price = book.find("price").text
...    if float(price) == 50:
...            root.remove(book)
...
>>> tree.write(file)

于是就有了下面的结果:

<bookstore>
<book category="WEB">
 <title lang="en">Learning XML</title> 
 <author>Erik T. Ray</author> 
 <year>2003</year> 
 <price updated="up">49.95</price> 
</book>
</bookstore>

接下来我们来看看增加元素:

>>> import xml.etree.ElementTree as ET
>>> tree = ET.ElementTree(file = 'test.xml')
>>> root = tree.getroot()
>>> ET.SubElement(root,"book") # 在root里面添加book节点
<Element 'book' at 0x000000000209C778>
>>> for ele in root:
...     print(ele.tag)
...
book
book
>>> b2 = root[1]
>>> b2.text = 'python'
>>> tree.write('test.xml')

这样就大功告成了,然后再像上面一样看一下源文件,发现果真增加了。

常用的属性 & 方法

ET 里面的属性 & 方法很多,这里列出常用的几个,供使用中备查。

1.Element 对象

常用的属性如下:

  • tag:string,元素数据种类
  • text:string,元素的内容
  • attrib:dictionary,元素的属性字典
  • tail:string,元素的尾形

针对属性的操作如下:

  • clear():清空元素的后代,属性,text 和 tail 也设置为 None。
  • items():根据属性字典返回一个列表,列表元素为(key,value)。
  • keys():返回包含所有元素属性键的列表。
  • set(key,value):设置新的属性键和值。

针对后代的操作如下:

  • append(subelement):添加直系子元素。
  • extend(sunelements):增加一串元素对象作为子元素。
  • find(match):寻找第一个匹配子元素,匹配对象可以为 tag 或 path。
  • findall(match):寻找所有匹配子元素,匹配对象可以为 tag 或 path。
  • insert(index,element):在指定位置插入子元素。
  • remove(subelement):删除子元素

2.ElementTree 对象

  • find(match)。
  • findall(match)。
  • getroot():获取根结点。
  • parse(source,parser = None):装载 XML 对象,source 可以为文件名或文件类型对象。

写在之后

更多内容,欢迎关注公众号「Python空间」,期待和你的交流。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/u013486414/article/details/85448863