要求:

  网址用一个XML文件描述,其中包括独立网页和目录的信息;

  程序能创建所需的目录和网页;

  可以改变网址的设计,并且以新的设计为基础重新生成所有网页

概念:

  网站:不用存储有关网站本身的任何信息,即网站就是包含所有文件和目录的顶级元素;

  目录:目录是文件和其他目录的容器;

  页面:一个网页;

  名称:目录和网页都需要名称——当目录和文件出现在文件系统和相应的URL中,可以用作目录名和文件名

  标题:每个网页都应该有标题(和文件名不同)

  内容:每个网页都应该有内容,这里只用XHTML来表示——就能将它传递到最终的网页上,让浏览器解释

XML程序:

  文档由一个包含数个directory和page元素的website元素组成,每个目录元素可以包括更多的页面和目录。directory和page元素有name特性,属性值为它们的名字。此外,page标签还有title特性。page元素包括XHTML代码(XHTML的body标签中的类型)

#用XML文件表示的简单网站(website.xml)
<website>
<page name="index" title="Home page">
<h1>Welcome to my Home page</h1> <p>Hi, there. My name is Mr.gumby,and this is my home page,here are some of my int:</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>shouting page</h1>
<p>....</p>
</page>
<page name="sleeping" title="Sleeping">
<h1>sleeping page</h1>
<p>...</p>
</page>
<page name="eating" title="Eating">
<h1>Eating page</h1>
<p>....</p>
</page>
</directory>
</website>

XML文件解析: 

  python解析xml和在java中一样,有两种方式,SAX和DOM,两种处理方式不同点在于速度和范围,前者讲究的是效率,每次只处理文档的一小部分,快速而能有效的利用内存,后者是相反的处理方式,先把所有的文档载入到内存,然后再进行处理,速度比较慢,也比较消耗内存,唯一的好处就是可以操作整个文档。

1. 简单实现

1.1 简单的内容处理程序

  在python中使用sax方式处理xml要先引入xml.sax中的parse函数,还有xml.sax.handler中的ContentHandler,后面的这个类是要和parse函数来配合使用的。使用方式如下: parse('xxx.xml',xxxHandler),这里面的xxxHandler要继承上面的ContentHandler。 然后这个parse函数在处理xml文件的时候,会调用xxxHandler中的startElement函数和endElement函数来表示一个xml中的标签的开始和结束,中间的过程使用一个名为characters的函数来处理标签内部的所有字符串。

from xml.sax.handler import ContentHandler
from xml.sax import parse class TestHandler(ContentHandler):
def startElement(self,name,attrs):
print name, attrs.keys() parse('website.xml',TestHandler())

  startElement函数参数:标签及其特性(保存在类字典对象中);

  endElement函数参数:标签名;

  characters函数参数:字符串;

#建立网站大标题(h1元素)列表的例子

from xml.sax.handler import ContentHandler
from xml.sax import parse class 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_lines=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

分析:

  

为啥结果是空?????????????????????????

1.2  创建HTML页面

要求:

  在每个page元素开始处,使用给定的文件名打开一个新文件,写入合适的HTML首部,包括给定的标题;

  在每个page元素的结尾处,写入HTML的页脚,然后关闭文件;

  在page元素内部时,跳过所有标签和字符,不进行修改(将它们直接写入文件);

  不在page元素内部时,忽略所有标签(比如website或者directory)

