Erstellung einer XML-Datei aus Logdatei

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
vikingrussel
User
Beiträge: 40
Registriert: Mittwoch 30. Mai 2007, 07:45

wie schon gesagt will ich eine xml-datei erstellen, hab mich bisher noch nicht viel mit programmieren beschäftigt.
zum thema: hab eine log-datei aus der bestimmte infos wie z.B. datum uhrzeit etc. ausgelesen werden sollen und diese sollen in einer xml-datei gespeichert werden. die datei öffnen und einzelne zeilen auslesen krieg ich hin

Code: Alles auswählen

File = open('Datei.log', 'r')
n = 1
for z in File.readlines():
	print 'Zeile',n,z
      n += 1
File.close() 
die benötigten infos würd ich mir mit slicing rausholen, bin mir da aber net so sicher weil ich dann listen oder sowas brauche.
hab absolut keinen plan wie das mit der xml gehen soll.

ich danke schon mal voraus für etwaiige hilfe
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

vikingrussel hat geschrieben:eine xml-datei erstellen
Hallo vikingrussel!

Willkommen im Python-Forum!

Mit ElementTree bist du auf der sicheren Seite. Hier ist ein Link zu einem Beitrag, der dich vielleicht weiter bringt: http://www.python-forum.de/post-58501.html#58501
Schau dir dort die Links durch.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
vikingrussel
User
Beiträge: 40
Registriert: Mittwoch 30. Mai 2007, 07:45

danke, ich werd mir das ma anschaun
vikingrussel
User
Beiträge: 40
Registriert: Mittwoch 30. Mai 2007, 07:45

wie sieht das mit der idee mit slicing aus. is da noch was besonderes zu beachten?

prob mit ElementTree:

Code: Alles auswählen

import elementtree.ElementTree as et
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    import elementtree.ElementTree as et
ImportError: No module named elementtree.ElementTree
kann bei mir nich geladen, arbeite mit version 2.5.1
BlackJack

`file.readlines()` liest alle Zeilen auf einmal in den Speicher. Das kann bei Logdateien unter Umständen sehr viel Speicher benötigen. Man kann über Dateiobjekte auch direkt iterieren, dann werden die Zeilen einzeln gelesen.

Code: Alles auswählen

lines = open('Datei.log')
for i, line in enumerate(lines):
    print 'Zeile', i + 1, line
lines.close()
Und den kompletten XML-Baum im Speicher aufzubauen ist eventuell dann auch keine gute Idee. Das Modul `elementtree.SimpleXMLWriter` bietet einen `XMLWriter` mit dem man eine XML-Datei "seriell" erzeugen kann.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Zunächst ein paar Tipps zu deinem Code:

- Namen für Instanzen sollten lowercase sein. `file` ist zudem der Name einer Funktion (bezeichnet dieselbe wie `open`). Nach meiner Erfahrung ist `f` (bei noch-nicht-so-Pythonistas auch `fh` für Filehandle) gängig.

- Anstatt über ``readlines()`` soll man direkt über das Dateiobjekt iterieren, das einen Iterator bereithält und damit speicherschonender arbeitet (weil nicht alles vorgehalten wird). Das sieht dann so aus: `for line in f:`

- Wenn du beim Durchlaufen mitzählen möchtest, kannst du `enumerate` verwenden, dass dir zu jedem Element den aktuellen Index liefert (beginnt bei 0).

- Zudem verwende ich hier die %-Formatierung, die du dir zumindest mal ansehen solltest.

- ``repr()`` sorgt dafür, dass Sonderzeichen wie Tabs oder Zeilenumbrüche als '\t' oder '\n' angezeigt, aber nicht "angewendet" werden. Gerade wenn die Zeile die Bildschirmbreite erreicht, übersieht man schon mal einen Zeilenumbruch.

Zusammengefügt:

Code: Alles auswählen

f = open('Datei.log', 'r')
for num, line in enumerate(f):
    print 'Zeile %d: %s' % (num + 1, repr(line))
