美文网首页
07.XML处理之SAX编程

07.XML处理之SAX编程

作者: 杨强AT南京 | 来源:发表于2019-02-02 19:41 被阅读31次

Python标准库xml模块提供4个功能模块:
  sax -- 基于事件的XML文档处理;
  dom -- DOM接口实现;
  etree -- 文档树
  parsers -- XML解析器的Python包装器

一、sax功能模块

import xml.sax
# help(xml.sax)

1. sax API结构

sax提供四个模块来处理xml:
  xml.sax.xmlreader — xml的解析接口规范,抽象的,需要继承实现才能使用。
  xml.sax.handler — 回调处理器,如果与xmlreader绑定,当满足xml条件就会被调用,用来处理具体的xml内容。
  xml.sax.saxutils — 一些数据处理工具,比如实体转换什么的。
  xml.parsers.expat — xmlreader的具体实现,可以直接使用。也可以使用parse函数直接解析,或者使用make_parser返回解析器,或者直接构造ExpatParser解析器使用。

下面对核心模块xmlreader与handler进一步说明。

1.1. xmlreader API结构

提供如下几个类实现数据分析:
  |- AttributesImpl
    |- AttributesNSImpl
  |- InputSource
  |- Locator
  |- XMLReader
    |- IncrementalParser

1.2. handler API结构

提供4个Handler来处理xml内容。
  |- ContentHandler
  |- DTDHandler
  |- EntityResolver
  |- ErrorHandler

2. sax解析器的三种使用方式

2.1. sax编程模式

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

class MyHandler(xml.sax.handler.ContentHandler, xml.sax.handler.DTDHandler):
    def setDocumentLocator(self, locator):
        print('setDocumentLocator')

    def startDocument(self):
        print('startDocument')

    def endDocument(self):
        print('endDocument')

    def startPrefixMapping(self, prefix, uri):
        print('startPrefixMapping')

    def endPrefixMapping(self, prefix):
        print('endPrefixMapping')

    def startElement(self, name, attrs):
        print('startElement')

    def endElement(self, name):
        print('endElement')

    def startElementNS(self, name, qname, attrs):
        print('startElementNS')

    def endElementNS(self, name, qname):
        print('endElementNS')

    def characters(self, content):
        print('characters')

    def ignorableWhitespace(self, whitespace):
        print('ignorableWhitespace')

    def processingInstruction(self, target, data):
        print('processingInstruction')

    def skippedEntity(self, name):
        print('skippedEntity')

    def notationDecl(self, name, publicId, systemId):
        print('notationDecl')

    def unparsedEntityDecl(self, name, publicId, systemId, ndata):
        print('unparsedEntityDecl')


class MyError(xml.sax.ErrorHandler):

    def error(self, exception):
        print('error')
        return super().error(exception)

    def fatalError(self, exception):
        print('fatalError')
        return super().fatalError(exception)

    def warning(self, exception):
        print('warning')
        super().warning(exception)


xml.sax.parse(
    source='codes/note.xml',
    handler=MyHandler(),
    errorHandler=MyError())

setDocumentLocator
startDocument
startElement
characters
characters
startElement
characters
endElement
characters
characters
startElement
characters
endElement
characters
characters
startElement
characters
endElement
characters
characters
startElement
characters
endElement
characters
endElement
endDocument

2.3. 构造parser

注意:不能直接构造XMLReader,而是使用工厂模式函数:
  xml.sax.make_parser()来产生parser,要么直接调用parse函数解析处理xml。
  XMLReader是xml解析的接口规范,其实现就是:xml.sax.expatreader.ExpatParser

# coding = utf-8
import xml.sax.handler
import xml.sax.xmlreader

class MyHandler(xml.sax.handler.ContentHandler,xml.sax.handler.DTDHandler):
    def setDocumentLocator(self, locator):
        print('setDocumentLocator')

class MyError(xml.sax.ErrorHandler):

    def error(self, exception):
        print('error')
        return super().error(exception)

