ElementTree XML Problem

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
madthomas
User
Beiträge: 35
Registriert: Dienstag 7. August 2007, 10:32
Wohnort: WND
Kontaktdaten:

Hallo
ich hab die Aufgabe bekommen mittels einens Parser bestimmt Textteile auszulesen . Der Tag sieht etwas so aus

<Message code="" severity="" time="">
<UserType name="irgendwas" profile="Profile1"
script="blablablubb"></UserType>
<Agent>Superman</Agent>
<Text>Fehler drin
</Text>
<Time>26.06.2008 13:19:41</Time>
</Message>
den Agenten den Fehler und die Zeit mit Datum

hab jetzt mal ein skript von hier modifiziert aber irgendwie findet der nicht.

Code: Alles auswählen

import re
from BeautifulSoup import BeautifulStoneSoup
xml = open("detailedReport.xml")

soup = BeautifulStoneSoup(xml) 
print "Beginn"
for text in soup("Message"):
	attrs = dict(text.attrs)
	print "tag     :", text
	print "string  :", text.string
	print "content :", "".join([str(item) for item in text.contents])
	print "contents:", text.contents
	print "Text    :", attrs.get("Text")
	print "Time    :", attrs.get("Time")
	print "Agent   :", attrs.get("Agent")
	print 
	
print "Ende"
Zuletzt geändert von madthomas am Freitag 11. Juli 2008, 10:00, insgesamt 1-mal geändert.
BlackJack

`BeautifulStoneSoup` ist nicht gerade das ideale Werkzeug um XML zu parsen. Das Modul ist für kaputtes (X)HTML gedacht. Bei "echtem" XML sollte man aber erwarten können, das es auch wohlgeformt ist und die entsprechenden XML-Werkzeuge verwenden.

Problem ist, das HTML bei Tags keinen Unterschied zwischen Gross- und Kleinschschreibung macht und `BeautifulSoup` deshalb alle Tags in klein Geschriebene umwandelt. Deshalb wird bei ``soup('Message')`` nichts gefunden.

Ein ``print soup`` hätte das sehr schnell aufgedeckt.
madthomas
User
Beiträge: 35
Registriert: Dienstag 7. August 2007, 10:32
Wohnort: WND
Kontaktdaten:

was wäre den ein besseres Werkzeug?
so er kann mir was auslesen nur leider klappt das ganze nicht so richtig.
Wie lese ich was ziwschen den Tags aus?
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Ich würde ElementTree verwendent.

Ab Python 2.5 in der Standardbibliothek. (gibts aber auch für die älteren Versionen)

Code: Alles auswählen

In [17]: from xml.etree import ElementTree as ET

In [18]: tree = ET.fromstring("""<Message code="" severity="" time="">
   ....: <UserType name="irgendwas" profile="Profile1"
   ....: script="blablablubb"></UserType>
   ....: <Agent>Superman</Agent>
   ....: <Text>Fehler drin
   ....: </Text>
   ....: <Time>26.06.2008 13:19:41</Time>
   ....: </Message>""")

In [19]: agent = tree.find("Agent")

In [20]: agent.text
Out[20]: 'Superman'
madthomas
User
Beiträge: 35
Registriert: Dienstag 7. August 2007, 10:32
Wohnort: WND
Kontaktdaten:

ok hab auch gelesen das ElementTree eine besser Lösung ist.
ich hab jetzt noch folgendes Problem
Mein Code sieht mittleweile so aus und ist in einer Datei

Code: Alles auswählen

<BaselineReport>
<Message code="" severity="" time="">
<UserType name="irgendwas" profile="Profile1"
script="blablablubb"></UserType>
<Agent>Superman</Agent>
<Text>Fehler drin
</Text>
<Time>26.06.2008 13:19:41</Time>
</Message>
<Message code="" severity="" time="">
<UserType name="irgendwas" profile="Profile1"
script="blablablubb"></UserType>
<Agent>Superman</Agent>
<Text>Fehler drin
</Text>
<Time>26.06.2008 13:19:41</Time>
</Message>
</BaselineReport>
Habs jetzt mal so versucht aber es klappt nicht

Code: Alles auswählen

from xml.etree import ElementTree as et

files = file("detailedReport.xml", "r")
etree = et.parse(files)
files.close()
root_tag = etree.getroot()
files_tag = root_tag.find("BaselineReport")
if files_tag:
    for file_tag in files_tag.findall("Message"):
        print file_tag.get("Agent")
        print "  " + (file_tag.text or "") 
