第二十一章 解读XML与JSON文件格式(工具)

XML

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

今天要说的 XML 是最突出的处理上述这种转换的标记格式,它使用标签(tag)分隔数据。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 可以为文件名或文件类型对象。

具体使用

  1. 解析XML文件并获取根节点:
import xml.etree.ElementTree as ET

tree = ET.parse('example.xml')
root = tree.getroot()
print(root.tag)
  1. 遍历XML文件的所有节点:
for child in root:
    print(child.tag, child.attrib)
    for subchild in child:
        print(subchild.tag, subchild.text)
  1. 根据标签名查找子节点:
for child in root.iter('tagName'):
    print(child.text)
  1. 根据属性查找节点:
for child in root.findall('.//tagName[@attrName="value"]'):
    print(child.text)
  1. 修改XML文件中的文本内容:
for subchild in root.findall('.//tagName'):
    subchild.text = 'new text'
tree.write('example.xml')
  1. 添加新的子节点:
new_child = ET.Element('tagName')
new_child.text = 'new text'
root.append(new_child)
tree.write('example.xml')
  1. 删除XML文件中的节点:
for child in root.findall('.//tagName'):
    root.remove(child)
tree.write('example.xml')
  1. 创建XML文件并保存到磁盘:
root = ET.Element('root')
child = ET.SubElement(root, 'child')
child.text = 'child text'
tree = ET.ElementTree(root)
tree.write('example.xml')
  1. 解析XML字符串并获取根节点:
xml_string = '<root><child>child text</child></root>'
root = ET.fromstring(xml_string)
print(root.tag)

JSON

就数据传递而言, XML 是一种选择,当然这里还有另一种选择 – 「JSON」。它是一种轻量级的数据交换格式,如果各位想要做 Web 编程的话,则肯定会用到它。下面我们就开始今天的学习。

首先我们参考《维基百科》中的相关内容,来对 JSON 做如下介绍:

JSON ( JavaScript Object Notation )
是一种由道格拉斯构想设计、轻量级的数据交换语言,以文字为基础,且易于让人阅读。尽管 JSON 是 JavaScript 的一个子集,但
JSON 是独立于语言的文本格式,并且采用了类似 C 语言家族的一些习惯。 关于 JSON
更为详细的内容,可以参考其官方网站,在这我截取部分内容,让大家更好的了解一下 JSON 的结构。

JSON 构建于两种结构基础之上:

  • “名称/值”对的集合。不同的语言中,它被理解为对象(object),记录(record),结构(struct),字典(dictionary),哈希表(hash table)等。
  • 值的有序列表。在某些语言中,它被理解为数组(array),类似于 Python 中的类表。

Python 标准库中有 JSON 模块,主要是执行序列化和反序列化功能。

  • 序列化:encoding,把一个 Python 对象编码转化成 JSON 字符串;
  • 反序列化:decoding,把 JSON 格式字符串解码转换为 Python 数据对象。

基本操作

JSON 模块相比于 XML 来说真的是简单多了:

>>> import json
>>> json.__all__
['dump', 'dumps', 'load', 'loads', 'JSONDecoder', 'JSONDecodeError', 'JSONEncoder']

1.encoding:dumps()

>>> data = [{'name':'rocky','like':('python','c++'),'age':23}]
>>> data
[{'name': 'rocky', 'like': ('python', 'c++'), 'age': 23}]
>>> data_json = json.dumps(data)
>>> data_json
'[{"name": "rocky", "like": ["python", "c++"], "age": 23}]'

encoding 的操作比较简单,请仔细观察一下上面代码中 data 和 data_json 的不同:like 的值从元组变成了列表,其实还有不同,请看下面:

>>> type(data)
<class 'list'>
>>> type(data_json)
<class 'str'>

2.decoding:loads()

decoding 的过程其实也像上面那么简单:

>>> new_data = json.loads(data_json)
>>> new_data
[{'name': 'rocky', 'like': ['python', 'c++'], 'age': 23}]

上面需要注意的是,解码之后并没有将值中的列表还原为数组。上面的 data 都不是很长,还能凑活着看,如何很长,阅读其实就很有难度了。所以 JSON 的 dumps() 提供了可选的参数,利用它们能在输入上对人更好,当然这个对机器来说都是无所谓的事情。