'''
xml.sax.parse(
    source='books.xml',
    handler=MyHandler(),
    errorHandler=MyError())
'''
handler = MyHandler()
error = MyError()
parser = xml.sax.make_parser()
print(parser)
parser.setContentHandler(handler)
parser.setErrorHandler(error)
parser.setDTDHandler(handler)
parser.parse('codes/note.xml')

<xml.sax.expatreader.ExpatParser object at 0x103f92160>
setDocumentLocator

2.4. ExpatParser的使用

   ExpatParser实现的接口类:
    |- class ExpatParser(xml.sax.xmlreader.IncrementalParser, xml.sax.xmlreader.Locator)
  下面是使用例子:

# coding = utf-8
import xml.sax.handler
import xml.sax.xmlreader
import xml.sax.expatreader


class MyHandler(xml.sax.handler.ContentHandler,xml.sax.handler.DTDHandler):
    def setDocumentLocator(self, locator):
        print('setDocumentLocator')



class MyError(xml.sax.ErrorHandler):

    def error(self, exception):
        print('error')
        return super().error(exception)

'''
xml.sax.parse(
    source='books.xml',
    handler=MyHandler(),
    errorHandler=MyError())
'''
handler = MyHandler()
error = MyError()
# parser = xml.sax.make_parser()
parser = xml.sax.expatreader.ExpatParser(namespaceHandling=True)
print(parser)
parser.setContentHandler(handler)
parser.setErrorHandler(error)
parser.setDTDHandler(handler)
parser.parse('codes/note.xml')

<xml.sax.expatreader.ExpatParser object at 0x103f9cbe0>
setDocumentLocator

3. handler的使用

  对DTDHandler这里不说明,

3.1. Locator的使用

Locator是文档定位,其实现类是ExpatLocator类。
  |- xml.sax.xmlreader.Locator(builtins.object)
  |- xml.sax.expatreader.ExpatLocator
该类使用是个函数提供四个信息:
  | - getColumnNumber(self) xml当前列数
  | - getLineNumber(self) xml当前行数
  | - getPublicId(self) xml的public ID:在Python中通常是None
  | - getSystemId(self) xml的system ID:通常就是xml文件

# coding = utf-8
import xml.sax.expatreader


class MyHandler(xml.sax.handler.ContentHandler):
    def setDocumentLocator(self, locator):
        print(f'system ID:{locator.getSystemId()}')
        print(f'public ID:{locator.getPublicId()}')
        print('行列位置(%d,%d)' % (locator.getLineNumber(),locator.getColumnNumber()))


handler = MyHandler()
error = xml.sax.ErrorHandler()

parser = xml.sax.expatreader.ExpatParser(namespaceHandling=True)
parser.setContentHandler(handler)
parser.setErrorHandler(error)
parser.setDTDHandler(handler)
parser.parse('codes/web.xml')

system ID:codes/web.xml
public ID:None
行列位置(1,0)

3.2. startDocument与endDocument的文档解析事件函数

  在文档解析开始的时候触发解析事件函数:startDocument,在文档解析结束的时候触发解析事件函数:endDocument。

# coding = utf-8
import xml.sax.expatreader


class MyHandler(xml.sax.handler.ContentHandler):

    def startDocument(self):
        print('开始文档解析')

    def endDocument(self):
        print('文档解析结束')


handler = MyHandler()
error = xml.sax.ErrorHandler()

parser = xml.sax.expatreader.ExpatParser(namespaceHandling=True)
parser.setContentHandler(handler)
parser.setErrorHandler(error)
parser.setDTDHandler(handler)
parser.parse('codes/books.xml')

开始文档解析
文档解析结束

3.3. startElement与endElement元素解析事件函数

   startElement函数在每个元素开始前触发。
  endElement函数在每个元素结束后触发。
  函数的原型如下:
    |- def startElement(self, name, attrs):
      |- name:类型是字符串str,表示元素名。
      |- attrs:类型是xml.sax.xmlreader.AttributesImpl,表示元素的所有属性。
    |- def endElement(self, name):

   其中attrs是属性列表,本质是一个字典,还有一些其他成员,可以使用帮助方式查看。

# coding = utf-8
import xml.sax.expatreader


