Der Sinn ist Rückwärtskompatibilität. Das ``as`` an der Stelle ist relativ neu.
Eine `expression` kann auch ein Tupel ergeben. Die Forderung nach den Klammern kommen, zumindest informell, daher, dass man bei einem Tupel die Klammern braucht, falls es sonst zu Mehrdeutigkeiten kommen kann. Das ist ja hier der Fall wenn man ein ``,`` statt dem ``as`` verwendet.
XML-Problem: XML zu CSV
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Und ``as`` ist sowieso erst ab Python 2.6 möglich.Dill hat geschrieben:ok, klar. in python 3 ist es ja auch eindeutig ("," statt "as" ist nichtmehr erlaubt)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Hallo,
hier mein Vorschlag:
Geht das?
Gruß
hier mein Vorschlag:
Code: Alles auswählen
#!/usr/bin/env python
#-*- coding: iso-8859-1 -*-
import xml.dom.minidom
def getUglyString(fname):
fh = file(fname, "r")
a = fh.readlines()
fh.close()
b = ""
for i in a:
i = i.strip()
b += i
return b
dom = xml.dom.minidom.parseString(getUglyString("file.xml"))
lines = []
def getLine(merkmalnode):
line = merkmalnode.attributes["ID"].nodeValue
for node in merkmalnode.childNodes:
if node.nodeType == node.ELEMENT_NODE and node.nodeName == "Name":
for u in node.childNodes:
if u.nodeType == u.TEXT_NODE:
line += ";" + u.nodeValue.strip()
if node.nodeType == node.ELEMENT_NODE and node.nodeName == "AddData":
for u in node.childNodes:
if u.nodeType == node.ELEMENT_NODE and u.nodeName == "Wert" and u.attributes["MerkmalID"].nodeValue == "Kurzbezeichnung":
for u2 in u.childNodes:
if u2.nodeType == u.TEXT_NODE:
line += ";" + u2.nodeValue.strip()
if u.nodeType == node.ELEMENT_NODE and u.nodeName == "Wert" and u.attributes["MerkmalID"].nodeValue == "Beschreibung":
for u2 in u.childNodes:
if u2.nodeType == u.TEXT_NODE:
line += ";" + u2.nodeValue.strip()
return line
def walkOver(domina):
for node in domina.childNodes:
if node.nodeType == node.ELEMENT_NODE and node.nodeName == "Merkmal" and node.attributes.has_key("ID"):
lines.append(getLine(node))
walkOver(node)
walkOver(dom)
for i in lines:
print i
Gruß
Also rein aus ästhetischen Gründen und aus "pythonischer" Sicht geht das ja mal gar nicht. Pfui, ist das *hässlich*!
Edit: So sieht das IMHO etwas hübscher aus:
Edit: So sieht das IMHO etwas hübscher aus:
Code: Alles auswählen
import csv
import sys
from lxml import etree
def parse(filename):
root = etree.parse(filename)
xpath_template = 'AddData/Wert[@MerkmalID="%s"]/text()'
short_description = xpath_template % 'Kurzbezeichnung'
description = xpath_template % 'Beschreibung'
for merkmal in root.xpath('//Merkmal'):
yield [merkmal.attrib['ID'],
merkmal.find('Name').text,
merkmal.xpath(short_description)[0],
merkmal.xpath(description)[0]]
def main():
writer = csv.writer(sys.stdout, delimiter=';')
writer.writerows(parse('test.xml'))
Zuletzt geändert von BlackJack am Freitag 22. Mai 2009, 20:34, insgesamt 1-mal geändert.
blackjack, hast du eigentlich einen generator fetisch? 
hier eine version mit xpath, lxml.objectify und csv.DictWriter

