【问题标题】:How to process text elements correctly with iterparse() in LXML?如何在 LXML 中使用 iterparse() 正确处理文本元素?
【发布时间】:2018-09-24 08:17:28
【问题描述】:

这是一个简单的 XML 文件:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
  <someThing>
    Text A: This is a test line.
    <p>Some paragraph.</p>
    Text B: This is another test line.
    <p>Some other paragraph.</p>
    Text C: And even another test line.
  </someThing>
</root>

虽然测试 XML 文件非常小,但我要处理的实际文件相当大:几 GB。因此,我想使用以下 Python 代码使用 iterparse() 解析此文件。

import xml.etree.ElementTree as etree
FILE_NAME = "test.xml"
for event, element in etree.iterparse(FILE_NAME, events=("start", "end", "start-ns", "end-ns")):
        print(event, "\t", element, "\t", repr(element.text))

如果我运行它,我会得到以下输出:

start    <Element 'root' at 0x7fd96a6aa728>      '\n\t'
start    <Element 'someThing' at 0x7fd968fba688>     '\n\t\tText A: This is a test line.\n\t\t'
start    <Element 'p' at 0x7fd968fcaf48>     'Some paragraph.'
end      <Element 'p' at 0x7fd968fcaf48>     'Some paragraph.'
start    <Element 'p' at 0x7fd968fcaf98>     'Some other paragraph.'
end      <Element 'p' at 0x7fd968fcaf98>     'Some other paragraph.'
end      <Element 'someThing' at 0x7fd968fba688>     '\n\t\tText A: This is a test line.\n\t\t'
end      <Element 'root' at 0x7fd96a6aa728>      '\n\t'

如您所见,&lt;p&gt; 元素之后的文本元素被忽略。

我的问题是:我需要如何使用 LXML API 来正确处理这个文件的内容?到目前为止,我能找到的关于该主题的所有示例都与我的一小段代码没有什么不同,因此遇到了同样的问题。如果这种情况不能用 LXML 完成,有人知道我可以使用的不同 XML 解析器并提供一个简短的例子吗?

【问题讨论】:

  • 在&lt;p&gt; 元素的tail 中找到缺失的文本片段。这是 ElementTree 和 lxml 的特性。请参阅 docs.python.org/3/library/… 和 infohost.nmt.edu/tcc/help/pubs/pylxml/web/etree-view.html。
  • 很奇怪 - 但感谢您提供这些信息!那是我最初寻找的东西。尽管如此,直接使用 SAX 似乎是更清洁的解决方案:我有大约一百万个条目嵌套在一个元素中,我无法阻止 etree API 收集这些条目。无论如何,etree 在后台使用 SAX。

标签: xml python-3.x lxml sax


【解决方案1】:

根据用户 mzjn 的友好评论,您可以使用 LXML 来做到这一点:有一个 tail 属性,缺少的文本被附加到。但由于以下原因,这可能不是最好的方法:

  • LXML 将不可避免地构造一棵大树(当然,在处理事件期间可以手动截断部分树,但这远非最佳)
  • 没有一个干净的单一事件来解析两个元素之间的文本,因此您必须通过解析 tail 来解决这个问题。

替代解决方案:直接使用 SAX API。

例子:

import xml.sax

FILE_NAME = "test.xml"

class MyHandler(xml.sax.handler.ContentHandler):

    def startElement(self, name, attrs):
        print("startElement\t" + repr(name))

    def endElement(self, name):
        print("endElement\t" + repr(name))

    def startElementNS(self, name, qname, attrs):
        print("startElementNS\t" + repr(name))

    def endElementNS(self, name, qname):
        print("endElementNS\t" + repr(name))

    def characters(self, content):
        print("  chars\t\t" + repr(content))

contentHandler = MyHandler()
xml.sax.parse(FILE_NAME, contentHandler)

上面的这个例子是处理巨大的 XML 文件的一个很好的起点。 characters() 方法将被每一个解析的文本调用。实体被解码并引起对characters() 的调用,因此很容易收集存储在 XML 元素中的所有文本。如果您在内容处理程序中实现一个简单的堆栈,该堆栈在对 startElement() 和 endElement() 的调用时增长和缩小,您可以轻松解析树的特定部分并省略您不需要处理的部分。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-22
    • 1970-01-01
    相关资源
    最近更新 更多