>>> data1 = json.dumps(data,sort_keys = True,indent = 2)
>>> print(data1)
[
 {
   "age": 23,
   "like": [
     "python",
     "c++"
   ],
   "name": "rocky"
 }
]

sort_keys = True 的意思是按照键的字典顺序排序;indent = 2 则是让每个键值对显示的时候,以缩进两个字符对齐,这样的视觉效果就好多了。

n)

new_data
[{‘name’: ‘rocky’, ‘like’: [‘python’, ‘c++’], ‘age’: 23}]


上面需要注意的是,解码之后并没有将值中的列表还原为数组。上面的 data 都不是很长,还能凑活着看,如何很长,阅读其实就很有难度了。所以 JSON 的 dumps() 提供了可选的参数,利用它们能在输入上对人更好,当然这个对机器来说都是无所谓的事情。

```text
>>> data1 = json.dumps(data,sort_keys = True,indent = 2)
>>> print(data1)
[
 {
   "age": 23,
   "like": [
     "python",
     "c++"
   ],
   "name": "rocky"
 }
]

sort_keys = True 的意思是按照键的字典顺序排序;indent = 2 则是让每个键值对显示的时候,以缩进两个字符对齐,这样的视觉效果就好多了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/190004.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【深度学习】如何找到最优学习率

经过了大量炼丹的同学都知道&#xff0c;超参数是一个非常玄乎的东西&#xff0c;比如batch size&#xff0c;学习率等&#xff0c;这些东西的设定并没有什么规律和原因&#xff0c;论文中设定的超参数一般都是靠经验决定的。但是超参数往往又特别重要&#xff0c;比如学习率&a…

Seurat Tutorial 1:标准分析流程,基于 PBMC 3K 数据集

目录 1 设置 Seurat 对象2 标准预处理工作流程 2.1 QC 和选择细胞进行进一步分析3 数据归一化4 识别高变特征&#xff08;特征选择&#xff09;5 标准化数据6 执行线性降维7 确定数据集的维度8 细胞聚类9 运行非线性降维 (UMAP/tSNE)10 寻找差异表达特征&#xff08;cluster b…

OSG编程指南<十二>:OSG二三维文字创建及文字特效

1、字体基础知识 适当的文字信息对于显示场景信息是非常重要的。在 OSG 中&#xff0c;osgText提供了向场景中添加文字的强大功能&#xff0c;由于有第三方插件 FreeType 的支持&#xff0c;它完全支持TrueType 字体。很多人可能对 FreeType 和 TrueType 还不太了解&#xff0c…

小程序项目:springboot+vue基本微信小程序的宠物领养系统

项目介绍 当今科技发展迅速&#xff0c;交通环境也变得越来越复杂。人们的出行方式变得多元化&#xff0c;这给视障人士带来了一定的困扰。而导盲犬可以帮助视障人士外出行走&#xff0c;提高他们的生活质量。在我国&#xff0c;导盲犬的数量远远少于视障人士的数量。由于导盲…

WPF绘图技术介绍

作者&#xff1a;令狐掌门 技术交流QQ群&#xff1a;675120140 csdn博客&#xff1a;https://mingshiqiang.blog.csdn.net/ 文章目录 WPF绘图基本用法绘制直线在XAML中绘制直线在C#代码中绘制直线使用Path绘制直线注意 矩形绘制在XAML中绘制矩形在C#代码中绘制矩形设置矩形的位…

<JavaEE> Java中线程有多少种状态(State)?状态之间的关系有什么关系?

目录 一、系统内核中的线程状态 二、Java中的线程状态 一、系统内核中的线程状态 状态说明就绪状态线程已经准备就绪&#xff0c;随时可以接受CPU的调度。阻塞状态线程处于阻塞等待&#xff0c;暂时无法在CPU中执行。 二、Java中的线程状态 相比于系统内核&#xff0c;Java…

火锅店管理系统外卖点餐配送小程序的效果

火锅是餐饮行业重要的组成部分&#xff0c;在每个地方都受到追捧&#xff0c;其从业商家众多&#xff0c;头部连锁品牌也不少&#xff0c;近些年行业市场规模也一直增加&#xff0c;而随着消费升级及数字化转型&#xff0c;传统火锅店经营痛点不少&#xff1a; 火锅店的需求非…

智能优化算法应用:基于蚁狮算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蚁狮算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蚁狮算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蚁狮算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

SpringBoot中如何优雅地使用重试

1 缘起 项目中使用了第三方的服务&#xff0c; 第三方服务偶尔会出现不稳定、连接不上的情况&#xff0c; 于是&#xff0c;在调用时为了保证服务的相对高可用&#xff0c;添加了超时连接重试&#xff0c; 当连接第三方服务超时时&#xff0c;多重试几次&#xff0c;比如3次&a…

XML映射文件

<?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace"org.mybatis.example.BlogMapper&q…

FreeRTOS学习之路,以STM32F103C8T6为实验MCU(2-7:软件定时器)

学习之路主要为FreeRTOS操作系统在STM32F103&#xff08;STM32F103C8T6&#xff09;上的运用&#xff0c;采用的是标准库编程的方式&#xff0c;使用的IDE为KEIL5。 注意&#xff01;&#xff01;&#xff01;本学习之路可以通过购买STM32最小系统板以及部分配件的方式进行学习…

Python大数据考题

Python大数据考题&#xff1a; 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;oracle&#xff0c;尤其sql要…

CDA一级备考思维导图

CDA一级备考思维导图 第一章 数据分析概述与职业操守1、数据分析概念、方法论、角色2、数据分析师职业道德与行为准则3、大数据立法、安全、隐私 CDA一级复习备考资料共计七个章节&#xff0c;如需资料&#xff0c;请留言&#xff0c;概览如下图&#xff1a; 第一章 数据分析…

Spring面向切面编程(AOP);Spring控制反转(IOC);解释一下Spring AOP里面的几个名词;Spring 的 IoC支持哪些功能

文章目录 Spring面向切面编程(AOP)什么是AOPSpring AOP and AspectJ AOP 的区别&#xff1f;Spring AOP中的动态代理如何理解 Spring 中的代理&#xff1f;解释一下Spring AOP里面的几个名词Spring在运行时通知对象Spring切面可以应用5种类型的通知&#xff1a;什么是切面 Aspe…

【数据结构】堆(C语言)

今天我们来学习堆&#xff0c;它也是二叉树的一种&#xff08;我滴神树&#xff01;&#xff09; 目录 堆的介绍&#xff1a;堆的代码实现&#xff1a;堆的结构体创建&#xff1a;堆的初始化&#xff1a;堆的销毁&#xff1a;堆的push&#xff1a;堆的pop&#xff1a;判空 &am…

OpenCV简介及安装

前言 因为最近想做图像处理、人脸检测/识别之类的相关开发&#xff0c;所以就开始补OpenCV的相关知识&#xff0c;便开个专栏用于记录学习历程和在学习过程中遇到的一些值得注意的重点和坑。 学习过程基本上也是面向官方文档和Google。 简介 OpenCV(开源的计算机视觉库)是基于…

十大排序之归并排序(详解)

文章目录 &#x1f412;个人主页&#x1f3c5;算法思维框架&#x1f4d6;前言&#xff1a; &#x1f380;归并排序 时间复杂度O(n*logn)&#x1f387;1. 算法步骤思想&#x1f387;2、动画演示&#x1f387;3.代码实现 &#x1f412;个人主页 &#x1f3c5;算法思维框架 &#…

渗透测试【一】:渗透测试常见问题

渗透测试【一】&#xff1a;渗透测试常见问题 1、问题清单2、问题现象及解决办法2.1、点击劫持2.2、用户枚举2.3、Springboot未授权访问2.4、Swagger未授权访问2.5、Host头注入2.6、任意文件上传2.7、敏感路径泄露2.8、跨域资源共享2.9、Spring Cloud Gateway RCE2.10、Content…

vsVode C++开发远程虚拟机工程配置

在使用VS Code进行C/C的开发过程中&#xff0c;有三个至关重要的配置文件&#xff0c;分别是 tasks.json, launch.json 和 c_cpp_properties.json 1. tasks.json tasks.json 是在 vscode 中辅助程序编译的模块&#xff0c;可以代你执行类似于在命令行输入 “gcc hello.c -o h…

文件搜索工具HoudahSpot mac中文版特点

HoudahSpot mac是一款文件搜索工具&#xff0c;它可以帮助用户快速准确地找到文件和文件夹&#xff0c;支持高级搜索和过滤&#xff0c;同时提供了多种视图和操作选项&#xff0c;方便用户进行文件管理和整理。 HoudahSpot mac软件特点 高级搜索和过滤功能&#xff1a;软件支持…