• 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'))
  • 相关阅读:
    Serialization and deserialization are bottlenecks in parallel and distributed computing, especially in machine learning applications with large objects and large quantities of data.
    Introduction to the Standard Directory Layout
    import 原理 及 导入 自定义、第三方 包
    403 'Forbidden'
    https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2
    These interactions can be expressed as complicated, large scale graphs. Mining data requires a distributed data processing engine
    mysqldump --flush-logs
    mysql dump 参数
    mysql dump 参数
    如果是在有master上开启了该参数,记得在slave端也要开启这个参数(salve需要stop后再重新start),否则在master上创建函数会导致replaction中断。
  • 原文地址:https://www.cnblogs.com/zxqstrong/p/4680376.html
Copyright © 2020-2023  润新知