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