要求:

  网址用一个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. Maven&nbsp;3&nbsp;入门&nbsp;--&nbsp;安装与配置

    Maven 3 入门 -- 安装与配置 Maven以及其Eclipse插件m2eclipse的安装 (本文参考了Maven实战) 检查JDK的安装以及环境变量的配置 打开cmd echo %Java_ ...

  2. Oracle tns 协议

    下面是翻译国外的一篇博客,原文连接如下: https://thesprawl.org/research/oracle-tns-protocol/ 简介 TNS(Transparent Network ...

  3. Depth Buffer

    Up until now there is only one type of output buffer you've made use of, the color buffer. This chap ...

  4. svn git 的区别(别再问我了)

    这篇主要是谈谈两者的区别,至于谁优谁劣看官自己思考吧! 把第一条理解到位思想到位了做起来才会有的放矢,其他几条都是用的时候才能体会到 1) 最核心的区别Git是分布式的,而Svn不是分布的.能理解这点 ...

  5. [poj]1050 To the Max dp

    Description Given a two-dimensional array of positive and negative integers, a sub-rectangle is any ...

  6. Unity开发Android应用优化指南(上)

    http://forum.china.unity3d.com/thread-27037-1-2.html 如今越来越多的开发者使用Unity开发Android及iOS项目,开发过程中难免会遇到一些性能 ...

  7. 区块链:基于Hyperledger Fabric的 java 客户端开发(java sdk /java api server/java event server)

    fabric针对java 开发的部分支持不是很友好.基于目前较为稳定的fabric 1.4版本,我们封装了一个java sdk,apiserver,eventServer 封装java sdk的主要目 ...

  8. 洛谷P2583 地铁间谍

    P2583 地铁间谍 题目描述 特工玛利亚被送到S市执行一个特别危险的任务.她需要利用地铁完成他的任务,S市的地铁只有一条线路运行,所以并不复杂. 玛利亚有一个任务,现在的时间为0,她要从第一个站出发 ...

  9. bzoj4889: [Tjoi2017]不勤劳的图书管理员(树套树)

    传送门 据说正解线段树套平衡树 然而网上参考(抄)了一个树状数组套动态开点线段树的 思路比较清楚,看代码应该就明白了 //minamoto #include<iostream> #incl ...

  10. .Net WebApi接口Swagger集成简单使用

    Swagger介绍 Swagger 是一款RESTFUL接口的.基于YAML.JSON语言的文档在线自动生成.代码自动生成的工具.而我最近做的项目用的是WebAPI,前后端完全分离,这时后端使用Swa ...