hier eine version mit xpath, lxml.objectify und csv.DictWriter
Code: Alles auswählen
import csv
from lxml import objectify
def main(xml_file, csv_file):
tree = objectify.parse(xml_file)
writer = csv.DictWriter(csv_file, ("ID", "Name", "Kurzbezeichnung", "Beschreibung", "Noch_ein_Wert"))
for m in tree.xpath("//Merkmal"):
row = dict()
row.update({"ID": m.get("ID")})
row.update({"Name": m.Name})
for wert in m.AddData.xpath("Wert"):
row.update({wert.get("MerkmalID") : wert})
writer.writerow(row)
if __name__ == "__main__":
import StringIO
xml_file = StringIO.StringIO("""
<root>
<Merkmal ID="34747">
<Name>Volumen</Name>
<AddData>
<Wert MerkmalID="Kurzbezeichnung">Volumen</Wert>
<Wert MerkmalID="Beschreibung">= Inhalt einer Verpackung in Liter</Wert>
</AddData>
</Merkmal>
<Merkmal ID="4711">
<Name>Gewicht</Name>
<AddData>
<Wert MerkmalID="Kurzbezeichnung">Gewicht</Wert>
<Wert MerkmalID="Beschreibung">= Inhalt einer Verpackung in kg</Wert>
<Wert MerkmalID="Noch_ein_Wert">Hallo, Welt!</Wert>
</AddData>
</Merkmal>
</root>""")
csv_file = StringIO.StringIO()
main(xml_file, csv_file)
print csv_file.getvalue()
Code: Alles auswählen
34747,Volumen,Volumen,= Inhalt einer Verpackung in Liter,
4711,Gewicht,Gewicht,= Inhalt einer Verpackung in kg,"Hallo, Welt!"
http://www.kinderpornos.info
@Dill: Ich denke halt gerne in Datenströmen und Funktionen die welche erzeugen, verändern, oder akkumulieren. Da bieten sich Generatorfunktionen und die `itertools` einfach an, um daraus flexibel Lösungen zusammen zu stecken.
Bei mir ist zum Beispiel die Datenquelle sauber von der Senke getrennt. Die Daten könnten genauso gut aus einer Funktion kommen die eine Datenbank befragt, also auch in eine Funktion gesteckt werden, die die Daten in eine Datenbank schreibt. Oder als JSON schreibt, oder…
Und man könnte auch noch Filterfunktionen dazwischen schalten wenn man möchte.
Bei mir ist zum Beispiel die Datenquelle sauber von der Senke getrennt. Die Daten könnten genauso gut aus einer Funktion kommen die eine Datenbank befragt, also auch in eine Funktion gesteckt werden, die die Daten in eine Datenbank schreibt. Oder als JSON schreibt, oder…
Und man könnte auch noch Filterfunktionen dazwischen schalten wenn man möchte.

