第1关:JSON篇:JSON基础知识
任务描述
本关任务:手动编写一个 JSON 格式的数据文件。
相关知识
JSON 全称:JavaScript Object Notation(JavaScript 对象表示法),是一种轻量级的文本数据交换格式。与接下来要介绍的 XML 相比,拥有更小、更快、更易解析的特点。
一个典型的 JSON 格式的字符串如下:

{
"students": 
    [
        { "name":"赵昊" , "age": 15 }, 
        { "name":"龙傲天" , "age": 16 }, 
        { "name":"叶良辰" , "age": 17 }
    ]
}

可以看到其结构和 Python 的list、dict有点相似。
数据表示
JSON 中数据都以名称:值的形式表示,名称包括在一对双引号" "中,值则有多种形式,多条数据之间用逗号,隔开,比如:

"name":"赵昊"
"name":"赵昊","age":15

这种表示方式与 Python 的dict类似。
数据类型
JSON 的值可以是如下类型:
字符串(在双引号中)
数字(整数或浮点数)
逻辑值(true 或 false)
数组(在中括号中)
对象(在大括号中)
null
比如:

"name":"赵昊" , "age":15 , "height":170.5 , "ismale" : false , "house":null

数组
JSON 的数组用一对方括号[]表示,类似于list,数组元素用逗号,隔开,元素值可以是任意 JSON 数据类型,比如:

"names":["赵昊","龙傲天","叶良辰"]
"ages":[15,16,17]

对象
JSON 的对象用一对大括号{}表示,类似于dict,对象可以拥有多个名称/值 对,名称/值 对用逗号,隔开,比如:

"first":{ "name":"赵昊" , "age": 15 }

编程要求
根据提示,在右文件中补充代码,创建一个 JSON 格式的字符串,创建完成后,记得删除第一行提示语,要求:
返回的 JSON 字符串代表一个对象
对象的属性有:
students:一个数组,包含三个学生对象
count:学生的数量,在这里是3个
学生对象的属性:
名称name,字符串类型
年龄age,number(int)类型
是否为男性ismale,逻辑值类型
三个学生对象的数据:
名称:赵昊,年龄:15,男性
名称:龙傲天,年龄:16,男性
名称:玛丽苏,年龄:15,女性
测试说明
测试代码会解析这个文件内的 JSON 字符串,并将其中的数据打印出来。
如果文件成功解析而且数据填写正确,将会有如下结果输出:
学生数:3
名称:赵昊,年龄:15,男性
名称:龙傲天,年龄:16,男性
名称:玛丽苏,年龄:15,女性
开始你的任务吧,祝你成功!
参考代码:

{
    "students":[
        {
            "name":"赵昊",
            "age":15,
            "ismale":true
        },
        {
            "name":"龙傲天",
            "age":16,
            "ismale":true  
        },
        {
            "name":"玛丽苏",
            "age":15,
            "ismale":false
        }
    ],
    "count":3
}

第2关:JSON篇:使用json库
任务描述
本关任务:编写一个能读取并修改 JSON 数据的程序。
相关知识
json库是 Python 内置的一个用于操作 JSON 数据的库,提供了几个函数用于解析与生成(或者说反序列化与序列化)JSON 格式的数据。
解析 JSON 数据
json库提供了一个函数loads,用于从 Python 的字符串中解析 JSON 数据。使用它的方法很简单,只需将含有 JSON 数据的字符串当做参数传递给它,它的返回值就是由 Python 中的基础数据类型组成的对象。

import json
data = '{"a":1,"b":2,"c":3,"d":4,"e":5}';
text = json.loads(data)
print(text)

得到的结果是:
{‘a’: 1, ‘b’: 2, ‘c’: 3, ‘d’: 4, ‘e’: 5}
JSON 的对象类型转换成了 Python 的dict类型。
JSON 各种数据类型在解析后,对应的 Python 基础数据类型如下表:
在这里插入图片描述
JSON 数据类型转化成 Python 数据类型后,就可以按照 Python 的方式来使用了:

import json
data = '[1,2,3]';
text = json.loads(data)
text.append(4) #调用list的append函数
print(text)

得到的结果是:
[1, 2, 3, 4]
如果需要以不同的字符编码来解析,可以指定 encoding参数,比如:

import json
data = '{"a":1,"b":2,"c":3,"d":4,"e":5}';
text = json.loads(data,encoding = "utf-8")
print(text)

