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 回答