Der Name "walkOver()" war zwar meine Idee (in Anlehnung an die "TreeWalker"-Klasse).
Das mit (der) "domina" aber nicht; das kommt von hier:
http://de.wikibooks.org/wiki/Python_unter_Linux:_XML
unter "XML lesen".
Gruß
@blackjack: dein code ist wirklich sehr sexy. ich werde mal drauf achten in zukunft wo sich generatoren anbieten. trotzdem finde ich meinen code hier einfach lesbarer. (was hautpsächlich an DictWriter liegt, dieser verhindert aber auch eine sinnvolle die trennenung von writer und parser und macht daher ein yield(row) weniger sinnig)
wie wärs damit: (das geht sicher auch klarer??)
wie wärs damit: (das geht sicher auch klarer??)
Code: Alles auswählen
l = [list(chain(*[
(m.get("ID"), m.Name), [wert for wert in m.AddData.xpath("Wert")]
])) for m in tree.xpath("//Merkmal")]
http://www.kinderpornos.info
-
- User
- Beiträge: 18
- Registriert: Samstag 25. April 2009, 11:11
Hallo!
Vielen Dank für Eure Antworten! Ich hatte vergangenes Wochenende ZEit und bin kurz vor der Lösung.
Es gibt nur noch ein einziges Problem:
Wenn ich die Elemente der CSV-Datei die ich in Variablen gespeichert habe mit dem CSV-Writer über writerow schreiben will passiert folgendes: Es steht in jedem Feld nur ein einziger Buchstabe, d.h. ein Wort mit 10 bestehend aus 10 Buchstaben erstreckt sich momentan über 10 Spalten.
Habe schon hin und her probiert, bin jedoch noch auf keinen grünen Zweig gekommen.
Hat einer Rat an was das liegen kann?
Vielen Dank für Eure Antworten! Ich hatte vergangenes Wochenende ZEit und bin kurz vor der Lösung.
Es gibt nur noch ein einziges Problem:
Wenn ich die Elemente der CSV-Datei die ich in Variablen gespeichert habe mit dem CSV-Writer über writerow schreiben will passiert folgendes: Es steht in jedem Feld nur ein einziger Buchstabe, d.h. ein Wort mit 10 bestehend aus 10 Buchstaben erstreckt sich momentan über 10 Spalten.
Habe schon hin und her probiert, bin jedoch noch auf keinen grünen Zweig gekommen.
Hat einer Rat an was das liegen kann?
strings sind tupel von zeichen, daher das seltsame verhalten...
Code: Alles auswählen
In [23]: w.writerow("hallo")
In [24]: w.writerow( ("hallo",) )
In [25]: print o.getvalue()
h,a,l,l,o
hallo
http://www.kinderpornos.info
wenn schon, dann (immutable) sequenz von chars und escapeseqs (mit evtl. prefix)
du hast angefangen 
Code: Alles auswählen
stringliteral ::= [stringprefix](shortstring | longstring)
stringprefix ::= "r" | "u" | "ur" | "R" | "U" | "UR" | "Ur" | "uR"
shortstring ::= "'" shortstringitem* "'" | '"' shortstringitem* '"'
longstring ::= "'''" longstringitem* "'''"
| '"""' longstringitem* '"""'
shortstringitem ::= shortstringchar | escapeseq
longstringitem ::= longstringchar | escapeseq
shortstringchar ::= <any source character except "\" or newline or the quote>
longstringchar ::= <any source character except "\">
escapeseq ::= "\" <any ASCII character>

