《Python基础教程(第2版)》学习笔记(三):
来源:互联网 发布:魔兽之路隐藏英雄数据 编辑:程序博客网 时间:2024/05/17 06:36
Proj3万能的XML
这个项目介绍了如何用XML来表示多种数据,以及如何使用适合XML或SAX的简单API来处理XML文件。XML并不是一种具体的语言(例如HTML),它更类似于定义语言类的一种规则集合。我们仍然使用HTML中的方式来写标签,但在XML中,还可以自己定义标签名。
工作和目标
本项目解决的问题就是解析(读取和处理)XML文件,具体来讲是通过一个描述各种网页和目录的XML文件生成一个完整的网站。这个文件包括站点结构和每个页面的基本内容。
目标列举如下:
-整个网站应该用一个XML文件描述,其中包括独立网页和目录的信息。
-程序应该能创建所需的目录和网页
-应该可以轻松改变整个网站的设计,并且以新的设计为基础重新生成所有网页。
工具
Python有一些内建的XML支持,查看是否已有一个可以用的SAX语法分析器,执行下面语句:
from xml.sax import parseparser = make_parser()
执行这条命令不引发任何异常即可以开始项目了。
准备工作
编写处理XML文件的程序前,需要设计XML格式。主要概念包括网站、目录、页面、名称、标题和内容。
-网站。不用存储有关网站本身的任何信息,所以网站就是包括所有文件和目录的顶级元素。
-目录。目录是文件和其他目录的容器。
-页面。一个网页。
-名称。目录和网页都需要名称–当目录和文件出现在文件系统和相应的URL中时,它们可以用作目录名和文件名。
-标题。每个网页都应该有标题(和文件名不同)。
-内容。每个网页都有一些内容。
简单来说,文档由一个包含directory和page元素的website元素组成,每个目录元素可以包括更多的页面和目录。directory和page元素有叫做name的特性,属性值是它们的名字。除此之外,page标签还有title特性。page元素包括XHTML代码。一个实例文件是Proj3万能的XML中的website.xml。如下:
<website> <page name="index" title="Home Page"> <h1>Welcome to My Home Page</h1> <p>Hi,there.My name is Alexis,and this is my home page.Here are some of my interests:</p> <ul> <li><a href="interests/shouting.html">Shouting</a></li> <li><a href="interests/sleeping.html">Sleeping</a></li> <li><a href="interests/eating.html">Eating</a></li> </ul> </page> <directory name="interests"> <page name="shouting" title="Shouting"> <h1>Alexis's Shouting Page</h1> <p>...</p> </page> <page name="sleeping" title="Sleeping"> <h1>Alexis's Sleeping Page</h1> <p>...</p> </page> <page name="eating" title="Eating"> <h1>Alexis's Eating Page</h1> <p>...</p> </page> </directory></website>
初次实现
创建简单的内容处理程序
在使用SAX进行解析时,有很多种事件类型可用,这里只用到3个:startElement(开始标签的匹配项)、endElement(关闭标签的匹配项)以及characters(字符)。使用xml.sax模块中的parse函数负责读取并且生成这些事件。要生成这些事件需要调用一些处理程序(content handler),xml.sax.handler中的ContentHandler类实现了这些处理程序,但函数具体工作需要用户重写。解析的具体原理可以参看这个链接(http://www.cnblogs.com/hongfei/p/python-xml-sax.html)。假如要解析一个<h1>
级别的标题,可以像下面这样编写一个类:
from xml.sax.handler import ContentHandlerfrom xml.sax import parseclass HeadlineHandler(ContentHandler): in_headline = False def __init__(self,headlines): ContentHandler.__init__(self) self.headlines = headlines self.data = [] def startElement(self,name,attrs): if name == 'h1': self.in_headline = True def endElement(self,name): if name == 'h1': text = ''.join(self.data) self.data = [] self.headlines.append(text) self.in_headline = False def characters(self,string): if self.in_headline: self.data.append(string)
这种解析类都至少包括上面说的三种事件类型的处理程序。具体执行时可以像这样调用:
headlines = []parse('website.xml',HeadlineHandler(headlines))print 'The following <h1> elements were found:'for h in headlines: print h
打印出的结果如下图:
简单的过程就是当找到<h1>
标签时,调用startElement,开关打开。在结束标签之前都会调用characters收集字符串。当遇到结束标签</h1>
时,执行endElement函数,处理收集到的字符串,添加到存储题目的列表中。
创建HTML页面
像上一节的例子处理<h1>
标签那样那样,我们需要编写一个还能处理<page>
等其他标签的完整的HTML页面解析程序(暂时不考虑目录的解析)。这个简单版本的代码在工程文件夹下的pagemaker.py文件中。运行结果如下所示:
<html><head><title>Home Page</title></head><body> <h1>Welcome to My Home Page</h1> <p>Hi,there.My name is Alexis,and this is my home page.Here are some of my interests:</p> <ul> <li><a href="interests/shouting.html">Shouting</a></li> <li><a href="interests/sleeping.html">Sleeping</a></li> <li><a href="interests/eating.html">Eating</a></li> </ul></body></html>
再次实现
调度程序的混入类
与其在标准的泛型事件处理程序(比如startElement)中编写大段的if语句,不如编写自己的具体程序(比如startPage),并且自动调用它们。一个提供有限功能的混入类(本文中是Dispatcher)和其他更具体的类(本文中是ContentHandler类)一起被继承,生成的新类WebsiteConstructor才是最终被parse使用的类。Dispatcher类中的方法dispatch()类似于项目1中的根据名称查找函数,该类还包括基本的startElement和endElement事件处理。
class Dispatcher: def dispatch(self,prefix,name,attrs=None): mname = prefix + name.capitalize() dname = 'default' + prefix.capitalize() method = getattr(self,mname,None) if callable(method): args = () else: method = getattr(self,dname,None) args = name, if prefix == 'start': args += attrs, #args是一个元组 if callable(method): method(*args) def startElement(self,name,attrs): self.dispatch('start',name,attrs) def endElement(self,name): self.dispatch('end',name)
下面就是实现具体的处理程序了:
class WebsiteConstructor(Dispatcher,ContentHandler): passthrough = False def __init__(self,directory): self.directory = [directory] self.ensureDirectory() def ensureDirectory(self): path = os.path.join(*self.directory) if not os.path.isdir(path): os.makedirs(path) def characters(self,chars): if self.passthrough: self.out.write(chars) def defaultStart(self,name,attrs): if self.passthrough: self.out.write('<' + name) for key,val in attrs.items(): self.out.write(' %s="%s"' % (key,val)) self.out.write('>') def defaultEnd(self,name): if self.passthrough: self.out.write('</%s>' % name) def startDirectory(self,attrs): self.directory.append(attrs['name']) self.ensureDirectory() def endDirectory(self): self.directory.pop() def startPage(self,attrs): filename = os.path.join(*self.directory+[attrs['name']+'.html']) self.out = open(filename,'w') self.writeHeader(attrs['title']) self.passthrough = True def endPage(self): self.passthrough = False self.writeFooter() self.out.close() def writeHeader(self,title): self.out.write('<html><head>\n <title>') self.out.write(title) self.out.write('</title>\n </head>\n <body>\n') def writeFooter(self): self.out.write('\n </body>\n</html>\n')
解释一下为什么要ensureDirectory。os.makedirs(‘foo/bar/baz’)函数会在当前目录中创建一个字符串中的目录,当该目录(指完整的../foo/bar/baz)本来就存在时,会引发一个异常。为了避免出现这个异常,需要使用os.path.isdir函数,它可以检查给定的路径是否是目录(也就是目录是否存在)。另外一个函数os.path.join可以使用正确的分隔符将数个路径连接起来例如:directory = [“C”, “pic”, “18x.jpg”],执行os.path.join(*directory) 会得到”C\\pic\\18x.jpg”。完整代码见website.py文件。
总结
本项目建立了一个简单的网站,非常简单,只有文本信息。要做更复杂的还需要深入学习,以后有机会再扩展一下这个程序。
- 《Python基础教程(第2版)》学习笔记(三):
- 《Python基础教程(第2版)》学习笔记(一):
- 《Python基础教程(第2版)》学习笔记(二):
- 《Python基础教程(第2版 修订版)》 第1章 快速改造:基础知识(学习笔记)
- 《Python基础教程 第2版·修订版》第3章 使用字符串(学习笔记)
- python 学习笔记(摘自《Python基础教程第2版》)
- Python基础教程学习(三)
- 《Pyhon基础教程 第2版·修订版》 第2章 列表和元组 (学习笔记·三)
- python基础教程学习笔记三
- 《Python基础教程 (第2版 修订版)》 第2章 列表和元组(学习笔记· 一)
- 《Python基础教程(第2版·修订版)》 第2章 列表和序列(学习笔记·二)
- 《Python基础教程 第2版·修订版》 第2章 列表和元组(学习笔记·总)
- 学习《Python基础教程(第二版)》笔记2--基础知识
- 学习《Python基础教程(第二版)》笔记10--抽象2
- Python基础教程(第2版)读书笔记
- Python基础教程(第2版)第一章
- 《Python基础教程》第20章学习笔记
- python学习笔记(1)--《python基础教程》第1章内容总结
- 深入理解urllib、urllib2及requests
- Python学习——struct模块的pack、unpack示例
- 29-HTML-14-HTML(表单格式化)
- 2015 Multi-University Training Contest 6 (hdu 5357 - Easy Sequence)栈的应用
- asp.net 中 linkbutton 点击下载文件
- 《Python基础教程(第2版)》学习笔记(三):
- HDU5375 Gray code
- leetcode 日经贴,python code -Different Ways to Add Parentheses
- GDOI2016模拟8.10火星菌
- 网络流 HDU 3549 Flow Problem
- 29-HTML-15-HTML(GET和POST区别)
- 学英语从背单词开始,但背单词要适可而止
- spring属性的注入实例
- 29-HTML-16-HTML(服务端GET和POST区别)