第十二章 json字符串和xml解析
1 json
1.1 json简介
Json全称:Javasript Object Notation(javascrip对象表示法)
Json是存储和交换文本信息的语法。类似xml
Json比xml更小、更快、更易解析
1.2 json语法和语法规则
1、json语法:Json语法是javascrip语法的子集。
2、json语法规则:json语法是javascript对象表示法语法的子集。
数据在名称/值对中,“name”:“cc” 等价于 name:“cc”
Json值类型可以是:int、float 、str、bool 、数组、对象、null
数据由逗号分隔
花括号保存对象
对象可以包含多个名称/值对,比如:{“name”:”cc”,”age”:18}
方括号保存数组
数组可以包含多个对象,比如:
{
“employees”:[
{“name”:”cc”,”age”:18},
{“name”:”zz”,”age”:20}
]
}
1.3 json编码
1、使用json.dumps()将一个python数据类型列表编码成json格式的字符串。
>>> import json
>>> data=[{"a":"A","b":(2,3),"c":3.3}]
>>> data
[{'a': 'A', 'b': (2, 3), 'c': 3.3}]
>>> type(data)
<class 'list'>
>>> json.dumps(data)
'[{"a": "A", "b": [2, 3], "c": 3.3}]' #编译为json串后,元组类型改为json数组
2、函数原型:
dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True,
cls=None, indent=None, separators=None, encoding=‘utf-8’, default=None,
sort_keys=False, **kw)
3、函数参数如下:
(1) sort_keys:是否按字典排序(a到z)输出,默认False不排序。
>>> import json
>>> data=[{"a":"A","x":[1,2],"f":666}]
>>> json.dumps(data,sort_keys=True)
'[{"a": "A", "f": 666, "x": [1, 2]}]'
(2) indent:
>>> import json
>>> data=[{"a":"A","x":[1,2],"f":666}]
>>> print(json.dumps(data,indent=3))
[
{
"a": "A",
"x": [
1,
2
],
"f": 666
}
]
(3) separators:去掉逗号和冒号后面的空格。不带该参数的结果能看到逗号和冒号后都有个空格,这是为了美化输出结果,但是在传输过程中越精简越好。
>>> data=[{"a":"A","x":[1,2],"f":666}]
>>> json.dumps(data,separators=(",",":"))
'[{"a":"A","x":[1,2],"f":666}]'
>>> data=[{"a":"A","x":[1,2],"f":666}]
>>> len(json.dumps(data))
35
>>> len(json.dumps(data,separators=(",",":")))
29
(4) skipkeys:dict对象的key只能是基本数据类型(str,int,float,bool,None),如果是其他类型,在编码过程中会抛出TypeError异常。该参数默认为False,设置为True可以跳过这些抛出异常的key,不处理。
>>> data=[{"a":"A","x":[1,2],"f":666,(1,2):(1,2)}]
>>> json.dumps(data)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "D:\App\Python37\lib\json\__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "D:\App\Python37\lib\json\encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "D:\App\Python37\lib\json\encoder.py", line 257, in iterencode
return _iterencode(o, 0)
TypeError: keys must be str, int, float, bool or None, not tuple
>>> json.dumps(data,skipkeys=True)
'[{"a": "A", "x": [1, 2], "f": 666}]'
(5) ensure_ascii:编码使用的字符集,默认使用ascii编码。设置为False,就会以Unicode进行编码
>>> data=[{"country":"中国","name":"程程"}]
>>> json.dumps(data)
'[{"country": "\\u4e2d\\u56fd", "name": "\\u7a0b\\u7a0b"}]'
>>> json.dumps(data,ensure_ascii=False)
'[{"country": "中国", "name": "程程"}]'
1.4 json解码
将json格式字符串解码为python对象,使用json.loads()。
>>> data=[{"a":"A","x":(1,2),"f":666}]
>>> data_json=json.dumps(data)
>>> data_json
'[{"a": "A", "x": [1, 2], "f": 666}]'
>>> data_py=json.loads(data_json)
>>> data_py #原来是tuple,经过json的编码解码,最终被转为list
[{'a': 'A', 'x': [1, 2], 'f': 666}]
1.5 json串与python数据类型的转换
Python类型 Json类型 Python类型
dict object dict
list tuple array list
str unicode string str unicode
int float Number(int) int float
True False true false True False
None null None
>>> data=[{1:2,"n":"c","a":1.33},[1,2],(3,4),"abc",1,3.3,True,False,None] #python
>>> data_json=json.dumps(data)
>>> data_json
'[{"1": 2, "n": "c", "a": 1.33}, [1, 2], [3, 4], "abc", 1, 3.3, true, false, null]' #json
>>> data_py=json.loads(data_json)
>>> data_py
[{'1': 2, 'n': 'c', 'a': 1.33}, [1, 2], [3, 4], 'abc', 1, 3.3, True, False, None] #python
1.6 将类对象编码成json串
Python中的dict对象可以直接序列化为json的{},但是很多时候,可能用class表示对象,比如定义Employee类,然后直接去序列化就会报错,是因为类不是一个可以直接序列化的对象,但我们可以使用dumps()函数中的default参数来实现。
import json
class Employee:
def __init__(self,name,age,gender):
self.name=name
self.age=age
self.gender=gender
def obj_json(self,obj_instance):
return {
"name":obj_instance.name,
"age":obj_instance.age,
"gender":obj_instance.gender
}
emp=Employee("cc",18,"女")
print(json.dumps(emp,ensure_ascii=False,default=emp.obj_json))
import json
class Employee:
def __init__(self,name,age,gender):
self.name=name
self.age=age
self.gender=gender
def obj_json(self):
return {
"name":self.name,
"age":self.age,
"gender":self.gender
}
emp=Employee("cc",18,"女")
print(json.dumps(emp.obj_json(),ensure_ascii=False))
1.7 json反序列化为类对象
使用json.loads()函数中object_hook参数实现。
import json
class Employee:
def __init__(self,name,age,gender):
self.name=name
self.age=age
self.gender=gender
emp=Employee("cc",18,"女")
def json_to_class(emp):
return Employee(emp["name"],emp["age"],emp["gender"])
json_str='{"name":"cc","age":18,"gender":"女"}'
e=json.loads(json_str,object_hook=json_to_class)
print(e)
print(e.name)
2 xml
2.1 xml简介
2.2 xml文档(树结构)
2.3 xml基础知识介绍
2.4 xml命名规则
2.5 python解析xml的三种方法
1、SAX
2、DOM
3、ElementTree
2.5.1 xml.dom解析xml
思路:一个DOM的解析器在解析一个xml文档时,一次性读取整个文档,将文档中所有元素保存在内存中的一个树结构里,之后利用DOM提供的不同函数来读取该文档的内容和结构,也可以把修改过的内容写入xml文件。
Xml实例(创建一个book.xml文件,内容如下)
<?xml version="1.0" encoding="utf-8" ?>
<!--this is a test about xml.-->
<booklist type="science and engineering">
<book category="math">
<title>learning math</title>
<author>张三</author>
<pageNumber>561</pageNumber>
</book>
<book category="Python">
<title>learning Python</title>
<author>李四</author>
<pageNumber>600</pageNumber>
</book>
</booklist>
(1)使用parse解析器打开xml文档,并将其解析为DOM文档,也就是内存中的一棵树,并得到这个DOM对象
>>> from xml.dom.minidom import parse
>>> dom_tree=parse("d:\\2019\\book.xml") #打开xml并解析为内存中的一棵树
>>> print(dom_tree)
<xml.dom.minidom.Document object at 0x00000223F1275A68>
>>> print(type(dom_tree))
<class 'xml.dom.minidom.Document'>
(2)获取xml文档对象,就是拿到DOM树的根
>>> booklist=dom_tree.documentElement
>>> print(booklist)
<DOM Element: booklist at 0x223f110b188>
(3)获取xml文档函数doc.toxml(encoding=None)
>>> print(dom_tree.toxml())
<?xml version="1.0" ?><!--this is a test about xml.--><booklist type="science and engineering">
<book category="math">
<title>learning math</title>
<author>张三</author>
<pageNumber>561</pageNumber>
</book>
<book category="Python">
<title>learning Python</title>
<author>李四</author>
<pageNumber>600</pageNumber>
</book>
</booklist>
(4)判断是否包含属性
>>> if booklist.hasAttribute("type"):性")
... print("booklist元素存在type属性")
... else:
... print("booklist元素不存在type属性"))
...
booklist元素存在type属性
(5)获取属性(获取节点node的某个属性的值)
>>> if booklist.hasAttribute("type"):性")")
... print("Root element is",booklist.getAttribute("type"))
...
Root element is science and engineering
(6)获取节点元素
获取xml文档中某个父节点下具有相同节点名的节点对象,是一个list对象
>>> books=booklist.getElementsByTagName("book")
>>> print(books)
[<DOM Element: book at 0x223f110b548>, <DOM Element: book at 0x223f1290188>]
>>> print(type(books))
<class 'xml.dom.minicompat.NodeList'>
返回节点node下所有子节点组成的list
>>> print(books[0].childNodes)
[<DOM Text node "'\n '">, <DOM Element: title at 0x223f110bf48>, <DOM Text node "'\n '">, <DOM Element: author at 0x223f1290048>, <DOM Text node "'\n '">, <DOM Element: pageNumber at 0x223f12900e8>, <DOM Text node "'\n '">]
from xml.dom.minidom import parse
#minidom解析器打开xml文档并将其解析为内存中的一棵树
DOMTree = parse("d:\\2019\\book.xml")
print(type(DOMTree))
booklist = DOMTree.documentElement
print(booklist)
print("*"*30)
books = booklist.getElementsByTagName("book")
d={}
for i in range(1,6,2):
tag_name = books[1].childNodes[i].tagName
d[tag_name]=books[1].childNodes[i].childNodes[0].data
print(d)
for k,v in d.items():
print(k,v)
(7)获取节点文本值(获取节点node的文本值,即标签之间的文本内容)
>>> import json
>>> from xml.dom.minidom import parse
>>> dom_tree=parse("d:\\2019\\book.xml")
>>> booklist=dom_tree.documentElement
>>> books=booklist.getElementsByTagName("book")
>>> books.length
2
>>> for book in books:
... print("********book********")
... if book.hasAttribute("category"):
... print("category is",book.getAttribute("category"))
...
********book********
category is math
********book********
category is Python
>>> title=book.getElementsByTagName("title")
>>> title
[<DOM Element: title at 0x265945935e8>]
>>> title=book.getElementsByTagName("title")[0]
>>> title
<DOM Element: title at 0x265945935e8>
>>> title.childNodes[0].data
'learning Python'
>>> author=book.getElementsByTagName("author")[0]
>>> author.childNodes[0].data
'李四'
>>> pageNumber=book.getElementsByTagName("pageNumber")[0]
>>> pageNumber.childNodes[0].data
'600'
(8)判断是否有子节点
判断节点node下是否有子节点,如果有返回True,否则返回False。但需要注意,每个节点都默认有一个文本子节点,所以只要标签后有值,就返回True,只有当标签后没值时并且也没有子节点时才会返回False。
>>> if books[0].hasChildNodes():
... print("存在子节点",books[0].childNodes)
... else:
... print("不存在子节点")
...
存在子节点 [<DOM Text node "'\n '">, <DOM Element: title at 0x26594593368>, <DOM Text node "'\n '">, <DOM Element: author at 0x26594593408>, <DOM Text node "'\n '">, <DOM Element: pageNumber at 0x265945934a8>, <DOM Text node "'\n '">]
2.5.2 xml.dom创建xml文件
1、创建空白文档
doc=Document()
该方法用于创建一个空白的xml文档对象,并返回这个doc对象
每个xml文档都是一个Document对象,代表着内存中的DOM树
>>> from xml.dom.minidom import Document
>>> doc=Document() #在内存中创建一个空的文档
>>> doc
<xml.dom.minidom.Document object at 0x00000265945E1FA8>
2、创建xml文档节点
doc.createElement(tagName) tagName—生成节点的名称
>>> root=doc.createElement("companys") #创建根节点companys
>>> root.tagName
'companys'
>>> company=doc.createElement("gloryroad") #创建子节点gloryroad
>>> name=doc.createElement("Name") #创建子节点Name
>>> ceo=doc.createElement("CEO") #创建子节点CEO
3、添加节点属性
Node.setAttribute(attName,value) 给节点添加属性值对,attName—属性名称 value—属性值
>>> root.setAttribute("name","公司列表") #给根节点root添加属性
>>> company.setAttribute("name","公司1") #给子节点company添加属性
>>> root.getAttribute("name")
'公司列表'
4、添加文本节点
doc.createTextNode(data)
>>> name_data=doc.createTextNode("光荣之路")
>>> ceo_data=doc.createTextNode("吴老师")
>>> name.appendChild(name_data)
<DOM Text node "'光荣之路'">
>>> ceo.appendChild(ceo_data)
<DOM Text node "'吴老师'">
5、添加子节点
doc/parentNode.appendChild(node)
将节点node添加到文档对象doc作为文档树的根节点或者添加到父节点parentNode下作为其子节点。
>>> doc.appendChild(root)
<DOM Element: companys at 0x26594593f48>
>>> company.appendChild(name)
<DOM Element: Name at 0x265945f7048>
>>> company.appendChild(ceo)
<DOM Element: CEO at 0x265945f7368>
>>> root.appendChild(company)
<DOM Element: gloryroad at 0x265945937c8>
6、生成xml文档
doc.writexml(fp,indent=’’,addindent=’’,newl=’’,encoding=None)
该方法用于将内存中xml文档树写入文件中,并保存到本地磁盘。
fp—文件对象 indent—根节点缩进方式 addindent—子节点缩进方式 newl—换行方式
>>> fp=open("d:\\2019\\school.xml","w",encoding="utf-8")
>>> doc.writexml(fp,indent='',addindent='\t',newl='\n',encoding='utf-8')
>>> fp.close()
7、结果
<?xml version="1.0" encoding="utf-8"?>
<companys name="公司列表">
<gloryroad name="公司1">
<Name>光荣之路</Name>
<CEO>吴老师</CEO>
</gloryroad>
</companys>