class MyHandler(xml.sax.handler.ContentHandler):

    def startElement(self, name, attrs):
        print('元素解析开始,元素名:', name)
        # attrs是属性列表
        print(type(attrs), type(name))
        # 属性列表
        print('属性数:%d' % attrs.getLength())
        for item in attrs.items():
            print('属性名:%s,属性值:%s' % item)


    def endElement(self, name):
        print('元素解析结束,元素名:', name)


handler = MyHandler()
error = xml.sax.ErrorHandler()

# namespaceHandling 对具有命名空间的元素处理,没有命名空间设置围为0。
parser = xml.sax.expatreader.ExpatParser(namespaceHandling=0)
parser.setContentHandler(handler)
parser.setErrorHandler(error)
parser.setDTDHandler(handler)
parser.parse('codes/books.xml')

元素解析开始,元素名: books
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:0
元素解析开始,元素名: book
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:1
属性名:category,属性值:Python
元素解析开始,元素名: title
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:1
属性名:lang,属性值:zh
元素解析结束,元素名: title
元素解析开始,元素名: author
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:0
元素解析结束,元素名: author
元素解析开始,元素名: year
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:0
元素解析结束,元素名: year
元素解析开始,元素名: price
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:0
元素解析结束,元素名: price
元素解析开始,元素名: publisher
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:0
元素解析结束,元素名: publisher
元素解析结束,元素名: book
元素解析开始,元素名: book
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:1
属性名:category,属性值:系统运维
元素解析开始,元素名: title
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:1
属性名:lang,属性值:zh
元素解析结束,元素名: title
元素解析开始,元素名: author
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:0
元素解析结束,元素名: author
元素解析开始,元素名: year
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:0
元素解析结束,元素名: year
元素解析开始,元素名: price
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:0
元素解析结束,元素名: price
元素解析开始,元素名: publisher
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:0
元素解析结束,元素名: publisher
元素解析结束,元素名: book
元素解析开始,元素名: book
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:1
属性名:category,属性值:区块链
元素解析开始,元素名: title
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:1
属性名:lang,属性值:en
元素解析结束,元素名: title
元素解析开始,元素名: author
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:0
元素解析结束,元素名: author
元素解析开始,元素名: year
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:0
元素解析结束,元素名: year
元素解析开始,元素名: price
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:0
元素解析结束,元素名: price
元素解析开始,元素名: publisher
<class 'xml.sax.xmlreader.AttributesImpl'> <class 'str'>
属性数:0
元素解析结束,元素名: publisher
元素解析结束,元素名: book
元素解析结束,元素名: books

3.4. characters文本解析事件函数

  函数原型是:characters(self, content)
    参数:content是文本内容。

# coding = utf-8
import xml.sax.expatreader


class MyHandler(xml.sax.handler.ContentHandler):

    def characters(self, content):
        # 为了看见所有的字符,下面输出采用子节序列。
        # 下面的文本包含所有元素结束的换行字符。
        print(content.encode('utf-8'))


handler = MyHandler()
error = xml.sax.ErrorHandler()

# namespaceHandling 对具有命名空间的元素处理,没有命名空间设置围为0。
parser = xml.sax.expatreader.ExpatParser(namespaceHandling=0)
parser.setContentHandler(handler)
parser.setErrorHandler(error)
parser.setDTDHandler(handler)
parser.parse('codes/note.xml')

b'\n'
b'    '
b'Tove'
b'\n'
b'    '
b'Jani'
b'\n'
b'    '
b'Reminder'
b'\n'
b'    '
b"Don't forget me this weekend!"
b'\n'

3.5. startElementNS与endElementNS带命名空间名的元素解析事件函数

  startElementNS(self, name, qname, attrs)
    |- qname:命名空间,qname是qualified name 的简写,比如:<song:id>。
    |- name:与startElement不同,这里是一个元组,格式如下:(uri, localname)

# coding = utf-8
import xml.sax.expatreader


class MyHandler(xml.sax.handler.ContentHandler):

    def startElementNS(self, name, qname, attrs):
        print(name, qname)
    def endElementNS(self, name, qname):
        print('结束:', name)
    


handler = MyHandler()
error = xml.sax.ErrorHandler()