上面的代码以utf-8的字符编码,解析data字符串的数据。
注意:如果字符编码指定错误,有可能会导致解析失败,引发异常。
json库的另一个函数load也是用于解析 JSON 数据的,它与loads函数唯一不同的地方在于,它是从文件中解析,比如:

import json
data = open("test.txt","r",encoding = "utf-8")
text = json.load(data) #将文件对象传递给load函数
print(text)
fp.close()

这样test.txt文件内的内容,就会被当做 JSON 格式的数据来解析。
注意:load函数没有可选参数encoding,只要文件对象使用了正确的字符编码打开文件,load函数就可以正确的解析数据。
生成 JSON 数据
与解析的那两个函数相对应,json库也提供了两个函数:dumps和dump,来将由 Python 基础数据类型组成的对象转化成 JSON 数据,使用方法也类似:

import json
data = [ { 'a' : 1, 'b' : 2, 'c' : 3, 'd' : 4, 'e' : 5 } ]
json = json.dumps(data) #转化成JSON格式的字符串
print(json)

得到的结果是:
[{“a”: 1, “b”: 2, “c”: 3, “d”: 4, “e”: 5}]
注意,这是一个字符串。
同样,在转化的时候,也有一个 Python 基础数据类型到 JSON 数据类型的对应表格:
在这里插入图片描述
注意:dumps没有可选参数encoding,当要转化的对象含有中文等非 ASCII 字符时,建议指定可选参数ensure_ascii为False。否则非 ASCII 的字符将会被显示成\uXXXX的形式:

data = {"name":"小明"}
print(json.dumps(data)) #ensure_ascii默认值为True
print(json.dumps(data,ensure_ascii= False)) #指定ensure_ascii为False

上面的代码的结果:
{“name”: “\u5c0f\u660e”}
{“name”: “小明”}
使用dump函数直接输出到文件也很简单,只需多传递一个文件对象作为参数。

import json
fp = open("test.txt","w")
data = [ { 'a' : 1, 'b' : 2, 'c' : 3, 'd' : 4, 'e' : 5 } ]
json.dump(data,fp) #转化成JSON格式的字符串后输出到文件
fp.close()

test.txt文件的内容:
[{“a”: 1, “b”: 2, “c”: 3, “d”: 4, “e”: 5}]
dump函数同样也没有可选参数encoding,如果有数据中有中文字符等非 ASCII 字符时,建议指定可选参数ensure_ascii为False。
编程要求
根据提示,在右侧编辑器Begin-End区间补充代码,实现以下功能:
有一个字符编码为utf-8的数据文件step2/2017.txt:

{"count":3 , 
    "infos":
    [
        {"name":"赵昊" , "age":15 ,"height": 1.83, "sex" : "男性" },
        {"name":"龙傲天" , "age":16 ,"height": 2.00, "sex" : "男性"},
        {"name":"玛丽苏" , "age":15 ,"height": 1.78, "sex" : "女性"}
    ]
}

将其按 JSON 格式解析后,将infos数组内的三个对象的年龄age增加一岁,然后增加一条记录:
名称:叶良辰,年龄:17,身高:1.87,男性
同时,将count的值从3改为4。
注意:所有打开的文件,请在打开文件的函数内及时关闭,以免影响测试代码读取数据。
测试说明
测试代码会以 JSON 格式解析step2/2018.txt的内容,并将其中的数据打印出来。
如果内容成功解析,并且数据填写正确,将会有如下结果输出:
学生数:4
名称:赵昊,年龄:16,身高:1.83,男性
名称:龙傲天,年龄:17,身高:2.00,男性
名称:玛丽苏,年龄:16,身高:1.78,女性
名称:叶良辰,年龄:17,身高:1.87,男性
开始你的任务吧,祝你成功!
参考代码:

import json
def Func():
    data = open("step2/2017.txt","r",encoding = "utf-8")
    obj = json.load(data)
    data.close()
    #********** Begin *********#
    infos = obj['infos']
    for stu in range(len(infos)):
        infos[stu]['age']+=1
    infos.append({'name':'叶良辰','age':17,'height':1.87,'sex':'男性'})
    obj = {
        'count':4,
        'infos':infos
    }
    #********** End **********#
    output = open("step2/2018.txt","w",encoding = "utf-8")
    json.dump(obj,output) #输出到文件
    output.close()

第3关:XML篇:XML基础知识
任务描述
本关任务:手动编写一个 XML 格式的数据文件。
相关知识
XML 全称可扩展标记语言(EXtensible Markup Language),是一种用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型。
一个典型的 XML 文件结构如下:

