当lxml的解析器目标被提供一个开始标记时,它不会立即触发'start'回调

时间:2012-05-24 09:01:30

标签: python xml lxml

我试图使用lxml的parser target interface逐步将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个字符长度的块看起来有点过分。

1 个答案:

答案 0 :(得分:1)

从阅读文档看,这似乎是预期的行为(引自http://lxml.de/parsing.html#the-feed-parser-interface):

  

“如果你不调用close(),解析器将保持锁定状态   后续的Feed会保留附加数据,通常会导致非数据   格式良好的文档和意外的解析器错误。所以请确保你   在使用后总是关闭解析器,也在异常情况下关闭。“

因此,解析器正在“等待”更多信息被馈送或关闭。您可以通过调用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

希望这有帮助。