f.close()
Wenn du außerdem noch Python 2.5 verwendest, kannst du vom neue `with`-Statement Gebrauch machen, wodurch das `f.close()` automatisch ausgeführt wird, auch im Fehlerfall bei ungefangenen Exceptions:

Code: Alles auswählen

from __future__ import with_statement

with open('Datei.log', 'r') as f:
    for num, line in enumerate(f):
        print 'Zeile %d: %s' % (num + 1, repr(line))
----

Zum Erzeugen des XML lege ich dir ebenfalls ElementTree sehr ans Herz (bei Python ab 2.5 bereits als `xml.etree` mit dabei). Auf der Website findest du Beispiele, wie es zu verwenden ist.

Hier ein Beispiel von mir grob zu deinem Vorhaben. Ich setze voraus, dass du eine exemplarische Liste von 3-Tupeln (date_time, priority, message) hast (du kannst stattdessen natürlich auch Dictionaries oder Objekte verwenden oder das ganze direkt beim Lesen aus der Datei weitergeben).

Erzeugen wir ein paar Testdaten für den Anfang:

Code: Alles auswählen

logs = []
for i in xrange(1, 6):
    date_time = '%02d.%02d.20%02d 12:00:%02d' % (i, i, i, i)
    logs.append((date_time, i, 'Event #%d has occured.' % i))
for l in logs:
    print l
Das sieht dann schon mal so aus:

Code: Alles auswählen

('01.01.2001 12:00:01', 1, 'Event #1 has occured.')
('02.02.2002 12:00:02', 2, 'Event #2 has occured.')
('03.03.2003 12:00:03', 3, 'Event #3 has occured.')
('04.04.2004 12:00:04', 4, 'Event #4 has occured.')
('05.05.2005 12:00:05', 5, 'Event #5 has occured.')
Dann wandeln wir das in XML um und geben es eingerückt aus:

Code: Alles auswählen

from xml.dom.minidom import parseString
from xml.etree.ElementTree import Element, SubElement, tostring


# XML-Baum erzeugen.
root = Element('events')
for date_time, prio, msg in logs:
    event_node = SubElement(root, 'event')
    SubElement(event_node, 'datetime').text = date_time
    SubElement(event_node, 'priority').text = str(prio)
    SubElement(event_node, 'message').text = msg

# XML formatiert ausgeben.
xml = tostring(root)
xml_indented = parseString(xml).toprettyxml(' '*4)
print xml_indented
Ausgabe:

Code: Alles auswählen

<?xml version="1.0" ?>
<events>
    <event>
        <datetime>
            01.01.2001 12:00:01
        </datetime>
        <priority>
            1
        </priority>
        <message>
            Event #1 has occured.
        </message>
    </event>
    <event>
        <datetime>
            02.02.2002 12:00:02
        </datetime>
        <priority>
            2
        </priority>
        <message>
            Event #2 has occured.
        </message>
    </event>
    <event>
        <datetime>
            03.03.2003 12:00:03
        </datetime>
        <priority>
            3
        </priority>
        <message>
            Event #3 has occured.
        </message>
    </event>
    <event>
        <datetime>
            04.04.2004 12:00:04
        </datetime>
        <priority>
            4
        </priority>
        <message>
            Event #4 has occured.
        </message>
    </event>
    <event>
        <datetime>
            05.05.2005 12:00:05
        </datetime>
        <priority>
            5
        </priority>
        <message>
            Event #5 has occured.
        </message>
    </event>
</events>
Du kannst natürlich auch Daten als Attribute anstatt von Textknoten einfügen, wenn du das für sinnvoller hältst.

Interessant ist ``SubElement(event_node, 'datetime').text = date_time``: Dabei wird eine `SubElement`-Instanz erzeugt, die über den ersten Parameter an den Baum gehängt wird. Diese Instanz bekommt keinen Namen, aber es wird direkt ihr Textknoten über das `text`-Attribut gesetzt. Attribute kannst du dem Konstruktor von `SubElement` mit übergeben, aber wenn du weitere Unterknoten anhängen willst, muss die Instanz einen Namen bekommen, vgl. `event_node`.
thelittlebug
User
Beiträge: 188
Registriert: Donnerstag 20. Juli 2006, 20:46
Wohnort: Wien
Kontaktdaten:

