3

lxml のパーサー ターゲット インターフェイスを使用して、XML を「カスタム」ツリーに段階的に解析しようとしましたが、次の問題に遭遇しました: パーサーをインスタンス化して、すぐにルート要素の開始タグ、「開始」ターゲットのコールバックは、他のイベント (着信データ、終了タグ、別の開始タグなど) が発生するまで発生しません。これは、他の (ネストされた) 要素では発生しないようです。

デモンストレーション:

class EchoTarget(object):
    def start(self, tag, attrib):
        print("start %s %s" % (tag, attrib))
    def end(self, tag):
        print("end %s" % tag)
    def data(self, data):
        print("data %r" % data)
    def comment(self, text):
        print("comment %s" % text)
    def close(self):
        print("close")
        return "closed!"

>>> p = etree.XMLParser(target=EchoTarget())
>>> p.feed('<a>') # nothing happens
>>> p.feed(' ') # suddenly..
start a {}
>>> p.feed('<b>') # works as expected
data u' '
start b {}

これを回避する方法があります。

>>> p = etree.XMLParser(target=EchoTarget())
>>> p.feed(' ')
>>> p.feed('<a>')
start a {}

これについての説明は何ですか?回避策は「有効」ですか?つまり、ストリームの最初の開始タグが「開始」コールバックを起動することを保証するために、この動作に依存しても安全ですか?

ところで、この結果を達成する別の方法があります。

>>> p = etree.XMLParser(target=EchoTarget())
>>> p.feed('<a')
>>> p.feed('>')
start a {}

ただし、ストリームを 2 文字の長さのチャンクに分割するのは少しやり過ぎのようです。

4

1 に答える 1

1

ドキュメントを読むと、これは予想される動作のようです(http://lxml.de/parsing.html#the-feed-parser-interfaceから引用):

「close()を呼び出さないと、パーサーはロックされたままになり、後続のフィードはデータを追加し続けます。通常、ドキュメントの形式が正しくなく、予期しないパーサーエラーが発生します。したがって、使用後も必ずパーサーを閉じてください。例外的な場合。」

したがって、パーサーは、さらにフィードされるか、クローズされるのを「待機」しています。closeメソッドを呼び出すことで、フィードしているものが(まだ)有効なXMLではないことを確認できます。

>>> p.feed('<a>')
>>> p.close()
start a {}
close
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "parser.pxi", line 1171, in lxml.etree._FeedParser.close (src/lxml/lxml.etree.c:79791)
  File "parsertarget.pxi", line 128, in lxml.etree._TargetParserContext._handleParseResult (src/lxml/lxml.etree.
c:88895)
  File "parser.pxi", line 590, in lxml.etree._raiseParseError (src/lxml/lxml.etree.c:74696)
XMLSyntaxError: Extra content at the end of the document, line 1, column 4

したがって、たとえば、開いたタグ(有効なXML)を閉じると、次のようになります。

>>> p = etree.XMLParser(target=EchoTarget())
>>> p.feed('<a>')
>>> p.feed('</a>')
start a {}
end a

お役に立てれば。

于 2012-07-13T11:17:20.647 に答える