2017-06-06 3 views
0

Ich muss eine XML-Datei überwachen, die von einem Tool geschrieben wird, das den ganzen Tag läuft. Die XML-Datei wird jedoch erst am Ende des Tages korrekt ausgefüllt und geschlossen.XML-Datei lesen, während sie geschrieben wird (in Python)

gleiche Einschränkungen wie XML-Stream-Verarbeitung:

  1. eine unvollständige XML-Datei on-the-fly Parsen und Aktionen auslösen
  2. Spur der letzten Position hält in der Datei wieder von Anfang an der Verarbeitung, es zu vermeiden

Auf Antwort von Need to read XML files as a stream using BeautifulSoup in Python, slezica schlägt xml.sax, xml.etree.ElementTree und cElementTree. Aber kein Erfolg mit meinen Versuchen, xml.etree.ElementTree und cElementTree zu verwenden. Es gibt auch xml.dom, xml.parsers.expat und lxml, aber ich sehe keine Unterstützung für "On-the-Fly-Parsing".

Ich brauche mehr offensichtliche Beispiele ...

ich zur Zeit mit Python bin 2.7 auf Linux, aber ich werde auch Tipps, neue Python 3.x Funktionen bieten zu Python 3.x => bitte migrieren. Ich benutze auch watchdog, um XML-Dateiänderungen zu erkennen => Verwenden Sie optional den Mechanismus watchdog. Optional unterstützt auch Windows.

Bitte geben Sie einfach zu verstehen/zu pflegen Lösungen. Wenn es zu komplex ist, kann ich einfach tell()/seek() verwenden, um innerhalb der Datei zu verschieben, dumme Textsuche im XML-Rohdatenformat zu verwenden und schließlich die Werte mithilfe von Basic Regex zu extrahieren.


XML Beispiel:

<dfxml xmloutputversion='1.0'> 
    <creator version='1.0'> 
    <program>TCPFLOW</program> 
    <version>1.4.6</version> 
    </creator> 
    <configuration> 
    <fileobject> 
     <filename>file1</filename> 
     <filesize>288</filesize> 
     <tcpflow packets='12' srcport='1111' dstport='2222' family='2' /> 
    </fileobject> 
    <fileobject> 
     <filename>file2</filename> 
     <filesize>352</filesize> 
     <tcpflow packets='12' srcport='3333' dstport='4444' family='2' /> 
    </fileobject> 
    <fileobject> 
     <filename>file3</filename> 
     <filesize>456</filesize> 
     ... 
     ... 

Erster Test mit SAX fehlgeschlagen:

import xml.sax 

class StreamHandler(xml.sax.handler.ContentHandler): 
    def startElement(self, name, attrs): 
     print 'start: name=', name 
    def endElement(self, name): 
     print 'end: name=', name 
     if name == 'root': 
      raise StopIteration 

if __name__ == '__main__': 
    parser = xml.sax.make_parser() 
    parser.setContentHandler(StreamHandler()) 
    with open('f.xml') as f: 
     parser.parse(f) 

Shell:

$ while read line; do echo $line; sleep 1; done <i.xml >f.xml & 
... 
$ ./test-using-sax.py 
start: name= dfxml 
start: name= creator 
start: name= program 
end: name= program 
start: name= version 
end: name= version 
Traceback (most recent call last): 
    File "./test-using-sax.py", line 17, in <module> 
    parser.parse(f) 
    File "/usr/lib64/python2.7/xml/sax/expatreader.py", line 107, in parse 
    xmlreader.IncrementalParser.parse(self, source) 
    File "/usr/lib64/python2.7/xml/sax/xmlreader.py", line 125, in parse 
    self.close() 
    File "/usr/lib64/python2.7/xml/sax/expatreader.py", line 220, in close 
    self.feed("", isFinal = 1) 
    File "/usr/lib64/python2.7/xml/sax/expatreader.py", line 214, in feed 
    self._err_handler.fatalError(exc) 
    File "/usr/lib64/python2.7/xml/sax/handler.py", line 38, in fatalError 
    raise exception 
xml.sax._exceptions.SAXParseException: report.xml:15:0: no element found 

Antwort

0

Drei Stunden s nach dem Posten meiner Frage, keine Antwort erhalten. Aber ich habe endlich das einfache Beispiel implementiert, nach dem ich gesucht habe.

Meine Inspiration ist von saaj 's answer und basiert auf xml.sax und watchdog.

