zoukankan      html  css  js  c++  java
  • python基础教程总结15——3 XML构建网址

    要求:

      网址用一个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>
    ')
                self.out.write('<title>%s</title>
    ‘ % attrs['title'])
                self.out.write('</head><body>
    ')
            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('
    <body></html>
    ’)
                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>
      <head>
      <title>")
        self.out.write(title)
        self.out.write("</title>
      </head>
      <body>
    ")
        
    def writeFooter(self):
        self.out.write("
      </body>
    </html>
    ")
    
    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>
     <head>
       <title>')
                    self.out.write(title)
                    self.out.write('</title>
     </head>
      <body>
    ')
    
            def writeFooter(self):
                    self.out.write('
     </body>
    </html>
    ')
    
    parse('website.xml',WebsiteConstructor('public_html'))
  • 相关阅读:
    3. Longest Substring Without Repeating Characters
    2. Add Two Numbers
    Concurrent Programming(5)
    Concurrent Programming(4)
    Concurrent Programming(3)
    Concurrent Programming(2)
    Concurrent Programming(1)
    Lua用table模拟二维数组
    C#深入研究ArrayList动态数组自动扩容原理
    ==与Equals的作用
  • 原文地址:https://www.cnblogs.com/zxqstrong/p/4680376.html
Copyright © 2011-2022 走看看