edit:
so hab jetzt mal weiter probiert und raus bekommen das der BaselineReport nicht findet und deswegen erst garnicht den if teil ausführt
Zuletzt geändert von madthomas am Donnerstag 10. Juli 2008, 09:39, insgesamt 1-mal geändert.
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

Du must in deiner Hirarchie erstmal noch eine Ebene Tiefer gehen und die Message Blöcke auswählen.

Code: Alles auswählen

from xml.etree import ElementTree as et

files = file("detailedReport.xml", "r")
etree = et.parse(files)
files.close()
root_tag = etree.getroot()
for message in root_tag.findall("Message"):
    print message.find("Agent").text
madthomas
User
Beiträge: 35
Registriert: Dienstag 7. August 2007, 10:32
Wohnort: WND
Kontaktdaten:

Zap hat geschrieben:Du must in deiner Hirarchie erstmal noch eine Ebene Tiefer gehen und die Message Blöcke auswählen.

Code: Alles auswählen

from xml.etree import ElementTree as et

files = file("detailedReport.xml", "r")
etree = et.parse(files)
files.close()
root_tag = etree.getroot()
for message in root_tag.findall("Message"):
    print message.find("Agent").text
das funktiert irgendwie nicht der findet Message nicht
Zap
User
Beiträge: 533
Registriert: Freitag 13. Oktober 2006, 10:56

madthomas hat geschrieben: Mein Code sieht mittleweile so aus und ist in einer Datei

Code: Alles auswählen

<BaselineReport>
<Message code="" severity="" time="">
<UserType name="irgendwas" profile="Profile1"
script="blablablubb"></UserType>
<Agent>Superman</Agent>
<Text>Fehler drin
</Text>
<Time>26.06.2008 13:19:41</Time>
</Message>
<Message code="" severity="" time="">
<UserType name="irgendwas" profile="Profile1"
script="blablablubb"></UserType>
<Agent>Superman</Agent>
<Text>Fehler drin
</Text>
<Time>26.06.2008 13:19:41</Time>
</Message>
</BaselineReport>
Mit der Beispieldatei sieht das Ergebnis bei mir so aus:

Code: Alles auswählen

Der Inhalt deiner XML Datei sieht (laut deinem Beispiel) so aus:



In [35]: cpaste
Pasting code; enter '--' alone on the line to stop.
:from xml.etree import ElementTree as et
:
:files = file("detailedReport.xml", "r")
:etree = et.parse(files)
:files.close()
:root_tag = etree.getroot()
:for message in root_tag.findall("Message"):
:    print message.find("Agent").text
:--
Superman
Superman
madthomas
User
Beiträge: 35
Registriert: Dienstag 7. August 2007, 10:32
Wohnort: WND
Kontaktdaten:

Sorry aber hab noch einen fehler bei mir übersehen deswegen klappt das auch nicht ich muss noch eine Ebene tiefer

Code: Alles auswählen

<BaselinReport>
    <MessageList>(deswegen hat das auch nicht geklappt)
        <Message>
            <Agent>
            </Agent>
        </Message>
    </MessageList>
</BaselineReport>

Code: Alles auswählen

for messagelist in root_tag.findall("MessageList"):
    for message in messagelist.findall("Message"):
        print message.find("Agent").text 
habs jetzt so und es klappt bis zu diesem Punkt
madthomas
User
Beiträge: 35
Registriert: Dienstag 7. August 2007, 10:32
Wohnort: WND
Kontaktdaten:

So soweit läuft mein Script. Leider befindet sich bei einem Text ein Umlaut und beim schreiben in die Datei bringt er einen Fehler

Code: Alles auswählen

ile "XMLparser.py", line 14, in <module>
    print ("%s;%s" % (time,text))
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe4' in position 65: ordinal not in range(128)

Code: Alles auswählen

# -*- coding: iso-8859-1 -*-
import sys
from xml.etree import ElementTree as et
files = file("detailedReport.xml", "r")
etree = et.parse(files)
files.close()
out_file = open("test.csv", "w")
root_tag = etree.getroot()
for messagelist in root_tag.findall("MessageList"):
    for message in messagelist.findall("Message"):
        time = message.find("Time").text 
        text =  message.find("Text").text 
	text = text.strip()
        print ("%s;%s" % (time,text))
	out_file.write("%s;%s" % (time, text))#habs hier auch mal mit encode('utf-8') versucht aber er findet im ersten satz kein umlaut und bricht dann ab
	out_file.write("\n")