from __future__ import print_function, division 
import time 
import watchdog.events 
import watchdog.observers 
import xml.sax 

class XmlStreamHandler(xml.sax.handler.ContentHandler): 
    def startElement(self, tag, attributes): 
    print(tag, 'attributes=', attributes.items()) 
    self.tag = tag 
    def characters(self, content): 
    print(self.tag, 'content=', content) 

class XmlFileEventHandler(watchdog.events.PatternMatchingEventHandler): 
    def __init__(self): 
    watchdog.events.PatternMatchingEventHandler.__init__(self, patterns=['*.xml']) 
    self.file = None 
    self.parser = xml.sax.make_parser() 
    self.parser.setContentHandler(XmlStreamHandler()) 
    def on_modified(self, event): 
    if not self.file: 
     self.file = open(event.src_path) 
    self.parser.feed(self.file.read()) 

if __name__ == '__main__': 
    observer = watchdog.observers.Observer() 
    event_handler = XmlFileEventHandler() 
    observer.schedule(event_handler, path='.') 
    try: 
    observer.start() 
    while True: 
     time.sleep(10) 
    finally: 
    observer.stop() 
    observer.join() 

Während das Skript, vergessen Sie nicht zu touch eine XML-Datei ausgeführt wird, oder das Schreiben on-the-fly simulieren mit dem folgenden Befehl ein: gestern

while read line; do echo $line; sleep 1; done <in.xml >out.xml & 
1

Da ich die Peter Gibson gefunden ' s answer über die undokumentierten xml.etree.ElementTree.XMLTreeBuilder._parser.EndElementHandler.

Dieses Beispiel ähnelt dem anderen, verwendet jedoch xml.etree.ElementTree (und watchdog).

Es funktioniert nicht, wenn ElementTree durch cElementTree ersetzt wird: -/

import time 
import watchdog.events 
import watchdog.observers 
import xml.etree.ElementTree 

class XmlFileEventHandler(watchdog.events.PatternMatchingEventHandler): 
    def __init__(self): 
     watchdog.events.PatternMatchingEventHandler.__init__(self, patterns=['*.xml']) 
     self.xml_file = None 
     self.parser = xml.etree.ElementTree.XMLTreeBuilder() 
     def end_tag_event(tag): 
      node = self.parser._end(tag) 
      print 'tag=', tag, 'node=', node 
     self.parser._parser.EndElementHandler = end_tag_event 

    def on_modified(self, event): 
     if not self.xml_file: 
      self.xml_file = open(event.src_path) 
     buffer = self.xml_file.read() 
     if buffer: 
      self.parser.feed(buffer) 

if __name__ == '__main__': 
    observer = watchdog.observers.Observer() 
    event_handler = XmlFileEventHandler() 
    observer.schedule(event_handler, path='.') 
    try: 
     observer.start() 
     while True: 
      time.sleep(10) 
    finally: 
     observer.stop() 
     observer.join() 

das Skript Während des Laufens ist, vergessen Sie nicht zu touch einer XML-Datei oder das Schreiben on-the-fly simulieren dies mit eine Zeile Skript:

while read line; do echo $line; sleep 1; done <in.xml >out.xml & 

Informationen, die xml.etree.ElementTree.iterparse scheint nicht eine Datei geschrieben unterstützen wird. Mein Testcode:

from __future__ import print_function, division 
import xml.etree.ElementTree 

if __name__ == '__main__': 
    context = xml.etree.ElementTree.iterparse('f.xml', events=('end',)) 
    for action, elem in context: 
     print(action, elem.tag) 

Meine Ausgabe:

end program 
end version 
end creator 
end filename 
end filesize 
end tcpflow 
end fileobject 
end filename 
end filesize 
end tcpflow 
end fileobject 
end filename 
end filesize 
Traceback (most recent call last): 
    File "./iter.py", line 9, in <module> 
    for action, elem in context: 
    File "/usr/lib64/python2.7/xml/etree/ElementTree.py", line 1281, in next 
    self._root = self._parser.close() 
    File "/usr/lib64/python2.7/xml/etree/ElementTree.py", line 1654, in close 
    self._raiseerror(v) 
    File "/usr/lib64/python2.7/xml/etree/ElementTree.py", line 1506, in _raiseerror 
    raise err 
xml.etree.ElementTree.ParseError: no element found: line 20, column 0 
Verwandte Themen