首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Python3练习项目05:解析XML(上)

这个练习项目来自《Python基础教程(第2版)》,案例原名为“万能的XML”。

XML是一种可扩展标记语言,具备以下特点(来自百度百科):

可扩展标记语言是一种很像超文本标记语言的标记语言。

它的设计宗旨是传输数据,而不是显示数据。

它的标签没有被预定义,需要自行定义标签。

它被设计为具有自我描述性。

它是W3C的推荐标准。

上面所说的超文本标记语言,大家已经见过。

一般超文本标记语言就是指HTML。

HTML文件由多个标记(即通常所说的标签)组成。

这些标记通常是成对出现,即一个开始标记对应一个 结束标记。

XML和HTML非常相像,它的标记也是成对出现。

不过,和HTML不同的是,HTML中的标记名称都是固定的,而XML中的标记名称是需要自定义的。

并且,XML和HTML最大不同之处是:XML的目的是传输信息,HTML的目的是显示信息。

例如,一个描述网站结构与页面内容的XML文件。

示例代码:

欢迎访问小楼的个人网站!

您正在访问的是小楼的个人网站,这个网站包含以下内容:

文章

下载

文档

您正在访问文章列表页!

....

您正在访问资源下载页!

...

您正在访问文档列表页!

....

在上方XML代码中,通过自定义标记、以及

定义了网站的结构。

并且,通过一些HTML标记,描述了每个网页的内容。

那么,我们就可以通过这个XML文件传输整个网站内容的数据,并通过对XML的解析,生成网站的结构和HTML页面文件。

所以,基于XML传输信息的特点,我们能够通过XML实现很多功能。

如果想很好的掌握XML,还需要深入的学习,请大家自行查阅相关技术文档。【点此查看推荐教程】

对XML有了一些基本的了解之后,我们来看一下如何对XML文件内容进行解析。

首先,我们先来做个小试验。

通过Python内置的xml模块就能够对XML文件进行解析。

这里需要先导入xml模块的一些功能。

示例代码:

parse()函数具有解析功能,ContentHandler类则具有内容处理的方法。

ContentHandler类所包含的方法有很多,比较常用的就是对开始元素、内容以及结束元素进行处理的方法。

这些方法,我们需要重写才能够实现我们想要的功能。

在重写方法之前,我们先来看一下通过这个类处理内容时,我们都能获取什么样的内容。

以处理开始标记的方法startElement()为例。

我们创建一个类继承自ContentHandler类,然后重写startElement()方法。

示例代码:

class XMLHandler(ContentHandler): def startElement(self, name, attrs): # 重写startElement方法 print(name, list(zip(attrs.keys(), attrs.values()))) # 显示输出参数内容parse('website.xml', XMLHandler()) # 调用解析函数

运行上方代码,我们能够看到以下内容:

很显然,所有开始标签的名称和属性都能够被获取到。

接下来,我们再进一步,将XML中的每个网页的一级标题(标签中的内容)提取出来。

为了避免混乱,我们可以删除刚才的代码,重新定义一个类。

示例代码:

class HeadLineHandler(ContentHandler): def __init__(self, headLines): super().__init__() # 不写对结果也没有影响 self.headLines = headLines # 初始化类的变量为传入的标题列表 self.in_headLine = False # 初始化开关变量 self.data = [] # 初始化临时保存数据的变量 def startElement(self, name, attrs): # 重写开始元素的方法 if name == 'h1': # 如果是一级标题开始标记 self.in_headLine = True # 打开开关 def characters(self, content): # 重写元素内容的方法 if self.in_headLine: # 如果开关打开 self.data.append(content) # 添加内容到临时变量 def endElement(self, name): # 重写结束元素的方法 if name == 'h1': # 如果是一级标题结束标记 content = ''.join(self.data) # 提取内容为临时变量中保存的所有内容 self.data = [] # 清空临时变量 self.headLines.append(content) # 标题列表中添加提取到的内容 self.in_headLine = False # 关闭开关if __name__ == '__main__': headLines = [] # 创建空的一级标题列表 parse('website.xml', HeadLineHandler(headLines)) # 调用解析方法 for line in headLines: # 遍历通过解析写入内容的一级标题列表 print(line) # 显示输出每一个标题内容

运行上方代码,显示结果为:

欢迎访问小楼的个人网站!

您正在访问文章列表页!

您正在访问资源下载页!

您正在访问文档列表页!

代码比较简单,大家参照注释进行理解基本就能够明白整个程序的运行过程。

这里面有两个关键点:

变量in_headLine是一个开关,读取到一级标题的开始标记时,打开这个开关,并且将开关打开时读取到的内容提取;当读取到一级标题的结束标记时,关闭这个开关,以免其他内容被提取。

变量data是一个临时保存提取内容的列表,在上方代码中并未发挥实际作用,它的作用是将某一对标记之间的多段数据内容顺序保存。只有当一对标记间存在其它标记时,才会出现多段内容,当前练习项目中不存在这种情况。

通过前面两段代码,我们已经对XML解析有了一些了解。

下面,我们就完成解析XML代码并生成HTML页面的功能。

为了避免混乱,我们可以新建一个Python文件。

实现的思路为:

读取开始标记时,如果是页面标记(page),创建页面文件,写入页头HTML代码;并打开写入页面内容的开关;

读取开始标记时,如果写入页面内容开关被打开,原样写入该开始标记的名称与属性到页面文件;

读取标记内容时,如果写入页面内容开关被打开,直接写入内容到页面文件;

读取结束标记时,如果是页面标记,关闭写入页面内容的开关,写入页脚HTML代码,关闭页面文件;

读取结束标记时,如果写入页面内容开关被打开,直接写入结束标记。

示例代码:

from xml.sax import parsefrom xml.sax.handler import ContentHandlerclass MakePages(ContentHandler): in_page = False # 定义开关变量 def startElement(self, name, attrs): # 重写开始元素的方法 if name == 'page': # 如果是页面标记 self.in_page = True # 打开开关 self.file = open(attrs['name'] + '.html', 'w') # 创建HTML文件 self.file.write('\n\n\n{}\n\n\n' .format(attrs['title'])) # 写入页头HTML代码 elif self.in_page: # 如果开关被打开 self.file.write('') # 写入标记末尾符号 def characters(self, content): # 重写元素内容的方法 if self.in_page: # 如果开关被打开 self.file.write(content) # 写入内容 def endElement(self, name): # 重写结束元素的方法 if name == 'page': # 如果是页面标记 self.in_page = False # 关闭开关 self.file.write('\n\n\n') # 写入页脚HTML代码 self.file.close() # 关闭创建的页面文件 elif self.in_page: # 如果开关被打开 self.file.write('') # 写入结束标记if __name__ == '__main__': parse('website.xml', MakePages()) # 调用解析函数

运行以上代码后,虽然会在项目文件夹中出现4个html文件,但是明显和我们的预期结果不一样。

我们希望能够将除了“index.html”页面之外的页面放在名为“catalog”目录中。

那么,如何解决这个问题呢?

在下一篇教程中,我带大家一起再次实现这个功能,让它能够完美实现。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180405G0AE6700?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券