ubuntuusers.de

Python: XML Daten einlesen/umwandeln

Status: Gelöst | Ubuntu-Version: Kein Ubuntu
Antworten |

mephisto33

Anmeldungsdatum:
17. Juni 2007

Beiträge: 66

Hallo,

vorweg, ich habe keine Erfahrung mit Phython, XML-Parsern oder was auch immer. Ich habe jedoch ein relativ simples Problem, und ich denke mit dem richtigen Turtorial sollte das machbar sein, allerdings fehlt mir ein Ansatz.

Also ich habe Datendateien *.xml vorliegen:

        <Data>
            <X>9.652815</X>
            <Z>-1070.49</Z>
        </Data>
        <Data>
            <X>12.87042</X>
            <Z>-1054.117</Z>
        </Data>
        <Data>

usw... Leider sind weder Libreoffice Calc, Koffice, noch QtiPlot in der Lage dieses einzulesen. (zweispaltig) Einzig mit Microsoft Excel klappt es. Letztlich brauche ich die Daten jedoch in qtiplot, so dass mir der Umweg darüber zu auf Dauer zu arbeitsaufwendig ist.

Was brauche ich also? Optimum wäre es, wenn es möglich wäre, diese Daten direkt in qtiplot zu lesen. Man kann dort wohl python scripts direkt integrieren. Alternativ wre es auch schon ausreichend, obige Daten in ein anderen Format zu bringen (csv?):

9.652815    -1070.49
12.87042    -1054.117

Ob nun durch Leerstelle, Komma oder Semikolon getrennt, ist egal.

Ist das mit Python möglich? Ist Python überhaupt die richtige Sprache? Könnt ihr mir eine Seite oder Tutorial empfehlen? Ohne, dass ich jetzt ewig viele Stunden in Einlesen verbringen muss?

Danke und Grüße meph

noisefloor Team-Icon

Anmeldungsdatum:
6. Juni 2006

Beiträge: 29567

Hallo,

Ist das mit Python möglich?

Ja.

Ist Python überhaupt die richtige Sprache?

Ja, wobei das sicher auch mit (fast) allen Programmiersprachen geht...

Könnt ihr mir eine Seite oder Tutorial empfehlen?

Es gibt für Python diverse XML-Parser wie z.B. Element Tree oder LXML.

Ohne, dass ich jetzt ewig viele Stunden in Einlesen verbringen muss?

Na ja, dass kommt drauf an... wenn du keine Anhang von Python hast, dann könnte es gut sein, dass du die Dokus zu den XML-Parsern nicht verstehtst... Und direkt Python komplett "nur" für das Problem zu lernen - ist dein Sache. 😉

Gruß, noisefloor

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17621

Wohnort: Berlin

Kommt es vor dass Z vor X steht? Multiple Z oder X? Missing X oder Z?

Kommt es vor, dass ein X- oder Z-Tag über mehr als eine Zeile reicht? Oder ist alles sauber, in mechanischer Regelmäßigkeit gesetzt?

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17621

Wohnort: Berlin

1
egrep "<.>" demo4.xml | tr -d "<>/X" | sed 's/^[ \t]\+Z\?//' | tr "\n" "\t" | tr "Z"  "\n"

erzeugt aus dem 4fach wiederholten Beispielcode dies:

1
2
3
4
5
6
7
8
9.652815	-1070.49
	12.87042	-1054.117
	9.652815	-1070.49
	12.87042	-1054.117
	9.652815	-1070.49
	12.87042	-1054.117
	9.652815	-1070.49
	12.87042	-1054.117

Die erste Zeile wäre noch unterschiedlich - auf Wunsch erkläre ich wie es geht. Es hängt aber von der Regelmäßigkeit der Daten ab.

Braindead

Avatar von Braindead

Anmeldungsdatum:
8. August 2010

Beiträge: 158

Wohnort: Saarbrücken

ich nehm mal die Voraussetzung ist erfüllt, dass alle Felder richtig bezeichnet und befüllt sind, dann reicht ein einfacher 3 zeiler

1
2
3
4
#!/bin/bash
grep -i 'x' testparser | cut -d '>' -f2 | cut -d '<' -f1 > x_file
grep -i 'z' testparser | cut -d '>' -f2 | cut -d '<' -f1 > z_file
paste x_file z_file > ergebnis

Man muss nicht immer mit Kanonen auf Spatzen schiessen, auch wenn es bestimmt elegantere Lösungen als die hier gibt

SG

mephisto33

(Themenstarter)

Anmeldungsdatum:
17. Juni 2007

Beiträge: 66

Hallo. Vielen Dank für eure Antworten!

Also um exakt zu sein: Die Daten sehen so aus:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<ProfilometerData>
    <Header>
        <TestDate>07-18-2011</TestDate>
        <TestTime>14:43:20</TestTime>
        <XUnits>MICRON</XUnits>
        <ZUnits>NANOMETER</ZUnits>
        <NumData>9323</NumData>
        <DataGain>1</DataGain>
        <DataOffset>0</DataOffset>
    </Header>
    <DataBlock>
        <Data>
            <X>0</X>
            <Z>-926.5429</Z>
        </Data>
        <Data>
            <X>3.217605</X>
            <Z>-910.2635</Z>
        </Data>



    </DataBlock>
