zoukankan      html  css  js  c++  java
  • 第22章 项目3:万能的XML

    Mix-in:混入类,是一种Python程序设计中的技术,作用是在运行期间动态改变类的基类或类的方法,从而使得类的表现可以发生变化。可以用在一个通用类接口中。

    在实践一个解析XML文件的实践中,体会动态改变的格式。

    格式一般是:

    定义一个基类:

    class base:

    def startElement(self,prefix,name,*args):

    self.callback('Start',name,*args)

    def callback(self,prefx,name,*args):

    mname = prefix + name

    method = getattr(self,mname,None)

    if callbale(method): method(*args)

    然后定义一个子类,在里面实现prefix+name的方法。

    处理xml的内置库:

    from xml.sax.hander import ContentHandler

    from xml.sax import parse

    parse('xmlfile', instanceofContentHandler)

    首先检查是否有可用的SAX语法分析器:

    from xml.sax import make_parser

    parser = make_parser

    没有引发任何异常,可以使用。

    20-1 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 interests:</p>

    <ul>
    <li><a herf="interests/shouting.html">Shouting</a></li>
    <li><a herf="interests/sleeping.html">Sleeping</a></li>
    <li><a herf="interests/eating.html">Eating</a></li>
    </ul>
    </page>
    <directory name="interests">
    <page name="shouting" title="Shouting">
    <h1>Mr. Gumby's Shouting Page</h1>

    <p>...</p>
    </page>
    <page name="sleeping" title="Sleeping">
    <h1>Mr. Gumby's Sleeping Page </h1>

    <p>...</p>
    </page>
    <page name="eating" title="Eating">
    <h1>Mr. Gumby's Eating Page </h1>

    <p>...</p>
    </page>
    </directory>
    </website>

     

    最小型的XML语法分析器:web1.py

    # coding=utf-8
    from xml.sax.handler import ContentHandler
    from xml.sax import parse
    # ContentHandler是内容处理器,实现了所以需要的事件处理程序(没有任何效果的伪操作)
    class TestHandler(ContentHandler): pass
    parse('website.xml', TestHandler()) # parse负责读取文件并生成事件

    执行之后,未报错也无输出

    简单的扩展 web2.py

    def startElement(self, name, attrs):
    print name, attrs.keys()
    添加到类TestHandler

    # coding=utf-8
    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())

    输出:

    website []

    page [u'name', u'title']

    h1 []

    p []

    ul []

    li []

    a [u'herf']

    li []

    a [u'herf']

    li []

    a [u'herf']

    directory [u'name']

    page [u'name', u'title']

    h1 []

    p []

    page [u'name', u'title']

    h1 []

    p []

    page [u'name', u'title']

    h1 []

    p []

    建立网站大标题(h1元素列表) web3.py

    使用startElementendElementcharacters三种方法

    # coding=utf-8
    from xml.sax.handler import ContentHandler
    from xml.sax import parse

    class HeadHandler(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_headline = True

    def endElement(self, name): # endElement只用标签名作为参数
    if name == 'h1':
    text = ''.join(self.data)
    self. data = []
    self.headlines.append(text)
    self.in_headline = False

    def characters(self, string): # characters使用字符串作为参数
    if self.in_headline:
    self.data.append(string)

    headlines = []
    parse('website.xml', HeadHandler(headlines))

    print 'The following <h1> elements were found:'
    for
    h in headlines:
    print h

    输出:

    The following <h1> elements were found:

    Welcome to My Home Page

    Mr. Gumby's Shouting Page

    Mr. Gumby's Sleeping Page

    Mr. Gumby's Eating Page

     

     

    22-2 pagemaker.py

    生成4HTML文件:

    index.html

    <html><head>
    <title>Home Page</title>
    </head><body>

    <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 interests:</p>

    <ul>
    <li><a herf="interests/shouting.html">Shouting</a></li>
    <li><a herf="interests/sleeping.html">Sleeping</a></li>
    <li><a herf="interests/eating.html">Eating</a></li>
    </ul>

    </body></html>

     

    22-3 网站构造函数(website.py

    调度程序的混入类

    基本事件处理程序:

    class Dispatcher:
    #...
    def startElement(self, name, attrs):
    self.dispatch('start', name, attrs)
    def endElement(self, name):
    self.dispatch('end', name)

    dispatch()方法:

    查找合适的处理程序,构造参数元组,然后使用这些参数调用处理程序。

    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)

    以上程序是这样构造的:首先获取组合函数名(mname,dname),然后判断是否存在这样的函数(callable),存在就是startname,endname否则是defaultname

     

    内容处理程序:

    class TestHandler(Dispatcher, ContentHandler):
    def startPage(self, attrs):
    print 'Begining page', attrs['name']
    def endPage(self):
    print 'Ending page'

     

    以上内容写入webTest.py

    # coding=utf-8
    from xml.sax.handler import ContentHandler

    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 TestHeanler(Dispatcher, ContentHandler):
    def startPage(self, attrs):
    print 'Begining page', attrs['name']
    def endPage(self):
    print 'Ending page'

    运行无输出,也没有报错。

    该调度程序混入类实现了大部分的探测功能,下面添加更多功能。

     

     

    22-3 网站构造函数 website.py

    # coding=utf-8
    from xml.sax.handler import ContentHandler
    from xml.sax import parse
    import os

    class Dispatcher:
    """
    是一个混合类,和第一个项目中有相似之处,因为要处理不同的标记,所以
    通过前缀名来指定处理函数更加方便。利用混合类管理一些细节也很容易
    """
    # dispatch()方法,用于查找合适的处理程序,构造参数元组,然后使用这些参数调用处理程序。
    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):
    """
    内容处理程序:
    在利用SAX在解析XML文件时,要用到Parser这个函数,这个函数在读取文件以及处理这些文件时,要相应的利用一些时间处理程序。
    继承CotentHandler是因为这个类中实现了几乎所有时间处理程序,当然也可以在本程序中重写里面的时间处理函数来进行覆盖使用。
    """
    passthrough= False # 设定布尔变量,处理特殊标签时由于要忽略一些内部标签及特殊处理,需要判断文件解析器是否要停止处理。

    # 构造函数,网站的根目录作为参数
    def __init__(self, directory):
    self.directory = [directory]
    self.ensureDirectory()

    # 这个函数主要利用os模块中对文件操作的特性,为xml文件中每一个页面都创建一个相应目录存放html文件,确保当前目录存在
    def ensureDirectory(self):
    path = os.path.join(*self.directory)
    if not os.path.isdir(path): os.makedirs(path) # 如果没有这个路径就创建

    def characters(self, chars):
    if self.passthrough: self.out.write(chars)

    # 使用defaultStart和defaultEnd对XHTML进行处理,两个默认的函数都是处理页面标签中的一些其他标签。
    # 这些页面中的所有标签在这里都做了忽略处理
    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)

    # 目录处理程序,使用directory和ensureDirectory方法。这两个函数是为了在xml文件中碰见不同的目录要进行创建,
    # 但是创建之后要删除,避免不同目录的页面最后出现在同样的目录下面
    def startDirectory(self, attrs):
    self.directory.append(attrs['name'])
    self.ensureDirectory()
    def endDirectory(self):
    self.directory.pop()

    # 页面处理程序,使用writeHeader和writeFooter方法,设定passthrough变量,打开和关闭与页面关联的文件。
    # 两个函数要处理页面,创建这个页面的html文件,然后添加上标题,打开这个文件,写入文件之后在关闭
    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()

    # 简单的首部和页脚
    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'))

     

    首先是从parse('website.xml', WebsiteConstructor('public_html'))开始,然后是进入WebsiteConstructor中,首先执行__init__函数创建public_html目录,然后开始startElement函数,并调用dispatch判断WebsiteConstructor是否有所需的函数,判断后进行程序运行,其中namedirectory则创建目录,否则就在文档里面写入语句,对于在文档中写入语句的多少依据passthrough判断。控制函数为characters函数。

    运行输出:index.htmlpublic文件夹及包括eating.htmlshouting.htmlsleepting.htmlinterests子文件夹

    打开public_html/index.html

  • 相关阅读:
    Android CTS(frome google)
    Android CTS
    【Linux】- 修改系统时间与时区
    【Linux】- CentOS查看IP
    【Linux】- Ubutnu UFW防火墙的简单设置
    【Linux】- Ubuntu安装nginx
    【Linux】- apt-get命令
    【Linux】- Ubuntu搭建FTP服务器
    【Linux】- Ubuntu 配置mysql远程访问
    【Linux】- Ubuntu安装redis,并开启远程访问
  • 原文地址:https://www.cnblogs.com/Sumomo0516/p/6131666.html
Copyright © 2011-2022 走看看