在Python中从套接字流构建/解析XML文档

3 投票
1 回答
3254 浏览
提问于 2025-04-16 22:52

我遇到了一个问题,想要解析一个不断发送过来的多个 XML 文档,这些文档是通过一个网络连接(socket)由第三方发送的。下面是通过 socket 发送的 XML 流的一个示例:

<?xml version="1.0"?><event><user id="1098"/><viewpage>109958</viewpage></event>
<?xml version="1.0"?><event><user id="1482"/><actions><edit>102865</edit><commit>1592356</commit></actions></event>
etc.

这是我正在使用的代码:

import socket
import xml.etree.cElementTree as etree
from StringIO import StringIO

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "IP.IP.IP.IP"
port = "8080"
addr = (host,port)
s.connect(addr)

def iparse(packet):
    for _, element in etree.iterparse(packet):
        print ("%s, %s" %(element.tag, element.text))
        element.clear()
    #if complete <event> node received, publish node

data = "<feeds>"
while 1:
    chunk = s.recv(1024)
    #replace the xml doc declarations as comments
    data += (chunk.replace("<?","<!--")).replace("?>","-->")
    iparse(StringIO(data))

一切运行得很好……不过,iparse 里的 for 循环每次都要遍历整个文档。有没有可能让 iparse 只处理一个完整的标签节点(事件),也就是在流中出现时就处理它?需要注意的是,我无法设置读取的块大小来获取一个完整的数据包。我可以使用一个缓冲区,等数据包完整后再发送给 iparse,但这样可能会引入不必要的延迟?有没有更好的处理方法?

补充说明:

每个事件都是独立的,但在根节点 <event> 下包含任意节点。iparse 需要将最新的事件发布给任意数量的订阅者,这些订阅者是在一个实时分析图形系统中。

1 个回答

0

你可以看看 lxml.etree 里的 feed parsing(数据流解析)。不过,你可能还是会遇到问题,因为你的文档会不断增大。

这些XML数据块是用换行符分开的么?如果是的话,我建议你先把数据缓存起来,等到遇到换行符再把每一行发送给XML解析器。就像 Twisted的LineReceiver那样。

其实如果是我,我可能会用 Twisted 来写这个应用。对我来说,把网络服务连接起来是它的一个常见用途。

撰写回答