Darf ich fragen wofür man eine Logdatei im xml Format braucht?
Mir fällt spontan kein Anwendungsfall dafür ein.

lgherby
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Ist vielleicht für eine Umgebung, in der vorrangig Java eingesetzt wird ;)

"If XML is your hammer, everything looks like a nail."
vikingrussel
User
Beiträge: 40
Registriert: Mittwoch 30. Mai 2007, 07:45

erstmal ein dickes danke an YOGi, das ganze hilft mir im moment ein ganzes stück weiter :D

@BlackJack; das mit größe der log-dateien is ein interressanter punkt. könnte man das ganze auch umgehen, indem man beim einlesen differenziert was man eigentlich nur haben will aus der log-datei? das ganze müsste dann in meinem fall unabhängig vom aufbau der log-dateien sein

@thelittlebug; das is für's firmen intranet, das man bequem darüber nachprüfen kann, ob bestimmte dinge wie z.B. datensicherung gelaufen sind, ohne jedesmal zum server(n) rennen zu müssen. das ganze wird in einer datenbank gespeichert. is alles a bissel komisch und normalerweise bin ich auch nicht für solche dinge zuständig um das zu realisieren, bloß wenn niemand sonst da is, weil das bedeuten würde noch eine stelle zu vergeben
thelittlebug
User
Beiträge: 188
Registriert: Donnerstag 20. Juli 2006, 20:46
Wohnort: Wien
Kontaktdaten:

Aber wenn es in einer Datenbank gespeichert wird warum wird es zuerst in XML umgewandelt? :shock:

lgherby
vikingrussel
User
Beiträge: 40
Registriert: Mittwoch 30. Mai 2007, 07:45

frag mich nicht, es soll halt. wahrscheinlich weil das ganze portabel sein soll und mit xml hat man da auch keine unnötigen probleme, bloß mir stellt sich wiederrum auch die frage WARUM?
BlackJack

Klar kann man aus der Logdatei auch nur die interessanten Sachen herausfischen. Je nachdem wie die Datei aufgebaut ist, kann das von einem ganz einfachen Zeilenfilter bis zu etwas komplexeren Parsern gehen.

Aber was meinst Du mit unabhängig vom Aufbau der Logdatei? Man muss den Aufbau doch kennen wenn man Informationen daraus gewinnen will!?
vikingrussel
User
Beiträge: 40
Registriert: Mittwoch 30. Mai 2007, 07:45

danke, du hast meine frage beantwortet. trotzdem bin jetzt am arsch, es gibt etwa 100 verschiedene log-dateien, das bedeutet viele scripte.
wenn sich noch was ergibt dann werd ich das nochmal kundtun

und danke an alle für die hilfe
BlackJack

Je nachdem wie stark die Formate sich unterscheiden, kann man sie vielleicht zu ähnlichen Gruppen zusammenfassen, die dann von je einem Skript mit unterschiedlichen Konfigurationen verarbeitet werden können.

Wenn man zum Beispiel oft aus nur je einer Zeile Informationen herausholen und in einen "XML-Datensatz" umformen soll, lässt sich dafür sicher eine flexible Lösung mit regulären Ausdrücken mit benannten Gruppen und einem dazu passenden XML-Fragment für ein XML-Template-System wie `Kid` oder `genshi` basteln.
vikingrussel
User
Beiträge: 40
Registriert: Mittwoch 30. Mai 2007, 07:45

@gerold:
was meinst du hier mit dem root_tag und dem files_tag. da steig ich grad net ganz durch

Code: Alles auswählen

# Root-Tag
root_tag = et.Element("ROOT")

# Files-Tag
files_tag = et.SubElement(root_tag, "FILES")

# Mehrere Files
file_tag = et.SubElement(files_tag, "FILE")
file_tag.set("name", "dateiname1.txt")
file_tag = et.SubElement(files_tag, "FILE")
file_tag.set("name", "dateiname2.txt")
file_tag = et.SubElement(files_tag, "FILE")
file_tag.set("name", "dateiname3.txt")
file_tag.text = "Hallo Welt" 
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