#简单的页面创建程序脚本(pagemaker.py)
from xml.sax.handler import ContentHandler
from xml.sax import parse class PageMaker(ContentHandler):
passthrough=False
def startElement(self,name,attrs):
if name == 'page':
self.passthrough=True
self.out=open(attrs['name']+'.html','w')
self.out.write('<html><head>\n')
self.out.write('<title>%s</title>\n‘ % attrs['title'])
self.out.write('</head><body>\n')
elif self.passthrough:
self.out.write('<'+name)
for key,val in attrs.items():
self.out.write(' %s=%s"' % (key,val))
self.out.write('>') def endElement(self,name):
if name == 'page':
self.passthrough=False
self.out.write('\n<body></html>\n’)
self.out.close()
elif self.passthrough:
self.out.write('<%s>' % name) def characters(self,chars):
if self.passthrough:self.out.write(chars) parse('website.xml',PageMaker())

有啥都没。。。。。。

存在的问题:

  使用if语句处理不同的事件类型,若事件很多,if语句很长且不易读;

  HTML代码是硬连接的,应该可以轻松进行替换

2. 改进

2.1 调度程序的混入类

#基本事件处理程序
class Dispatcher: #... def startElement(self,name,attrs):
self.dispatch('start',name,attrs)
def endElement(self,name):
self.dispatch('end',name) #dispatch方法
#capitalize()方法返回字符串的一个副本,只有它的第一个字母大写
#Instance = A() print getattr(Instance , 'name, 'not find')
#如果Instance 对象中有属性name则打印self.name的值,否则打印'not find'
#callable(obj),检查对象obj是否可调用 def dispatch(self,predix,name,attrs=None):
mname=predix+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)

说明:

  根据一个前缀(‘start’或‘end’)和一个标签名(比如‘page’)构造处理程序的方法名(比如‘startPage');

  使用同样的前缀,构造默认处理程序的名字(比如’defaultStart');

  试着使用getattr获得处理程序,用Nono作为默认值;

  如果结果可以调用,将一个空元组赋值给args;

  否则试着利用getattr获取默认处理程序,再次使用None作为默认值,同样的将args设为只包括标签名的元组(默认程序需要);

  如果正在使用一个起始处理程序,那么将属性添加到参数元组(args);

  如果处理程序可调用(或者是可用的具体处理程序,或者是可用的默认程序)使用正确的参数进行调用。

2.2 实现首部,页脚和默认的处理程序 

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") 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)

2.3 对目录的支持

  os.makedirs:在给定的路径内创建所需要的目录;

  os.path.isdir:检查指定的路径是否是目录;

  os.path.join:可用使用正确的分隔符将数个路径连接起来

2.4 事件处理程序

#目录处理程序
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()

3. 总结

3.1 流程

程序执行逻辑:
  1).parse('website.xml',WebsiteConstructor('public_html'))
      首先生成一个WebsiteConstructor对象,生成此对象时调用其构造方法创建名为public_html的目录
  2).parse调用处理程序WebsiteConstructor,下面将是触发式执行程序
      逻辑概要:一共会触发时执行三种事件,起始标签、结束标签、遇到字符
      遇到字符:只需直接打印字符即可
      起始标签:会判断如果有此标签起始方法则调用,否则调用默认其实方法(default开头的)
      结束标签:同上

在page里才能打印,所以在page的起始标签中加入了passthroug变量(如果为True在页面内,False不再页面内)。如果在页面内则能调用默认方法下的if语句,否则不执行。

3.2 程序

1)attrs是一个字典,存储的是该标签的所有属性,以字典方式存储, key=属性名,value=属性值

2)characters遇到字符就会触发的事件,字符块可能是全是空格的字符块

