编程语言
首页 > 编程语言> > python-xml.sax解析器和行号等

python-xml.sax解析器和行号等

作者:互联网

任务是解析一个简单的XML文档,并按行号分析内容.

正确的Python包似乎是xml.sax.但是我该如何使用呢?

在对文档进行一些挖掘之后,我发现:

> xmlreader.Locator接口具有以下信息:getLineNumber().
> handler.ContentHandler接口具有setDocumentHandler().

首先想到的是创建一个定位器,将其传递给ContentHandler,并在调用其character()方法等期间从定位器中读取信息.

但是,xmlreader.Locator只是一个框架接口,并且只能从其任何方法返回-1.
因此,作为一个贫穷的用户,我该怎么办,而没有编写自己的完整解析器和定位器?

我现在将回答我自己的问题.

(好吧,除了说我不能的任意,烦人的规则外,我会有.)

我无法使用现有文档(或通过网络搜索)来弄清楚这一点,并且被迫读取xml.sax的源代码(在我的系统上的/usr/lib/python2.7/xml/sax/下).

xml.sax函数make_parser()默认创建一个真正的解析器,但是那是什么呢?
在源代码中,人们发现它是在expatreader.py中定义的ExpatParser.
而且…它有自己的定位器,即ExpatLocator.但是,无法访问此东西.
在此与解决方案之间,需要进行很多艰苦的努力.

>编写自己的ContentHandler,它知道定位器,并使用它来确定行号
>使用xml.sax.make_parser()创建一个ExpatParser
>创建一个ExpatLocator,并向其传递ExpatParser实例.
>制作ContentHandler,为其提供此ExpatLocator
>将ContentHandler传递给解析器的setContentHandler()
>在解析器上调用parse().

例如:

import sys
import xml.sax

class EltHandler( xml.sax.handler.ContentHandler ):
    def __init__( self, locator ):
        xml.sax.handler.ContentHandler.__init__( self )
        self.loc = locator
        self.setDocumentLocator( self.loc )

    def startElement( self, name, attrs ): pass

    def endElement( self, name ): pass

    def characters( self, data ):
        lineNo = self.loc.getLineNumber()
        print >> sys.stdout, "LINE", lineNo, data

def spit_lines( filepath ):
    try:
        parser = xml.sax.make_parser()
        locator = xml.sax.expatreader.ExpatLocator( parser )
        handler = EltHandler( locator )
        parser.setContentHandler( handler )
        parser.parse( filepath )
    except IOError as e:
        print >> sys.stderr, e

if len( sys.argv ) > 1:
    filepath = sys.argv[1]
    spit_lines( filepath )
else:
    print >> sys.stderr, "Try providing a path to an XML file."

Martijn Pieters在另一种方法下面指出了一些优点.
如果正确调用了ContentHandler的超类初始化程序,
那么事实证明,一个看起来私密的,没有证件的成员._locator是
集,其中应包含适当的定位符.

优势:您不必创建自己的定位器(或了解如何创建定位器).
缺点:它没有记录在案,并且使用未记录的私有变量是草率的.

谢谢马丁!

解决方法:

sax解析器本身应该为您的内容处理程序提供定位器.定位器必须实现某些方法,但是只要具有正确的方法,它就可以是任何对象. xml.sax.xmlreader.Locator class是定位器希望实现的接口;如果解析器为您的处理程序提供了一个定位器对象,那么您可以依靠定位器上存在的这4种方法.

仅鼓励解析器设置定位器,而无需这样做. expat XML解析器确实提供了它.

如果您将xml.sax.handler.ContentHandler()子类化,它将为您提供标准的setDocumentHandler()方法,并且在调用该处理程序上的.startDocument()时,您的内容处理程序实例将设置self._locator:

from xml.sax.handler import ContentHandler

class MyContentHandler(ContentHandler):
    def __init__(self):
        ContentHandler.__init__(self)
        # initialize your handler

    def startElement(self, name, attrs):
        loc = self._locator
        if loc is not None:
            line, col = loc.getLineNumber(), loc.getColumnNumber()
        else:
            line, col = 'unknown', 'unknown'
        print 'start of {} element at line {}, column {}'.format(name, line, col)

标签:saxparser,python,xml-parsing
来源: https://codeday.me/bug/20191031/1973312.html