我试图使用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个字符长度的块看起来有点过分。
答案 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
希望这有帮助。