out_file.close()
Wie kann ich das am besten lösen
BlackJack

Wenn `unicode`-Objekte das Programm verlassen, sei es durch ``print`` oder schreiben in eine Datei, müssen sie in Bytes umgewandelt werden, also "gewöhnliche" `str`-Objekte. Bei ``print`` kann man Glück haben, dass Python heraus finden konnte, was zum Beispiel die Standardausgabe für eine Kodierung erwartet, aber spätestens bei Dateien kann man das nicht mehr automatisch ermitteln und Du musst explizit die `encode()`-Methode mit einer passenden Kodierung verwenden. Oder die Datei mit `codecs.open()` öffnen.
madthomas
User
Beiträge: 35
Registriert: Dienstag 7. August 2007, 10:32
Wohnort: WND
Kontaktdaten:

ich hab es mal so versucht

Code: Alles auswählen

import codecs
from xml.etree import ElementTree as et
files = file("detailedReport.xml", "r")
etree = et.parse(files)
files.close()
out_file = codecs.open("test.csv", "w", "utf-16") #codecs.open 
root_tag = etree.getroot()
for messagelist in root_tag.findall("MessageList"):
    for message in messagelist.findall("Message"):
        time = message.find("Time").text 
        text =  message.find("Text").text 
	text = text.strip()
        print ("%s;%s" % (time,text))
	out_file.write("%s;%s" % (time, text))
	out_file.write("\n")
out_file.close()
weil mir das am einfachsten erschien aber es klappt nicht
BlackJack

Definiere "klappt nicht". Ich sehe da auf den ersten Blick schonmal einen bösen Einrückungsfehler. Und natürlich kann Dir das ``print`` noch Probleme machen, wenn der Interpreter nicht erraten kann, was das Programm am anderen Ende von `sys.stdout` für eine Kodierung erwartet.
madthomas
User
Beiträge: 35
Registriert: Dienstag 7. August 2007, 10:32
Wohnort: WND
Kontaktdaten:

Sorry
meinte damit das der Fehler immer noch der Selbe ist.

Code: Alles auswählen

26.06.2008 13:43:59;Error(blablablubb)
26.06.2008 13:47:58;Error(blablablubb)
Traceback (most recent call last):
  File "XMLparser.py", line 13, in <module>
    print ("%s;%s" % (time,text))
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe4' in position 65: ordinal not in range(128)
>Exit code: 1
und in der Zeile die da kommt ist ein Umlaut
madthomas
User
Beiträge: 35
Registriert: Dienstag 7. August 2007, 10:32
Wohnort: WND
Kontaktdaten:

Ok es lag wirklich am print.
Jetzt hab ich nur noch ein Problem. Immer wenn ich in die Dateischreiben will macht der keine neue Zeile habs mit verschiedenen Lösungen schon versucht.

Code: Alles auswählen

import codecs
from xml.etree import ElementTree as et
files = file("detailedReport.xml", "r")
etree = et.parse(files)
files.close()
out_file = codecs.open("test.csv", "w", "utf-8")
root_tag = etree.getroot()
for messagelist in root_tag.findall("MessageList"):
    for message in messagelist.findall("Message"):
        time = message.find("Time").text 
        text =  message.find("Text").text 
        agent = message.find("Agent").text 
        text = text.strip()
        time = time.replace(" ",";")
        out_file.write("%s;%s;1" % (time, text)+"\n")
        out_file.write("%s;%s;1" % (time, agent)+'\n')
        out_file.write('\n')
        out_file.write("\n")
        out_file.write("%s;%s;1" % (agent, text))
out_file.close()
Wie bekomme ich das hin das ich am Ende von out_file.write eine neue Zeile schreiben kann
Keins der \n tut seinen Dienst
BlackJack

Die landen '\n' alle in der Datei. Kann es sein, dass Du Windows-Zeilenenden haben möchtest, also '\r\n'?

Ich würde die ja gleich in die Format-Zeichenkette schreiben und nicht extra mit ``+`` anhängen oder mit einzelnen `write()`-Aufrufen schreiben.
Antworten