<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

XML 的声明
XML 文档的声明是可选的,如果要声明,需要将其放在文档的第一行最顶端。

<?xml version="1.0" encoding="utf-8"?>

以上定义了 XML 的版本1.0和所使用的编码utf-8。
元素
XML 元素指的是 XML 文件中出现的标签,一个标签分为开始标签和结束标签,结束标签与开始标签名称相同,只是要在前面加一个斜杠/,比如:

<hello></hello>
<to></to>

一个标签中也可以嵌套其他的若干个子标签。但所有的标签必须合理的嵌套,绝不允许交叉嵌套,比如:

<student>
    <name>赵昊</name>
    <age>16</age>
</student>

以上是一个正确嵌套的例子。
格式良好的 XML 文档必须有且仅有一个根元素,其他的元素都是这个元素的子孙元素。
元素的命名规则:
名称可以包含字母、数字以及其他的字符
名称不能以数字或者标点符号开始
名称不能以字母 xml(或者 XML、Xml 等等)开始
名称不能包含空格
名称是大小写敏感的
XML 没有保留字,元素名称可以任意使用。

<hello></hello>
<F12></F12>
<if></if>
<!--上面这些都是合理的名称-->
<!--下面这些都是不合理的名称-->
<.123></.123>
<A D></A D>
<hello></Hello> <!-- 这一个是因为开始标记(hello)和结束标记(Hello)名称不同 -->

属性
一个元素可以有多个属性,每个属性都有它自己的名称和取值。同一个元素下,属性名称不能重复。属性的值一定要用双引号或者单引号括起来,比如:

<date year="2018" month="7" day="28"></date>

以上是一个格式正确的例子。
属性的命名规范和元素的命名规范一样。
注释
XML 文件中注释采用:<!--注释内容--> 这样的格式,注释没有结束标签,不能嵌套。举例如下:

<!--一个正确的注释1-->
<hello>
<!--一个正确的注释2-->
</hello>
<!--<!--一个发生嵌套的错误的注释-->-->

编程要求
根据提示,在右侧编辑器的文件中手动编写一个 XML 文件,要求:
附带文档声明,使用 XML 版本1.0,字符编码为utf-8;
文档有一个根元素data,根元素有一个属性count,值为3;
根元素有三个student子元素,代表三个学生对象,每个子元素都有三个属性name,age,sex(值为男性或者女性),它们的值由下面的数据得来。
三个学生对象的数据:
名称:赵昊,年龄:15,男性
名称:龙傲天,年龄:16,男性
名称:玛丽苏,年龄:15,女性
提示:代码补充完毕,记得删除第一行提示语。
测试说明
测试代码会以 XML 格式解析这个文件的内容,并将其中的数据打印出来。
如果内容解析成功而且数据填写正确,将会有如下结果输出:
学生数:3
名称:赵昊,年龄:15,男性
名称:龙傲天,年龄:16,男性
名称:玛丽苏,年龄:15,女性
开始你的任务吧,祝你成功!
参考代码:

<?xml version="1.0" encoding="UTF-8"?>
<data count="3">
<student name="赵昊" age="15" sex="男性"></student>
<student name="龙傲天" age="16" sex="男性"></student>
<student name="玛丽苏" age="15" sex="女性"></student>
</data>

第4关:XML篇:使用SAX库解析XML
任务描述
本关任务:解析 XML 文件,输出个人信息。
相关知识
SAX是一种基于事件驱动的 API,使用SAX解析 XML 时,主要分两个部分:解析器和事件处理器。
解析器
解析器负责读取 XML 文档,并向事件处理器发送事件,比如元素开始跟元素结束事件。
SAX提供了两个函数:parse和parseString。前者用于从文件中解析 XML 数据,后者用于从字符串中解析 XML 数据。
两个函数的声明如下:

xml.sax.parse( xmlfile, contenthandler)
xml.sax.parseString(xmlstring, contenthandler)

parse函数的第一个参数是 XML 文件的路径,比如:

xml.sax.parse("test.xml",contenthandler)

parseString函数的第一个参数是,含有 XML 数据的字符串,比如:

data = "<data>Hello</data>"
xml.sax.parseString(data,contenthandler)