from xml.sax.handler import ContentHandler
from xml.sax import parse
import os 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,
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)
print path
print '----'
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):
print 'endDirectory'
self.directory.pop() def startPage(self, attrs):
print 'startPage'
filename = os.path.join(*self.directory + [attrs['name']+'.html'])
self.out = open(filename, 'w')
self.writeHeader(attrs['title'])
self.passthrough = True def endPage(self):
print 'endPage'
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基础教程总结15——3 XML构建网址的更多相关文章

  1. python基础教程总结15——7 自定义电子公告板

    1. Python进行SQLite数据库操作 简单的介绍 SQLite数据库是一款非常小巧的嵌入式开源数据库软件,也就是说没有独立的维护进程,所有的维护都来自于程序本身.它是遵守ACID的关联式数据库 ...

  2. python基础教程总结15——6 CGI远程编辑

    功能: 将文档作为普通网页显示: 在web表单的文本域内显示文档: 保存表单中的文本: 使用密码保护文档: 容易拓展,支持处理多余一个文档的情况 1.CGI CGI(Comment Gateway I ...

  3. python基础教程总结15——5 虚拟茶话会

    聊天服务器: 服务器能接受来自不同用户的多个连接: 允许用户同时(并行)操作: 能解释命令,例如,say或者logout: 容易拓展 套接字和端口: 套接字是一种使用标准UNIX文件描述符(file ...

  4. python基础教程总结15——4 新闻聚合

    NNTP:网络新闻传输协议,Network News Transfer Protocol 目标: 从多种不同的来源收集新闻: 用户可以轻松添加新的新闻来源(甚至是新类型的新闻来源: 程序可以将编译好的 ...

  5. python基础教程总结15——1.即时标记

    1. 测试文档: # test_input.txt Welcome to World Wide Spam. Inc. These are the corporate web pages of *Wor ...

  6. python基础教程总结15——2 画幅好画

    要求:从Internet上下载数据文件:  分析数据文件并提取感兴趣的部分 工具:图形生成包(ReportLab,PYX等) 数据:太阳黑子和射电辐射流量(http://services.swpc.n ...

  7. Python基础教程(第3版)PDF高清完整版免费下载|百度云盘

    百度云盘:Python基础教程(第3版)PDF高清完整版免费下载 提取码:gkiy 内容简介 本书包括Python程序设计的方方面面:首先从Python的安装开始,随后介绍了Python的基础知识和基 ...

  8. python基础教程(一)

    之所以选择py交易有以下几点:1.python是胶水语言(跨平台),2.python无所不能(除了底层),3.python编写方便(notepad++等文本编辑器就能搞事情),4.渗透方面很多脚本都是 ...

  9. Python基础教程学习笔记:第一章 基础知识

    Python基础教程 第二版 学习笔记 1.python的每一个语句的后面可以添加分号也可以不添加分号:在一行有多条语句的时候,必须使用分号加以区分 2.查看Python版本号,在Dos窗口中输入“p ...

随机推荐

  1. Socket 阻塞与非阻塞模式

    http://blog.sina.com.cn/s/blog_5d0990c7010115ib.html

  2. Lightoj1028【计算约数个数】

    思路: 最终就是求一个数的约数(除了1)对吧. 然后想要枚举sqrt(N)受阻,枚举素数数组受阻,加上prime[i]*prime[i]<=n就好了?那就好了吧. #include <bi ...

  3. ue4 motage

    Montage是什么 一个(可以自由拼接动画的)动画剪辑,通过slot,在任意时候由玩家主动向动画系统push自己制作的动画剪辑 Montage用途 上图是一个近身攻击动画,含有 3 个片段 [开始. ...

  4. [UE4]C++实现动态加载的问题:LoadClass()和LoadObject()

    http://aigo.iteye.com/blog/2281558 原文作者:@玄冬Wong 相关内容:C++静态加载问题:ConstructorHelpers::FClassFinder()和FO ...

  5. c#---delegate关键字

    http://www.cnblogs.com/wenjiang/archive/2013/03/12/2954913.html 注:只看红字 在C#中,delegate是一个神奇的关键字,值得拿出来单 ...

  6. 2014-10-6 NOIP模拟赛

    1. 锻炼计划(exercise.pas) 身体是革命的本钱,OIers不要因为紧张的学习和整天在电脑前而忽视了健康问题.小x设计了自己的锻炼计划,但他不知道这个计划是否可行,换句话说如果计划不当可能 ...

  7. codevs 3162 抄书问题

    3162 抄书问题 题目描述 Description 现在要把M本有顺序的书分给K个人复制(抄写),每一个人的抄写速度都一样,一本书不允许给两个(或以上)的人抄写,分给每一个人的书,必须是连续的,比如 ...

  8. 洛谷P4099 [HEOI2013]SAO(树形dp)

    传送门 HEOI的题好珂怕啊(各种意义上) 然后考虑树形dp,以大于为例 设$f[i][j]$表示$i$这个节点在子树中排名第$j$位时的总方案数(因为实际只与相对大小有关,与实际数值无关) 我们考虑 ...

  9. MySQL的ibdata1文件占用过大瘦身

    处理MySQL的ibdata1文件过大问题本人在对数据库进行大量的数据插入和删除的时候,发现ibdata1的占了将近一个T ibdata1文件是什么? ibdata1是一个用来构建innodb系统表空 ...

  10. Java基础笔记(四)——命名规则、数据类型

    标识符即Java程序中需要自定义的名称,如变量名.方法名.类名.包名.工程名等. 标识符的命名规则: 1.可由字母.数字.下划线(_)和美元符($)组成,不能以数字开头. 2.严格区分大小写. 3.不 ...