Python:解析不完整的 XML 块

bas*_*kum 5 python xml xml-parsing

我从服务器接收 XML 块。这些块不是完整的段,但可能看起来像这样:

chunk1 = '<el a="1" b='
chunk2 = '"2"><sub c="'
chunk3 = '3">test</sub'
chunk4 = '></el><el d='
chunk5 = '"4" e="5"></'
chunk6 = 'el>'
Run Code Online (Sandbox Code Playgroud)

我如何解析这个流,以便每当一个“el”元素完成时调用一个函数?

到目前为止,我正在采用这种方法(使用 ElementTree):

import xml.etree.ElementTree as ET

text = ""

def handle_message(msg):
    text += msg
    try:
        root = ET.fromstring("<root>" + text + "</root>")
        for el in list(root):
            handle_element(el)
        text = ""
        return True
    except ET.ParseError:
        return False
Run Code Online (Sandbox Code Playgroud)

然而,这种方法实际上并不起作用,因为它仅handle_elementtext意外包含格式良好的 XML 文档时调用,但不能保证永远都是这种情况。

unu*_*tbu 3

您也许可以使用ET.iterparse来增量解析 XML 块:

import xml.etree.ElementTree as ET

chunks = iter([
    '<root>'
    '<el a="1" b=',
    '"2"><sub c="',
    '3">test</sub',
    '></el><el d=',
    '"4" e="5"></',
    'el>',
    '</root>'
    ])


class Source(object):
    def read(self, size):
        # Replace this with code that reads XML chunks from the server
        return next(chunks)

for event, elem in ET.iterparse(Source(), events=('end', )):
    if elem.tag == 'el':
        print(elem)
        # handle_element(elem)
Run Code Online (Sandbox Code Playgroud)

产量

<Element 'el' at 0xb744f6cc>
<Element 'el' at 0xb744f84c>
Run Code Online (Sandbox Code Playgroud)

第一个参数ET.iterparse通常是文件名、io.BytesIO 或 StringIO 对象。然而,它可以是具有方法的任何对象read。因此,如果您创建一个对象,其 read 方法从服务器读取,那么您可以将其挂钩ET.iterparse以进行增量解析。

请注意,ET.iterparse将使用请求的字节数(例如read(16384))调用 read 方法。如果服务器给您的字节数就是这样,您可以返回更少的字节,但我不确定如果您返回的字节数多于请求的字节数是否会发生任何不好的事情。理想情况下,您应该能够将请求的字节数传递到服务器,并依赖服务器提供正确的字节数(或更少)。