Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python中附加数据到外部XML文件的增量解析_Python_Xml_Python 2.6 - Fatal编程技术网

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

Python中附加数据到外部XML文件的增量解析,python,xml,python-2.6,Python,Xml,Python 2.6,我在局域网的外部计算机上有一个日志文件。日志是一个XML文件。文件无法从http访问,并且每秒都在更新。 目前我正在将日志文件复制到我的计算机并运行解析器,但我想直接从外部主机解析文件 我如何用Python实现它?是否可以只解析一次整个文件,然后在将来的版本中只解析添加到末尾的新内容?我假设您无法访问的另一个过程是将xml作为一个对象进行维护,每隔一段时间更新一次,然后转储结果 如果您无法访问转储XML的程序的源代码,则需要在两个XML版本之间进行巧妙的区分,以获得通过网络发送的增量更新 我认为

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


我如何用Python实现它?是否可以只解析一次整个文件,然后在将来的版本中只解析添加到末尾的新内容?

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

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

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

因此,您可能需要一个python进程来监视文件,解析新版本,对其进行扩散(例如,使用来自此版本的解决方案),然后您可以使用类似的工具通过网络发送这种差异。如果你想节省带宽,它可能会有所帮助。尽管我认为我会通过网络直接发送原始差异,在本地机器中修补和解析文件

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

您可以使用and的默认解析器,
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

我拿不到外部计算机。我只能通过ssh登录并下载文件,不能在上面运行任何应用程序。通过添加行来更新XML。我甚至不知道文件何时被更改,我必须每0,6秒检查一次。网络带宽不是问题-它在我的LAN网络中。让一个进程计算本地和远程文件的差异,并每隔10秒将该差异作为临时文件删除。然后,您的python进程可以是那个临时文件,在它到达时对其进行解析,并将节点添加到当前XML中。@Lilley,使用文本更改位置的知识通知一个确凿的解析器是可行的,但它也非常非常重要--需要为该作业编写一个解析器,我所知道的惟一解析器是用Java或LISP编写的,不是Python。当你说“通过ssh登录”时,你的意思是你可以在外部计算机上打开shell还是其他什么?若你们可以登录到一个shell,你们就可以运行一个程序。是的,但我只有读取目录的权限,并没有执行脚本的权限。“更改”太模糊了。如果唯一可能的更改是追加操作,而不是已经写入的文件部分中的内容更改,这使得以有效的方式实现这一点变得可行——但仅仅说它“更改”和您想要“差异”太笼统了,因为这允许非追加操作,能够处理就地编辑的增量解析器是一项极其复杂的任务。(在该领域进行研究的大多数人都在构建IDE;指出他们的工作是可行的,但我认为采用它将是一项巨大的努力)。您是否可以访问主机来运行自己的程序?您使用什么协议将日志文件复制到您的计算机上?主机和您的计算机运行的是什么操作系统?值得注意的是,这只处理附加,而不是就地编辑。OP的问题指的是日志记录——适用于附录——但也询问“差异”,这是一个通常在就地编辑环境中使用的短语,因此,在我们能够确定这个答案是否正确之前,可能需要进行一些澄清。@CharlesDuffy看一下第一个答案的第一条评论。OP说XML是通过添加行来更新的。
#!/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)