</ProfilometerData>

Der Header interessiert mich nicht. Es folgt immer Z auf X und auch sonst sind alle Datenreihen immer gleich aufgebaut.

Braindead

Avatar von Braindead

Anmeldungsdatum:
8. August 2010

Beiträge: 158

Wohnort: Saarbrücken

also wenn nur der data block interessant ist, dann einfach so abändern:

1
2
3
4
#!/bin/bash
grep -i '<x>' testparser | cut -d '>' -f2 | cut -d '<' -f1 > x_file
grep -i '<z>' testparser | cut -d '>' -f2 | cut -d '<' -f1 > z_file
paste x_file z_file > ergebnis

mephisto33

(Themenstarter)

Anmeldungsdatum:
17. Juni 2007

Beiträge: 66

Die blanken Zahlen reichen, alles andere würde ich beim Import nach Qtiplot oder Origin ohnehin ignorieren.

Braindead

Avatar von Braindead

Anmeldungsdatum:
8. August 2010

Beiträge: 158

Wohnort: Saarbrücken

sry zu spät gesehen, dass du bereits auf meine Frage geantwortet hast, lösung siehe oben

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17621

Wohnort: Berlin

Mein Befehl filtert nur Zeilen aus, die ein Tag mit einem Zeichen "<.>" haben, so dass der Header nichts an der Funktionsweise ändert.

Lysander

Avatar von Lysander

Anmeldungsdatum:
30. Juli 2008

Beiträge: 2669

Wohnort: Hamburg

Ich würde ja auch das "richtige" Werkzeug zum Arbeiten mit XML zurückgreifen: xmlstarlet 😉

1
xmlstarlet sel -T -t -m "//Data" -v "concat(X, '  ', Z)" -n  values.xml 

Ergibt:

0  -926.5429
3.217605  -910.2635

track

Avatar von track

Anmeldungsdatum:
26. Juni 2008

Beiträge: 7174

Wohnort: Wolfen (S-A)

Hi meph,

echte xml-Daten mit sed und Konsorten herauszuziehen geht zwar, ist aber unschön.

Für sowas nimmt man einen XML-Parser, also sowas wie XSLT, xpath oder xmlstarlet, der liefert die Daten absolut fachgerecht und wasserdicht frei Haus.
Das einfachste ist xmlstarlet:

xmlstarlet sel -t -m "//Data"  -v "X" -o "&#09;" -v "Z" -n  barodaten.xml
###               ^^^^(1)^^^^  ^^^^^^^^^^^^(2)^^^^^^^^^^^^

in Klartext:
- (1) wähle der Reihe nach alle Knoten "Data" aus
- (2) gib davon den Wert im Unterknoten X , einen TAB, den Wert im Unterknoten Z und einen Zeilenumbruch aus
Hier habe ich TAB als Trenner genommen, aber es ist natürlich auch leicht jedes andere Format möglich.

Zum Verständnis empfehle ich einen Blick in die Dokumentation: http://xmlstar.sourceforge.net/doc/UG/xmlstarlet-ug.html

Mit Python kann ich Dir nicht weiterhelfen, da bin ich nicht fit genug.

LG,

track

Edit:
Oh, Lysander hat mich inzwischen überholt ... ☺

noisefloor Team-Icon

Anmeldungsdatum:
6. Juni 2006

Beiträge: 29567

Hallo,

track schrieb:

echte xml-Daten mit sed und Konsorten herauszuziehen geht zwar, ist aber unschön.

Ich hatte auch mit dem Gedanken gespielt, sed & Co. in den Ring zu werfen. Hab's dann aber nicht, genau deshalb. ☺

Wobei: Bei so einfach gestrickten XML-Dateien ist es schon die kürzeste Lösung...

Gruß, noisefloor

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17621

Wohnort: Berlin

Meine erste Lösung hatte aber etwas viele Pipes und tr-Aufrufe; hier etwas kürzer: grep, tr und sed:

1
egrep "<.>" demo4.xml | tr -d '\n' | sed -r 's|[<>/]||g;s/[ \t]+[XZ]?//g;s/X/\t/g;s/Z/\n/g'

mephisto33

(Themenstarter)

Anmeldungsdatum:
17. Juni 2007

Beiträge: 66

Vielen vielen Dank für alle Antworten.

Meine Datei sieht jetzt so aus:

for i in *.xml; do xml sel -T -t -m "//Data" -v "concat(X, '	', Z)" -n  $i > $i.txt ; done

Damit werden automatisch alle xml Dateien in das gewünschte Format umgewandelt. Das funktioniert soweit wirklich super, viel schneller als über Umwege wie Excel und co.

Antworten |