http://www.kinderpornos.info
@Dill: Nein, denn es gibt in Python keine `char`\s [1]_. Die Beschreibung von Zeichenkettenliteralen im Quelltext und die Eigenschaften von `str`-Objekten sind zwei verschiedene paar Schuhe.
Zeichenketten sind eine ("immutable") Sequenz von Zeichenketten der Länge 1, ist denke ich eine treffende Beschreibung, die das Phänomen erklärt.
.. [1] Jaja, ich weiss, es gibt `ctypes.c_char`.
Zeichenketten sind eine ("immutable") Sequenz von Zeichenketten der Länge 1, ist denke ich eine treffende Beschreibung, die das Phänomen erklärt.
.. [1] Jaja, ich weiss, es gibt `ctypes.c_char`.
Schön. Und wie jetzt, mit minidom oder lxml/etree?PhantomWorks hat geschrieben:Vielen Dank für Eure Antworten! Ich hatte vergangenes Wochenende ZEit und bin kurz vor der Lösung.
(Bei letzterem bin ich raus.)
Gruß
-
- User
- Beiträge: 18
- Registriert: Samstag 25. April 2009, 11:11
@problembär: Ich verwende jetzt lxml/etree. Ich habe zwar auch einen Versuch mit minidom gestartet, diesen jedoch bald wieder verworfen.
@all:
Ich habe mir nun die csv.DictWriter Funktion angesehen
Mein Code:
Ich bekomme folgenden Error:
Ich habe inzwischen eine Liste erzeugt aus allen Merkmalen, wobei jedes Merkmal (eindeutig durch die ID identifiziert) ein Dictionary darstellt. Ziel ist es nun die Dictionaries anhand der Fieldnames die ich mit den Schlüsseln des Dicts gemappt habe (also z.B. entspricht der Schlüssel Merkmal ID --> A1, Name --> A2 usw.), zeilenweise in die CSV zu schreiben, sodass letztendlich jedes einzelne Dict der Liste eine Zeile der CSV darstellt.
Viele Grüße
@all:
Ich habe mir nun die csv.DictWriter Funktion angesehen
als auch das was dahinter stecktcsv.DictWriter(csvfile, fieldnames[, restval=''[, extrasaction='raise'[, dialect='excel'[, *args, **kwds]]]])
Code: Alles auswählen
class DictWriter:
def __init__(self, f, fieldnames, restval="", extrasaction="raise",
dialect="excel", *args, **kwds):
self.fieldnames = fieldnames # list of keys for the dict
self.restval = restval # for writing short dicts
if extrasaction.lower() not in ("raise", "ignore"):
raise ValueError, \
("extrasaction (%s) must be 'raise' or 'ignore'" %
extrasaction)
self.extrasaction = extrasaction
self.writer = writer(f, dialect, *args, **kwds)
self.writer.writerow(fieldnames)
def _dict_to_list(self, rowdict):
if self.extrasaction == "raise":
for k in rowdict.keys():
if k not in self.fieldnames:
raise ValueError, "dict contains fields not in fieldnames"
return [rowdict.get(key, self.restval) for key in self.fieldnames]
def writerow(self, rowdict):
return self.writer.writerow(self._dict_to_list(rowdict))
def writerows(self, rowdicts):
rows = []
for rowdict in rowdicts:
rows.append(self._dict_to_list(rowdict))
return self.writer.writerows(rows)
Code: Alles auswählen
fieldnames=['A1','A2', 'A3', 'A4', 'A5']
csv.DictWriter((csv_file, 'w'), fieldnames, restval="", extrasaction="raise", dialect="excel", *args, **kwds)
Wozu brauche ich dieses *args, **kwds? ich habe schon hier im Forum danach gesucht und auch etwas gefunden doch meiner Meinung nach ist dieses für meinen Anwendungsfall nicht notwendig.File "C:\Python26\lib\csv.py", line 133, in __init__
self.writer = writer(f, dialect, *args, **kwds)
TypeError: argument 1 must have a "write" method
Ich habe inzwischen eine Liste erzeugt aus allen Merkmalen, wobei jedes Merkmal (eindeutig durch die ID identifiziert) ein Dictionary darstellt. Ziel ist es nun die Dictionaries anhand der Fieldnames die ich mit den Schlüsseln des Dicts gemappt habe (also z.B. entspricht der Schlüssel Merkmal ID --> A1, Name --> A2 usw.), zeilenweise in die CSV zu schreiben, sodass letztendlich jedes einzelne Dict der Liste eine Zeile der CSV darstellt.
Viele Grüße
@PhantomWorks: In der Doku zu csv.DictWriter kannst Du nachlesen, dass als erstes Argument eine Datei ewartet wird. So wie's aussieht übergibst Du aber ein Tupel mit, keine Ahnung was `csv_file` ist, und einer Zeichenkette. Und so ein Tupel hat im Gegensatz zu einer Datei keine `write()`-Methode.
Wieso übergibst Du die ganzen Argumente mit den gleichen Werten wie sie sowieso schon vorbelegt sind? Was ist an ``*args`` und ``**kwds`` gebunden und *warum*?
Vielleicht magst Du mal das Tutorial zum Thema “Defining functions“ durcharbeiten.
Wieso übergibst Du die ganzen Argumente mit den gleichen Werten wie sie sowieso schon vorbelegt sind? Was ist an ``*args`` und ``**kwds`` gebunden und *warum*?
Vielleicht magst Du mal das Tutorial zum Thema “Defining functions“ durcharbeiten.