python - 当输入开始标记时,lxml 的解析器目标不会立即触发 'start' 回调

标签 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 个字符长度的 block 似乎有点矫枉过正。

最佳答案

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

"If you do not call close(), the parser will stay locked and subsequent feeds will keep appending data, usually resulting in a non well-formed document and an unexpected parser error. So make sure you always close the parser after use, also in the exception case."

因此解析器正在“等待”更多内容被提供或关闭。您可以通过调用 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

希望这对您有所帮助。

关于python - 当输入开始标记时,lxml 的解析器目标不会立即触发 'start' 回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10734277/

相关文章:

Python nosetests 跳过某些测试

java - 我可以使用 CURL -u 访问 XML 数据,并使用 HTTP Basic Auth 在浏览器中获取它。如何在 Java 中复制该过程?

xml - 如果另一个子值匹配,则获取子值

c# - 将对象序列化为 XElement 并在内存中反序列化

python - 在 Python 中生成非常大的 XML 文件?

python - Windows 上的 Tensorflow - ImportError : DLL load failed: The specified module could not be found

python - 尝试获取 theta 值并将其打印为弧度

python - 在 python 中使用 lxml iterparse 解析大型 .bz2 文件 (40 GB)。未压缩文件不会出现的错误

python - 支持引号的XML转义字符串的静态python方法

python - 为 Google 云端硬盘中上传的私有(private)文件生成可下载链接