3. Python脚本学习实战笔记三 主流的XML

3. Python脚本学习实战笔记三 主流的XML

本篇名言:“有种力量叫放大目标,有种智慧叫把问题缩小,有种承诺叫人生诚信,有种约定叫顶峰相见,有种幸福叫结缘惜缘,有种信念叫必定成功!”

本次项目中来看看,如何使用XML来表示多种数据,以及如何使用适合XML或SAM的简单API来处理XML文件。

1.  需求

很多项目需要解析XML文件。因为使用XML几乎能表示任何数据,并且在解析的时候可以随意处理数据,所以应用程序的能力是无穷的。

                  关于XML的资料,查看附录介绍。

                  本次项目的具体目标如下:

1、  整个网站应该用一个XML文件描述

2、  程序应该能创建所需的目录和网页

3、  可以轻松改变整个网站的设计,以新的设计为基础重新生成所有网页

 

2.  工具及准备

Python有内建的XML支持。需要一个可以工作的SAX语法分析器。

通过如下命令进行查看:

>>>from xml.sax import make_parser

>>>parser=make_parser()

>>> 

没问题就OK。

当然,除了标准的PyXML框架之外,可以选择ElementTree。

我们还需要表示网站的XML文件。

2.1      website.xml

<website>

  <page name="index"title="Home Page">

    <h1>Welcome to My HomePage</h1>

 

    <p>Hi, there. My name is Mr. Gumby,and this is my home page. Here

    are some of my interests:</p>

 

    <ul>

      <li><ahref="interests/shouting.html">Shouting</a></li>

      <li><ahref="interests/sleeping.html">Sleeping</a></li>

      <li><ahref="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 SleepingPage</h1>

 

      <p>...</p>

    </page>

    <page name="eating"title="Eating">

      <h1>Mr. Gumby's EatingPage</h1>

 

      <p>...</p>

    </page>

  </directory>

</website>

 

 

 

3.  初次实现

可以使用SAX来解析XML,包括编写一组事件处理程序。当解析器读XML文档的时候,可以让它调用这些处理程序完成解析工作。

                  (在Python中有两种方法来处理XML: SAX和 DOM文档对象模型。SAX语法分析器读取XML文件,一次只存储文档的一小部分,所以简单、快速并能有效利用内存。DOM走的是另外一条路:它构造一个表示整个文档的数据结构,这样会慢些并且需要更多内存,如果希望操作整个文档结构的话则很有用。 pyRXP是快速且简单的XML语法分析器,ElementTree则更加灵活易用。)

3.1      创建简单的内容处理程序      

使用SAX进行解析时,有很多事件类型,本次只用3个:元素的起始、元素的结束以及纯文本。

                  要解析XML文件,可使用xml.sax模块的parse函数。这个函数负责读取文件并且生成事件,由于生成3类事件所以需要调用一些事件处理程序。这些事件处理程序会作为内容处理程序对象的方法来实现。需要继承xml.asx.handler中的ContentHandler类,该类实现了所有需要的事件处理程序,在需要的时候覆盖这些函数。

                  示例如下:

fromxml.sax.handler importContentHandler

fromxml.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 inattrs.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 ())

输出4个html文件:index.html, eating.html, shouting.html, sleeping.html

                  每个HTML文件都是page段。

其中index.html打开如下

HeadlineHandler会一直关注当前解析的文本是否包含在一对h1标签中。找到一个h1标签设置内置BOOL值为TRUE,找到下一个,则设置为FALSE。这类使用BOOL变量判断当前是否位于给定标签类型内是SAX程序设计中非常普遍。

4.  重构

与标准泛型事件处理程序如startElement中编写大段if语句,不如编写自己的具体程序,并且自动调用他们。混入类可以实现这个功能,然后将这个类和ContentHandler一同继承。

                  右面实现有点类似第一个项目中的程序处理模块,根据start+page就调用 startPage函数。

4.1      目录支持

创建目录需要os和os.path模块中的函数。

4.2      事件处理

需要4个对象,两个处理目录,两个处理页面。

 

5.  交付

最后交付如下:

fromxml.sax.handler importContentHandler

fromxml.sax import parse

importos

 

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)

        ifnotos.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 inattrs.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):

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

 

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

有两个类一个Dispatcher ,一个WebsiteConstructor.

WebsiteConstructor继承于Dispatch和ContentHandler.

事件触发的时候先会调用Dispatch中的startElement函数,然后通过startElement函数来分发。endElement也类似。

 

 

最后输出

Public_html目录

Public_html/index.html 文件

Public_html/interests目录

Public_html/interests/shouting.html

Public_html/interests/sleeping.html

Public_html/interests/eating.html

 

 

 

 

 

 

 

 

6.  附录

6.1      XML

1998年2月,W3C正式批准了可扩展标记语言的标准定义,可扩展标记语言可以对文档和数据进行结构化处理,从而能够在部门、客户和供应商之间进行交换,实现动态内容生成,企业集成和应用开发。可扩展标记语言可以使我们能够更准确的搜索,更方便的传送软件组件,更好的描述一些事物。例如电子商务交易等。

可扩展标记语言是一种元标记语言,即定义了用于定义其他特定领域有关语义的、结构化的标记语言,这些标记语言将文档分成许多部件并对这些部件加以标识。XML 文档定义方式有:文档类型定义(DTD)和XMLSchema。DTD定义了文档的整体结构以及文档的语法,应用广泛并有丰富工具支持。XML Schema用于定义管理信息等更强大、更丰富的特征。XML能够更精确地声明内容,方便跨越多种平台的更有意义的搜索结果。它提供了一种描述结构数据的格式,简化了网络中数据交换和表示,使得代码、数据和表示分离,并作为数据交换的标准格式,因此它常被称为智能数据文档。

XML技术已经广泛应用于e-Learning应用系统的开发,大多数的商用e-Learning平台都支持XML标准。一些主要的网络设备制造商,如CISCO、JUNIPER等,生产的网络设备也已提供了对XML的支持,以利于今后基于XML的网络管理。

关于语法等其他细节,大家可以那本书籍进行学习一下。

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值