# namespaceHandling 对具有命名空间的元素处理,没有命名空间设置围为0。
parser = xml.sax.expatreader.ExpatParser(namespaceHandling=True)
parser.setContentHandler(handler)
parser.setErrorHandler(error)
parser.setDTDHandler(handler)
parser.parse('codes/song.xml')

('http://www.example.org/athena', 'body') None
('http://www.example.org/athena', 'id') None
结束: ('http://www.example.org/athena', 'id')
('http://www.example.org/athena', 'name') None
结束: ('http://www.example.org/athena', 'name')
('http://www.example.org/athena', 'birthday') None
结束: ('http://www.example.org/athena', 'birthday')
结束: ('http://www.example.org/athena', 'body')

3.6. startPrefixMapping与endPrefixMapping解析事件函数

  命名空间前缀映射解析事件。
  startPrefixMapping(self, prefix, uri):
    |- prefix :前缀
    |- uri:uri

# coding = utf-8
import xml.sax.expatreader


class MyHandler(xml.sax.handler.ContentHandler):


    def startPrefixMapping(self, prefix, uri):
        print(prefix, uri)

    def endPrefixMapping(self, prefix):
        print(prefix)


handler = MyHandler()
error = xml.sax.ErrorHandler()

# namespaceHandling 对具有命名空间的元素处理,没有命名空间设置围为0。
parser = xml.sax.expatreader.ExpatParser(namespaceHandling=True)
parser.setContentHandler(handler)
parser.setErrorHandler(error)
parser.setDTDHandler(handler)
parser.parse('codes/song.xml')

song http://www.example.org/athena
xsi http://www.w3.org/2001/XMLSchema-instance
xsi
song

3.7. 其他

  还有一些其他事件函数,这里不详细解释。比如:
  processingInstruction(self, target, data)函数就是处理'<?xml version="1.0" encoding="UTF-8"?>'。但实际不触发该函数。

注意:
   SAX解析处理XML比较麻烦,我们都不直接使用,这里只是说明xml的处理底层细节。

总结:
  sax模块结构分成两个标准接口定义:handler与xmlreader,一个实现模块expatreader,一个工具模块saxutils。

相关文章

  • 07.XML处理之SAX编程

    Python标准库xml模块提供4个功能模块:  sax -- 基于事件的XML文档处理;  dom -...

  • PYTHON XML解析-SAX解析

    1.SAX模块 SAX是一种基于事件驱动的API,利用SAX解析XML牵扯到两个部分,解析器和事件处理器。其中解析...

  • 2020-12-09:python-sax

    Python中解析xml接口一般有SAX、DOM、ElementTree,SAX是基于事件处理机制,有“解析器”和...

  • 工作iOS技术总结

    链式编程、函数式、面向接口编程思想 iOS 之ReactiveCocoa 链式编程2 WKWebView的缓存处理...

  • XML解析--SAX

    XML结构 事件模型 SAX处理XML数据是采用事件的形式来处理,下面我们来简单的做个介绍: 当我们处理XML数据...

  • Senior进阶 网络之数据解析之XML解析和JSON解析的用法

    Senior进阶 网络之数据解析之XML解析和JSON解析的用法 XML解析之SAX解析 XML解析之DOM解析 ...

  • 3.xml中Sax解析实例

    1.Sax解析原理 2.Sax解析的功能 3.Sax解析xml的步骤 MyDefaultHander 继承 Def...

  • XML解析方式:sax、pull 、dom

    Sax 定义 SAX全称是Simple API for Xml,既是指一种接口,也是一个软件包 。作为接口,sax...

  • xml解析中sax解析

    xml解析中的sax解析:1,工作方式:逐步扫描xml文档,当遇到标签时触发解析处理器,通过事件处理的方式来解析x...

  • 解析XML文件的方式(三)之SAX

    SAX采用自顶向下逐行解析,解析效率比DOM快,内存占用小。 0、要处理的XML文件 1、创建DeaultHand...

网友评论

      本文标题:07.XML处理之SAX编程

      本文链接:https://www.haomeiwen.com/subject/cyfesqtx.html