Python基础教程十个项目(3)



这个项目是和第一个项目相反,第一个项目是形成html文件,这个项目是解析xml文件。在解析这个xml文件的时候,我们用到了SAX这个工具,要了解这个项目的具体流程处理,还是要看看SAX到底是怎么解析xml文件的。


http://www.ibm.com/developerworks/cn/xml/x-cert/part8/


估计大家看了上面这个连接的 SAX是如何工作的,就会对这个解析器有了一些了解,这对于理解整个项目是很有帮助的。

因为要解析xml文件,就要用到prase函数,在调用这个函数的期间必然要用到一些处理工具,即函数,ContentHandler这个类基本定义了所有的处理函数,当然如果你有不同的需求可以通过在你自己的类里面继承它,然后重写里面的同名函数,这样就会覆盖掉父类里面的这个函数。


WebsiteConstructor这个类主要是各种标签的处理函数。Dispatcher这个类和第一个项目的处理程序的父类类似,都是去寻找带有正确前缀和名字的函数来调用。值得注意的是元组的增加元素是必须加上逗号的。


还有一个需要注意的一点就是,这个项目有两种*号的用法。

第一种是在method(*argv),这里明显是用到了冗余参数的办法,一次性把所有的参数传给对应的函数。

第二种是在os.path.join(*directory),这里面*号的作用是把directory这个列表里面的所有的元素都要展开,分成一个个的,也就是部分路径,然后再通过join方法连接成一个整体的路径。



这个解析xml的项目,就是针对xml文件中不同的标签做出一些不同的动作,如果是目录标签那么就创建一个文件夹,如果是一个页面,那么就打开相应的文件,把内容写入文件。这样一个网站也就建成了


#coding=utf-8
from xml.sax.handler import ContentHandler
from xml.sax import parse
import os

class Dispatcher:
	u"""
	是一个混合类,和第一个项目中有相似之处,因为要处理不同的标记,
	所以通过前缀名来指定处理函数更加方便。利用混合类管理一些细节也很容易
	"""
	def dispatch(self,prefix,name,attrs=None):
		u"""
		在调用各种处理方法的时候,要先判断这个方法有还是没有,如果有,那么就直接调用相应的函数,如果没有
		那么就把属性和名称都添加到一个元组里面去调用一个默认的函数,也就是所说的忽略其他的标签,不做特殊处理、
		直接按原样输出即可
		"""
		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,#这里需要注意,要加上逗号
		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):
	u"""
	在利用SAX在解析XML文件的时候,要用到Parser这个函数,这个函数在读取文件
	以及在处理这些文件的时候要相应的利用一些时间处理程序。继承CotentHandler是因为这个类里面
	实现了几乎所有时间处理程序,当然我们也可以在本程序中重写里面的时间处理函数来进行覆盖使用
	"""
	passthrough = False        #设定布尔变量,在处理特殊标签的时候由于要忽略一些其内部的标签以及一些特殊的处理,需要判断文件解析器是否要停止处理

	def __init__(self, directory):
		self.directory = [directory]
		self.ensureDirectory()

	def ensureDirectory(self):
		u"""
		这个函数主要是利用os模块中对文件操作的特性,为xml文件中每一个页面都创建一个相应的目录存放html文件
		"""
		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):
		u"""
		两个默认的函数都是处理一页面标签中的一些其他标签,这些页面中的所有标签在这里都做了忽略的处理
		"""
		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):
		u"""
		这两个函数是为了在xml文件中碰见不同的目录要进行创建,但是创建之后要删除,避免不同目录的页面最后出现在同样的目录下面
		"""
		self.directory.append(attrs['name'])
		self.ensureDirectory()
	def endDirectory(self):
		self.directory.pop()

	def startPage(self,attrs):
		u"""
		两个函数要处理页面,创建这个页面的html文件,然后添加上标题,打开这个文件,写入文件之后在关闭
		"""
		filename = os.path.join(*self.directory+[attrs['name'] + '.html'])
		self.out = open(filename, 'a+')
		self.writeHeader(attrs['title'])
		self.passthrough = True
		print u"正在写入 %s" % filename
	def endPage(self):
		self.passthrough = False
		self.writeFooter()
		self.out.close()


	def writeHeader(self, title):
		self.out.write("<html>\n <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')


parse('website.xml', WebsiteConstructor('public.html'))

你可能感兴趣的:(Python基础教程十个项目(3))