タスクは、単純な XML ドキュメントを解析し、内容を行番号で分析することです。
正しい Python パッケージはxml.sax
. しかし、どのように使用するのですか?
ドキュメントを掘り下げた後、次のことがわかりました。
xmlreader.Locator
インターフェイスには次の情報があります:getLineNumber()
。handler.ContentHandler
インターフェイスにはsetDocumentHandler()
.
最初に考えられるのは、 を作成しLocator
、これを に渡し、メソッドのContentHandler
呼び出し中に Locator から情報を読み取る、などです。character()
ただし、xmlreader.Locator
はスケルトン インターフェイスにすぎず、そのメソッドのいずれからも -1 しか返せません。それで、貧弱なユーザーとして、私は何をすべきでしょうParser
かLocator
?
私は今、自分の質問に答えます。
(まあ、私はできないという恣意的で迷惑なルールを除いて、私は持っているでしょう。)
既存のドキュメントを使用して (または Web 検索で) これを理解することができず、xml.sax
(私のシステムの /usr/lib/python2.7/xml/sax/ の下にある) のソース コードを読むことを余儀なくされました。
xml.sax
関数make_parser()
はデフォルトで実数を作成しますが、それParser
はどのようなものですか?
ソース コードでは、ExpatParser
expatreader.py で定義されている であることがわかります。そして...それは独自のLocator
、を持っていExpatLocator
ます。しかし、これにはアクセスできません。これと解決策の間で多くの頭を悩ませました。
- r
ContentHandler
について知っている独自の を作成し、それを使用して行番号を決定しますLocato
ExpatParser
で作成xml.sax.make_parser()
- を作成し、インスタンス
ExpatLocator
に渡します。ExpatParser
- を作り、
ContentHandler
これを与えるExpatLocator
ContentHandler
をパーサーに渡すsetContentHandler()
- を呼び出し
parse()
ますParser
。
例えば:
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
場合、適切なLocator
.
利点: 独自のものを作成する必要はありませんLocator
(または作成方法を見つける必要はありません)。欠点: どこにも文書化されておらず、文書化されていないプライベート変数を使用するのは適切ではありません。
ありがとうマルティン!