第18章 数据交换格式

数据交换格式有文本数据交换和二进制数据交换。文本数据交换格式有CSV格式、XML格式和JSON格式。

XML和JSON格式可以自带描述信息,被称为“自描述的”结构化文档。

JSON字节数一般比XML少,因此称为“轻量级”的数据交换格式。

18.1 XML数据交换格式

18.1.1 XML文档结构

标签:描述数据的标识,位于尖括号中的内容(<to>...</to>等)。

标签<to></to>之间的是“称谓”。

标签<content></content>之间是内容。

标签<from></from>之间是“落款”。

标签<date></date>之间是“日期”。

XML在形式上与HTML很像。

XML的基本架构:

1)声明

2)根元素

note是XML文件的根元素,<note>是根元素的开始标签,</note>是根元素的结束标签。根元素只有一个,开始标签和结束标签必须一致。

3)子元素

to、content、from和date是根元素note的子元素。所有元素都要有结束标签,开始标签和结束标签必须一致。如果开始标签和结束标签之间没有内容,可以写成<from/>,称为“空标签”。

4)属性

属性定义在开始标签中,在开始标签<Noted id="1">中, id="1"是Note元素的一个属性,id是属性名,1是属性值,属性值必须放在双引号或单引号之间。一个元素不能有多个相同名字的属性。

5)命名空间

用于为XML文档提供名字唯一的元素和属性。例如在一个学籍信息的XML文档中都需要id,直接引用会冲突,但是放在不同的命名空间就会解决。

下图以xmlns:开头的内容都属于命名空间。

6)限定名

由命名空间引出的概念,定义了元素和属性的合法标识符。在XML文档中通常用作特定元素或属性引用。上图标签<soap:Body>就是合法的限定名,前缀soap是由命名空间定义的。

18.1.2 解析XML文档

XML文档操作有读和写,读入XML文档并解析的过程称为“解析”。有两种模式:SAX和DOM。

๏ SAX(Simple API for XML)是一种基于事件驱动的解析模式。解析 XML文档时,程序从上到下读取XML文档,如果遇到开始标签、结束标签和属性等,就会触发相应的事件。只能读取XML文档,不能写入XML文档。解析速度快。

๏ DOM(Document Object Model)将XML文档作为一棵树状结构进行分析,获取节点的内容以及相关属性,或是新增、删除和修改节点的内容。XML解析器在加载XML文件以后,DOM模式将XML文件的元素视为一个树状结构的节点,一次性读入内存。能修改XML文档,但是文档大,解析速度慢。

Python也提供了兼顾SAX和DOX优点的XML模块--ElementTree。

使用python创建xml代码。

#encoding:utf-8
'''
根据一个给定的XML Schema,使用DOM树的形式从空白文件生成一个XML。
'''
from xml.dom.minidom import Document
doc = Document()  #创建DOM文档对象
DOCUMENT = doc.createElement('DOCUMENT') #创建根元素
DOCUMENT.setAttribute('content_method',"full")#设置命名空间
#DOCUMENT.setAttribute('xsi:noNamespaceSchemaLocation','DOCUMENT.xsd')#引用本地XML Schema
doc.appendChild(DOCUMENT)
############item:Python处理XML之Minidom################
item = doc.createElement('item')
#item.setAttribute('genre','XML')
DOCUMENT.appendChild(item)
key = doc.createElement('key')

key_text = doc.createTextNode('Key1') #元素内容写入
key.appendChild(key_text)
item.appendChild(key)
display = doc.createElement('display')
item.appendChild(display)
display_url = doc.createElement('url')
display_title  = doc.createElement('title')
display_url_text = doc.createTextNode('https://www.baidu.com/')
display_title_text  = doc.createTextNode('哈哈')
display.appendChild(display_url)
display.appendChild(display_title)
display_url.appendChild(display_url_text)
display_title.appendChild(display_title_text)
item.appendChild(display)
'''
price = doc.createElement('price')
price_text = doc.createTextNode('28')
price.appendChild(price_text)
item.appendChild(price)
'''
########### 将DOM对象doc写入文件
f = open('Notes.xml','w')
#f.write(doc.toprettyxml(indent = '\t', newl = '\n', encoding = 'utf-8'))
doc.writexml(f,indent = '\t',newl = '\n', addindent = '\t',encoding='utf-8')
f.close()
import xml.etree.ElementTree as ET  # 导入xml.etree.ElementTree模块

tree = ET.parse('Notes.xml')   # parse()函数创建XML文档树
print(type(tree))   # xml.etree.ElementTree.ElementTree,表示整个XML文档树

root = tree.getroot()   # root是根元素,tree.getroot()是从tree获得它的根元素
print(type(root))   # xml.etree.ElementTree.Element
print(root.tag)    # Notes

for index, child in enumerate(root):
    print('第{0}个{1}元素,属性:{2}'.format(index, child.tag, child.attrib))
    for i, child_child in enumerate(child):
        print('     标签:{0},内容:{1}'.format(child_child.tag, child_child.text))
# tag属性可以获得当前元素的标签名
# enumerate()函数可以获得循环变量index,注意此时的child是Note元素
# child.attrib是获得当前元素的属性,返回属性和值的字典
# child_child.tag是获得子元素的标签名,child_child.text是获得子元素的文本内容

 18.1.3 使用XPath

