在Python中对附加数据到外部XML文件的增量解析

时间:2015-03-03 07:14:58

标签: python xml python-2.6

我的LAN网络中的外部计算机上有一个日志文件。 Log是一个XML文件。无法从http访问文件,并且每秒都在更新。 目前我正在将日志文件复制到我的计算机并运行解析器,但我想直接从外部主机解析文件。

我怎样才能用Python做到这一点?是否有可能解析整个文件一次,然后在将来的版本中只解析添加到最后的新内容?

2 个答案:

答案 0 :(得分:4)

您可以使用paramikoxml.sax的默认解析器xml.sax.expatreader来实现xml.sax.xmlreader.IncrementalParser

我在本地虚拟机上运行以下脚本来生成XML。

#!/bin/bash

echo "<root>" > data.xml
I=0
while sleep 2; do 
  echo "<entry><a>value $I</a><b foo='bar' /></entry>" >> data.xml; 
  I=$((I + 1)); 
done

这是增量消费者。

#!/usr/bin/env python
# -*- coding: utf-8 -*-


import time
import xml.sax
from contextlib import closing

import paramiko.client


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

  lastEntry = None
  lastName  = None


  def startElement(self, name, attrs):
    self.lastName = name
    if name == 'entry':
      self.lastEntry = {}
    elif name != 'root':
      self.lastEntry[name] = {'attrs': attrs, 'content': ''}

  def endElement(self, name):
    if name == 'entry':
      print({
        'a' : self.lastEntry['a']['content'],
        'b' : self.lastEntry['b']['attrs'].getValue('foo')
      }) 
      self.lastEntry = None

  def characters(self, content):
    if self.lastEntry:
      self.lastEntry[self.lastName]['content'] += content


if __name__ == '__main__':
  # use default ``xml.sax.expatreader``
  parser = xml.sax.make_parser()
  parser.setContentHandler(StreamHandler())

  client = paramiko.client.SSHClient()
  # or use ``client.load_system_host_keys()`` if appropriate
  client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  client.connect('192.168.122.40', username = 'root', password = 'pass')
  with closing(client) as ssh:
    with closing(ssh.open_sftp()) as sftp:
      with closing(sftp.open('/root/data.xml')) as f:
        while True:
          buffer = f.read(4096)
          if buffer:
            parser.feed(buffer)
          else:
            time.sleep(2)

答案 1 :(得分:1)

我假设您无法访问的另一个进程是将xml维护为每隔一段时间更新一次的对象,然后转储结果。

如果您无法访问转储XML的程序源,则需要在两个XML版本之间进行花哨的区分,以获得通过网络发送的增量更新。

我认为你每次都必须解析新的XML才能有这种差异。

所以也许你可以让python进程观看文件,解析新版本,区分它(例如使用来自此article的解决方案),然后你可以使用像这样的工具通过网络发送差异xmlrpc。如果你想节省带宽,它可能会有所帮助。虽然我认为我会通过网络直接发送原始差异,然后在本地计算机中修补和解析文件。

但是,如果只有部分XML值发生变化(没有节点删除或插入),则可能会有更快的解决方案。或者,如果xml文件上的唯一操作是追加新树,那么您应该只能解析这些新树并将它们发送(首先是diff,然后在服务器中解析,发送到客户端,在客户端合并)。