而它们的第二个参数则是,接下来要介绍的事件处理器。
事件处理器
事件处理器则负责对事件作出响应,对传递的 XML 数据进行处理。
一个事件处理器必须是ContentHandler类型的子类,通过重写父类的以下函数来响应解析器的事件请求:
cha\fracters(content)函数,它会在以下时机被调用:
如果从一行开始,遇到标签之前,存在字符,则content的值为这些字符串;
如果从一个标签,遇到下一个标签之前,存在字符,则content的值为这些字符串;
如果从一个标签,遇到行结束符(换行符)之前,存在字符,则content的值为这些字符串;
标签可以是开始标签,也可以是结束标签。
startDocument()函数,它在文档启动的时候调用;
endDocument()函数,它在解析器到达文档结尾时调用;
startElement(name, attrs)函数,它在遇到 XML 开始标签时调用,name是标签的名字,attrs是标签的属性值字典;
endElement(name)函数,它在遇到 XML 结束标签时调用。
假设有如下文件test.xml:

<data>文字1
文字2<ele1>元素1数据</ele1>文字3
文字4<ele2>元素2数据</ele2>文字5
</data>

当运行以下代码时:

import xml.sax
class Handler(xml.sax.ContentHandler):
    def startDocument(self):
        print("文档开始")
    def endDocument(self):
        print("文档结束")
    def startElement(self,name,attrs):
        print("开始标签:" , name)
    def endElement(self,name):
        print("结束标签:" , name)
    def cha\fracters(self,content):
        print("数据:" ,content)
if __name__ == '__main__':
    xml.sax.parse("test.xml",Handler())

会得到以下结果:
文档开始
开始标签: data
数据: 文字1
数据:<换行>
数据: 文字2
开始标签: ele1
数据: 元素1数据
结束标签: ele1
数据: 文字3
数据:<换行>
数据: 文字4
开始标签: ele2
数据: 元素2数据
结束标签: ele2
数据: 文字5
数据:<换行>
结束标签: data
文档结束
注意:结果中的<换行>其实是换行字符\n,为了方便阅读才改成<换行>。
将其与test.xml中数据的结构对比一下,就可以明白每个函数调用的时机了。
编程要求
根据提示,在右侧编辑器补充代码,要求:
GetHandler函数必须要返回一个事件处理器,它将被用于解析个人信息文件data.xml;
这个事件处理器在解析文件的过程中,要能识别出个人信息中个人签名的部分,然后将它打印出来。
data.xml的文件结构见测试说明。
测试说明
data.xml文件的结构:

<data>
    <info name="XXX" age="XXX">个人签名部分</info>
    ....
</data>

测试用的代码也会产生输出,与GetHandler返回的事件处理器的输出结合以后,将会得到以下结果:
赵昊的个人签名:
我赵昊第一个不服!
龙傲天的个人签名:
我命由我不由天
玛丽苏的个人签名:
我冷若冰霜,冷酷无情
叶良辰的个人签名:
良辰日后必有重谢!
其中第1,3,5,7行是测试代码产生的输出(不需要学员实现),2,4,6,8行则是事件处理器应该有的输出。

开始你的任务吧,祝你成功!
参考代码:

import xml.sax
class Handler(xml.sax.ContentHandler):
    #********** Begin *********#
    infostart = False
    def startElement(self,name,attrs):
        self.infostart = name == "info"
    def endElement(self,name):
        self.infostart = False
    def characters(self,content):
        if self.infostart:
            print(content)
    #********** End **********#                                 
def GetHandler():
    return Handler()

第5关:XML篇:使用ElementTree解析XML
任务描述
本关任务:设计一个查询个人信息的小程序。
ElementTree
xml.etree.ElementTree模块是一个轻量级的 DOM(文件对象模型),具有方便友好的 API。代码可用性好,速度快,消耗内存少。
ElementTree模块大致可以三部分:ElementTree类,Element类以及一些操作 XML 的函数。
教程中所使用的data.xml文件的内容如下:

<collection shelf="New Arrivals">
    <movie title="Enemy Behind">
       <type>War, Thriller</type>
       <description>Talk about a US-Japan war</description>
    </movie>
    <movie title="Transformers">
       <type>Anime, Science Fiction</type>
       <description>A schientific fiction</description>
    </movie>
    <movie title="Trigun">
       <type>Anime, Action</type>
       <description>Vash the Stampede!</description>
    </movie>
    <movie title="Ishtar">
       <type>Comedy</type>
       <description>Viewable boredom</description>
    </movie>
</collection>

解析
xml.etree.ElementTree提供了两个函数:parse和fromstring,用于从文件和字符串解析 XML 数据,比如:

import xml.etree.ElementTree as ET
doc = ET.parse("data.xml") #从文件解析XML数据
root = doc.getroot() #获取根元素
data = "<a>hello</a>"
el = ET.fromstring(data) #从字符串解析XML数据

parse函数返回一个ElementTree对象,fromstring返回一个Element对象。
Element对象代表一个 XML 元素,它的功能接下来会介绍。
ElementTree对象代表一个 XML 文档,它提供了函数getroot,来获取一个文档的根元素,正如上面的例子中展示的那样。
查找元素
Element对象和ElementTree对象都提供了用于在子元素查找元素的函数:
find(name):用于在直接子元素中,查找一个名为name的元素;
findall(name):用于在直接子元素中,查找所有名为name的元素,它的返回值可以看做一个所有元素都是Element对象的tuple对象,可以对它进行迭代操作或者索引[]操作;
iter(name = None):用于在当前元素下的所有子元素中,查找名为name的元素,如果不指定name,则返回所有子元素。它返回一个迭代器对象。
比如:

import xml.etree.ElementTree as ET
doc = ET.parse("data.xml") #从文件解析XML数据
root = doc.getroot() #获取根元素
for s in root.findall("movie"): #选择所有名为moive的元素
        print(s.find("description").text) #打印出movie元素下description元素的文本

得到结果是:
Talk about a US-Japan war
A schientific fiction
Vash the Stampede!
Viewable boredom
获取元素的文本与属性值
Element有一个属性text,这个属性用于获取直接在这个元素的开始、结束标志之间的文本。如果没有文本,则返回空字符串:

import xml.etree.ElementTree as ET
data = "<a>TextA<b>TextB</b></a>"
ele = ET.fromstring(data)
print(ele.text)
print(ele.find("b").text)

得到的结果是:
TextA
TextB
如果要获取一个元素的某个属性,可以使用get(name)函数,它会寻找当前元素上名为name的属性。如果找到就返回这个属性的值,没找到则返回空字符串。比如:

import xml.etree.ElementTree as ET
doc = ET.parse("data.xml") #从文件解析XML数据
root = doc.getroot() #获取根元素
for s in root.findall("movie"): #选择所有名为moive的元素
        de = s.find("description") #获取description元素
        print("%s: %s" % (s.get("title"),de.text)) #获取tile属性,与description元素的文本值格式化输出

得到的结果:
Enemy Behind: Talk about a US-Japan war
Transformers: A schientific fiction
Trigun: Vash the Stampede!
Ishtar: Viewable boredom
打印出了电影的名字与简介。
编程要求
根据提示,补充右侧编辑器Begin-End区间代码,完成InfoManager类的定义,实现如下的功能:
LoadInfo():从step5/data.xml中读取 XML 数据;
GetInfoCount():返回个人信息的条数,类型为int;
GetAge(name):返回名为name的人的年龄age,类型为int;
GetDescription(name):返回名为name的人的个人签名(元素的文本)。
为了简单起见,假设查询的人的信息一定存在。
测试说明
step5/data.xml中的数据如下:

<?xml version="1.0" encoding="utf-8"?>
<data count="4">
    <info name="赵昊" age="15" >我赵昊第一个不服!</info>
    <info name="龙傲天" age="16">我命由我不由天</info>
    <info name="玛丽苏" age="15">我冷若冰霜,冷酷无情</info>
    <info name="叶良辰" age="16">良辰日后必有重谢!</info>
</data>

评测代码会将查询到的信息,按照一定格式输出,请确保返回结果正确。
开始你的任务吧,祝你成功!
参考代码:

import xml.etree.ElementTree as ET
class InfoManager:
    doc = None
    root = None
    def LoadInfo(self):
        self.doc = ET.parse("step5/data.xml")
        self.root = self.doc.getroot()
    def GetInfoCount(self):
        return int(self.root.get("count"))
    def GetAge(self,name):
        infos = self.root.findall("info")
        for s in infos: #搜索name属性与函数参数name的值相同的xml元素
            if s.get("name") == name:
                return int(s.get("age"))
        return 0 #随便返回一个值,评测代码不会有找不到的数据
    def GetDescription(self,name):
        infos = self.root.findall("info")
        for s in infos: #搜索name属性与函数参数name的值相同的xml元素
            if s.get("name") == name:
                return s.text
        return "" #随便返回一个值,评测代码不会有找不到的数据
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