18.1.2的示例是从根元素开始遍历整个XML文档。实际开发,还需要查找某些特殊元素和特殊属性。需要使用xml.etree.ElementTree.Element的相关find方法,还要结合XPath(专门用来在XML文档中查找信息的语言)匹配查找。

相关find方法有三种:

๏ find(match, namespaces=None)。查找匹配的第一个子元素。match可以是标签名或XPath。返回元素对象或None。namespaces是指定命名空间,如果namespaces非空,那么查找会在指定的命名空间的标签中进行。

๏ findall(match, namespaces=None)。查找所有匹配的子元素,参数同 find()方法。返回值是符合条件的元素列表。

๏ findtext(match, default=None, namespaces=None)。查找匹配的第一 个子元素的文本,如果未找到元素,则返回默认。default参数是默认值, 其他参数同find()方法。

Xpath将XML中的所有元素,属性和文本都看作节点(Node),根元素就是根节点,它就没有父节点,属性称为节点属性,文本称为文本节点。除了根节点外,其他节点都有一个父节点,零或多个子节点和兄弟节点。

XPath提供了由特殊符号组成的表达式。

import xml.etree.ElementTree as ET  # 导入xml.etree.ElementTree模块

tree = ET.parse('Notes.xml')
root = tree.getroot()

node = root.find("./Note")  # 当前节点的第一个Note子节点
print(node.tag, node.attrib)
node = root.find("./Note/CDate")    # Note子节点下的第一个CDate节点
print(node.text)
node = root.find("./Note/CDate/..")    # Note节点
print(node.tag, node.attrib)
node = root.find(".//CDate")    # 当前节点查找所有后代节点中第一个CDate节点
print(node.text)

node = root.find("./Note[@id]") # 具有id属性Note节点
print(node.tag, node.attrib)

node = root.find("./Note[@id='2']") # id属性等于'2'Note节点
print(node.tag, node.attrib)

node = root.find("./Note[2]") # 第二个Note节点
print(node.tag, node.attrib)

node = root.find("./Note[last()]") # 最后一个Note节点
print(node.tag, node.attrib)

node = root.find("./Note[last()-2]")    #倒数第三个Note节点
print(node.tag, node.attrib)

18.2 JSON数据交换格式

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,速度快。

18.2.1 JSON文档结构

JSON文档类型的结构有两个:对象(object)和数组(array)。对象是“名称:值”对集合,类似于Python中的Map类型。以“{”开始,“}”结束。“名称:值”对之间用“,”名称是字符串类型(string),值可以是任何合法的JSON类型。

JSON数组是值的有序集合。以“[”开始,“]”结束。

JSON中的值可以是双引号括起来的字符串、数字、true、false、null、对象或数组,这些结构可以嵌套。

数值中的值的JSON语法结构。

18.2.2 JSON数据编码 

编码:将Python数据网络传输和存储,可以将Python数据转换为JSON数据再进行传输和存储。

JSON编码使用dumps()和dump()函数,dumps()将编码结果以字符串形式返回,dump()将结果保存到文件对象(类似文件对象或流) 。

import json

# 准备数据
py_dict = {'name': 'tony', 'age': 30, 'sex':True}   # 创建字典对象
py_list = [1, 3]    # 创建列表对象
py_tuple = ('A', 'B', 'C')  # 创建元组对象

py_dict['a'] = py_list  # 添加列表到字典中
py_dict['b'] = py_tuple # 田间元组到字典中

print(py_dict)
print(type(py_dict))    # <class 'dict'>

# 编码过程
json_obj = json.dumps(py_dict)
print(json_obj)
print(type(json_obj))   # <class 'str'>

# 编码过程
json_obj = json.dumps(py_dict, indent=4)
# 漂亮的格式化字符串后输出
print(json_obj)

# 写入JSON数据到data1.json文件
with open('data1.json', 'w') as f:
    json.dump(py_dict, f)

# 写入JSON数据到data2.json文件
with open('data2.json', 'w') as f:
    json.dump(py_dict, f, indent=4)

 

dumps()函数使用indent,indent可以格式化字符串,indent =4表示缩进4个空格。主要用来日志输出和显示,但不适合网络传输和保存。

18.2.3 JSON数据解码

从网络接受或从磁盘读取JSON数据时,需要转码为Python数据。

json模块提供的解码函数是loads()和load()。loads()将JSON字符串数据进行解码,返回Python数据。load()读取文件或流,对其中的JSON数据进行解码,返回结果为Python数据。

import json

# 准备数据
json_obj = r'{"name": "tony", "age": 30, "sex": true, "a": [1, 3], "b": ["A", "B", "C"]}'

py_dict = json.loads(json_obj)
print(type(py_dict))    # <class 'dict'>
print(py_dict['name'])
print(py_dict['age'])
print(py_dict['sex'])

py_lista = py_dict['a'] # 取出列表对象
print(py_lista)

py_listb = py_dict['b'] # 取出列表对象
print(py_listb)

# 读取JSON数据到data3.json文件
with open('data2.json', 'r') as f:
    data = json.load(f)
    print(data)
    print(type(data))   # <class 'dict'>

注意:按照规范的JSON文档要求,每一个JSON数据项的“名称”都必须使用双引号括起来,而且数值中的字符串也必须使用双引号括起来。 

 

  • 26
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值