专栏首页Python程序员杂谈python项目练习三:万能的XML

python项目练习三:万能的XML

这个项目的名称与其叫做万能的XML不如叫做自动构建网站,根据一份XML文件,生成对应目录结构的网站,不过只有html还是太过于简单了,如果要是可以连带生成css那就比较强大了。这个有待后续研发,先来研究下怎么html网站结构。 既然是通过XML结构生成网站,那所有的事情都应该由这个XML文件来。先来看下这个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,两种处理方式不同点在于速度和范围,前者讲究的是效率,每次只处理文档的一小部分,快速而能有效的利用内存,后者是相反的处理方式,先把所有的文档载入到内存,然后再进行处理,速度比较慢,也比较消耗内存,唯一的好处就是可以操作整个文档。

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

有了上面的这些认识,我们已经知道如何处理xml文件了,然后再来看那个罪恶的源头website.xml文件,分析其结构,只有两个节点:page和directory,很明显page表示一个页面,directory表示一个目录。

所以处理这个xml文件的思路就变的清晰了。读取xml文件的每一个节点,然后判断是page还是directory如果是page则创建html页面,然后把节点中的内容写到文件里。如果遇到directory就创建一个文件夹,然后再处理其内部的page节点(如果存在的话)。

下面来看这部分代码,书中的实现比较复杂,比较灵活。先来看,然后在分析。

.. code:: python

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

看起来这个程序上面分析的复杂了一些,不过伟人毛毛说过,任何复杂的程序都是纸老虎。那我们再来分析一下这个程序。

首先看到这个程序是有两个类,其实完全可以当作一个类,因为有了继承。

然后再来看它多了些什么,除了我们分析出来的startElement和endElement以及characters,多出来了startPage,endPage;startDirectory,endDirectory;defaultStart,defaultEnd;ensureDirectory;writeHeader,writeFooter;和dispatch,这些个函数。除了dispatch,前面的函数都很好理解,每一对函数都是单纯的处理对应的html标签以及xml节点。而dispatch比较复杂,复杂之处在于他是用来动态拼合函数并且进行执行的。

dispatch的处理思路是,首先根据传递的参数(就是操作名称以及节点名称)判断是否存在对应的函数如startPage,如果不存在则执行default+操作名称:如defaultStart。

一个函数一个函数搞清楚之后,就知道整个处理流程是什么样了。首先创建一个public_html的文件,存放整个网站,然后读xml的节点,通过startElement和endElement调用dispatch进行处理。然后就是dispatch怎么调用具体的处理函数了。 到此为止,这个项目算是分析完了。

主要掌握的内容一个是python中使用SAX处理XML,另一个就是python中的函数的使用,比如getattr,传参数时的星号……

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • python项目练习十:DIY街机游戏

    终于来到了最后一个项目,看看前面的那些练习,也算是熟悉了python的基本操作,也知道python能干哪些事情,最后一个项目相比于以前的稍微复杂些,但是任何一个...

    the5fire
  • python项目练习五:虚拟茶话会

    几乎在学习、使用任何一种编程语言的时候,关于socket的练习从来都不会少,尤其是会写一些局域网的通信的东西。所以书上的这个项目刚好可以练习一下socket编程...

    the5fire
  • python项目练习一:即时标记

    这是《python基础教程》后面的实践,照着写写,一方面是来熟悉python的代码方式,另一方面是练习使用python中的基本的以及非基本的语法,做到熟能生巧。

    the5fire
  • 《流畅的Python》第十章学习笔记

    注意:调用__repr__函数的目的是调试,因此绝对不能抛出异常,尽量输出有用的内容,让用户能够识别目标对象。

    zx钟
  • python模块:win32com用法详解

    import win32com from win32com.client import Dispatch, constants

    菲宇
  • python高级编程第二讲:类与对象深度问题与解决技巧

    将上面的代码我们进行改造,引入内存跟踪的类,并且将2个类分别实例化100000次,并打印相应的内存大小

    小海怪的互联网
  • Python《植物大战僵尸》代码实现:植物卡片选择和种植

    最近一直在给这个植物大战僵尸游戏添加新的植物和僵尸, 因为网上的图片资源有限,能加的植物和僵尸比较少, 目前进展如下。

    AI科技大本营
  • 用 Python 实现植物大战僵尸代码

    导读:以前很火的植物大战僵尸游戏,本想在网上找个Python版本游戏学习下,无奈没有发现比较完整的,那就自己来写一个吧。

    华章科技
  • 数据结构之——Python实现循环队列

    栈是先入后出,与之相反的是队列,队列是先进先出的线性结构。队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。允许插入的一端称为队尾,允许删除的一端...

    py3study
  • wxPython_03_常用控件--Grid,ListBox,ListCtrl,TreeCtrl​

    wxPython各种控件用法官方手册 : http://xoomer.virgilio.it/infinity77/wxPython/widgets.html

    码农帮派

扫码关注云+社区

领取腾讯云代金券