我从服务器接收XML块。那些块不是完整的段,但可以看起来像这样:
chunk1 = '<el a="1" b='
chunk2 = '"2"><sub c="'
chunk3 = '3">test</sub'
chunk4 = '></el><el d='
chunk5 = '"4" e="5"></'
chunk6 = 'el>'
我如何解析这个流,这样每当一个“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
然而,这种方法并没有真正起作用,因为当handle_element
偶然包含格式良好的XML文档时,它只调用text
,但不能保证这种情况永远都是如此。
答案 0 :(得分:2)
您可以使用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)
产量
<Element 'el' at 0xb744f6cc>
<Element 'el' at 0xb744f84c>
ET.iterparse
的第一个参数通常是文件名,或者是io.BytesIO或StringIO对象。但是,它可以是具有read
方法的任何对象。因此,如果您创建一个read方法从服务器读取的对象,则可以将其挂钩到ET.iterparse
以进行增量解析。
请注意ET.iterparse
将使用请求的字节数(例如read(16384)
)调用read方法。如果这是服务器给你的全部,你可以返回更少的字节,但是我不确定如果你返回超过请求的字节数,是否会发生任何错误。理想情况下,您应该能够将请求的字节数传递给服务器,并依赖服务器提供正确的字节数(或更少)。
答案 1 :(得分:0)
您正在尝试在拥有正确的XML sting之前创建一个XML对象(我相信您已经弄明白了)。基本上,您将所有字符串/块连接在一起(加入),一旦拥有完整的XML,使用完整的字符串创建XML对象。使用io.BytesIO或io.StringIO,每当从服务器获取内容时,将其写入缓冲区,然后解析缓冲区并取出所需内容。
扭曲的例子:
from io import StringIO
def __init__(self):
self.buffer = StringIO() # Buffer obj
def dataReceived(self, data):
# this is data that is received from the server
self.buffer.write( data ) # Usually want this in a callBack
def processBuffer(self):
string = self.buffer.getvalue()
''' Do your parsing
Then once you have the complete xml
do etree.fromstring( string ) or equivalant'''
希望有所帮助,我们在工作中做了类似的事情,但我不记得我们是如何实现的。