vikingrussel hat geschrieben:@gerold:
was meinst du hier mit dem root_tag und dem files_tag.
Hallo vikingrussel!

Das hier geht NICHT als XML-durch:

Code: Alles auswählen

<settings>
  <apache>
  </apache>
  <postfix>
  </postfix>
</settings>
<log>
  <apache>
  </apache>
  <postfix>
  </postfix>
</log>
Es muss immer einen übergeordneten TAG geben. Diesen nennt man Root-Tag -- also Wurzel-TAG. Das hier: ``<apache></apache>`` ist ein so genanntes TAG. Im ElementTree wird dieser Tag durch ein Element oder SubElement dargestellt.

Hier ein gültiges XML-Beispiel:

Code: Alles auswählen

<?xml version="1.0" encoding="windows-1250"?>
<services>
  <apache>
    <settings>
      <setting id=automatic_start>True</setting>
      <setting id=user>www</setting>
    </settings>
    <log_lines>
      <line>2007-01-01 20:15:00 - Apache start<line>
      <line>2007-01-01 20:16:00 - Apache stop<line>
    </log_lines>
  </apache>
  <postfix>
    <settings>
      <setting id=automatic_start>False</setting>
      <setting id=user>postfix</setting>
    </settings>
    <log_lines>
      <line>2007-01-01 20:15:00 - Postfix start<line>
      <line>2007-01-01 20:16:00 - Postfix stop<line>
    </log_lines>
  </postfix>
</services>
"<services>" ist das Root-Element und unterhalb sind die anderen Elemente (TAGs) angeordnet. root_tag und files_tag sind nur zugewiesene Namen für die Elemente, denen man wieder andere Elemente unterordnen kann.

Edit:
Siehe auch: http://de.wikipedia.org/wiki/Tag_%28Informatik%29

mfg
Gerold
:-)
Zuletzt geändert von gerold am Dienstag 5. Juni 2007, 14:39, insgesamt 1-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Müsste man für gültiges XML nicht auch ein DTD oder xmlns haben?
TUFKAB – the user formerly known as blackbird
vikingrussel
User
Beiträge: 40
Registriert: Mittwoch 30. Mai 2007, 07:45

@gerold: das bringt natürlich licht ins tiefe dunkel, hätte man zwar auch selber draufkommen können aber egal, trotzdem danke
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

blackbird hat geschrieben:Müsste man für gültiges XML nicht auch ein DTD oder xmlns haben?
Hallo blackbird!

Nein, das braucht man nicht. XML gilt auch ohne Schema und Namespaces als gültig. Ein Schema ist ideal um einen Datenaustausch zu validieren, verkompliziert ihn aber auch. Ideal an so einem Schema ist, dass schon der Sender der Daten prüfen kann, ob die Daten prinzipiell gültig sind, noch bevor diese an den Empfänger geschickt werden.

EDIT:

Die Spezifikation spricht in oben gezeigten Beispiel von einem wohlgeformten XML. Du hast recht, gültiges XML bedarf eines DTD. Hier ein Auszug aus der Spezifikation von XML 1.0:
Ein textuelles Objekt ist ein wohlgeformtes XML-Dokument, wenn:
1. es als Gesamtheit betrachtet zu der mit document bezeichneten Produktion passt,
2. es alle Wohlgeformtheitsbeschränkungen dieser Spezifikation erfüllt und
3. jedes seiner parsed Entities, welches direkt oder indirekt referenziert wird, wohlgeformt ist.
Ein XML-Dokument ist gültig, wenn es eine dazugehörige Dokumenttyp-Deklaration besitzt und wenn sich das Dokument an die darin formulierten Beschränkungen hält.
Siehe: - http://edition-w3c.de/TR/2000/REC-xml-2 ... wellformed
- http://edition-w3c.de/TR/2000/REC-xml-2 ... /#dt-valid

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Zur Terminologie: `<apache></apache>` ist ein *Element* mit je einem öffnenden und schließenden *Tag*. Es gibt auch in sich geschlossene Elemente, die haben dann nur ein Tag: `<apache/>`.
Antworten