Seite 1 von 1
sax parser - tag gruppen, doppelte tag namen
Verfasst: Donnerstag 2. Dezember 2010, 10:45
von PauleJS
hallo,
wie kann ich tags einer tag gruppe einlesen bei der bereits ein tag name ausserhalb der gruppe existiert?
aufbau tag gruppe
<shipping>
<price> ----> existiert bereits
<destination>
<country>
</shipping>
Re: sax parser - tag gruppen, doppelte tag namen
Verfasst: Donnerstag 2. Dezember 2010, 10:58
von BlackJack
@PauleJS: Kannst Du die Frage noch einmal anders formulieren? Was sind Tag-Gruppen? Meinst Du das Du damit ``<shipping>`` und seine Kindelemente? Das heisst Du bist schon einmal an einem `shipping/price` vorbeigekommen innerhalb eines anderen ``<shipping>``-Elements? Oder gar innerhalb des Selben? Was soll denn dann mit den Daten passieren?
Bei SAX kommt von mir wieder die übliche Frage: Warum!? Geht nicht auch `ElementTree.iterparse()` bzw. muss es überhaupt zwingend lazy geparst werden?
Re: sax parser - tag gruppen, doppelte tag namen
Verfasst: Donnerstag 2. Dezember 2010, 11:30
von PauleJS
genau, mit tag gruppe meine ich <shipping> und seine kinderlemente!
ich bin bereits schonmal an einem <price> vorbei gekommen, nicht innerhalb eines anderen <shipping> elements
die geparsten daten sollen in einer liste gespeichert werden
es sollte schon wenn möglich mit sax geparst werden!
Re: sax parser - tag gruppen, doppelte tag namen
Verfasst: Donnerstag 2. Dezember 2010, 12:25
von BlackJack
@PauleJS: Ich verstehe jetzt das Problem nicht ganz? Wenn Du auf ein ``<shipping>`` triffst, bindest Du einen Namen, zum Beispiel `price` an `None` und immer wenn Du innerhalb eines ``<shipping>``\s auf ``<price>`` stösst, kannst Du schauen ob der Name schon einmal an einen anderen Wert als `None` gebunden wurde. In dem Falle musst Du halt irgend etwas machen. Den alten Preis ersetzen, eine Warnung ausgeben, ...
Re: sax parser - tag gruppen, doppelte tag namen
Verfasst: Donnerstag 2. Dezember 2010, 16:23
von PauleJS
BlackJack hat geschrieben:@PauleJS: Ich verstehe jetzt das Problem nicht ganz? Wenn Du auf ein ``<shipping>`` triffst, bindest Du einen Namen, zum Beispiel `price` an `None` und immer wenn Du innerhalb eines ``<shipping>``\s auf ``<price>`` stösst, kannst Du schauen ob der Name schon einmal an einen anderen Wert als `None` gebunden wurde. In dem Falle musst Du halt irgend etwas machen. Den alten Preis ersetzen, eine Warnung ausgeben, ...
ich kann also nicht zweimal <price> speichern? ich möchte den preis nicht ersetzen, oder meldungen ausgegeben bekommen, ich will nur das der wert hiervon auch gespeichert und am besten auch mit dem namen "price", nur als kind von "shipping"
Re: sax parser - tag gruppen, doppelte tag namen
Verfasst: Donnerstag 2. Dezember 2010, 16:38
von BlackJack
@PauleJS: Ich versteh's immer noch nicht. *Wie* willst Du zwei Preise speichern? Kommst Du jetzt einfach nicht auf das naheliegendste statt `None` eine Liste an `price` (bzw. dann besser `prices`) zu binden und wenn Du einen Preis parst, dann eben den Wert an diese Liste anzuhängen? Und was meinst Du mit »als Kind von "shipping"« speichern? Was wird denn aus den geparsten XML-Daten?
Kannst Du ein valides XML-Fragment zeigen und die Datenstruktur die Du daraus gerne erstellen würdest?
Re: sax parser - tag gruppen, doppelte tag namen
Verfasst: Montag 6. Dezember 2010, 14:51
von PauleJS
beispiel xml
Code: Alles auswählen
<rss>
<channel>
<item>
<title>Oversized-Shirt</title>
<link>
http://www.otto.de/artikel.up?artinr=34634234
</link>
<description>
Oversized-Shirt mit dekorativ verziertem Peace-Zeichen vorne
</description>
<g-core:price>29.95 EUR</g-core:price> -> preis 1
<g-core:shipping>
<g-core:country>de</g-core:country>
<g-core:service>Standard</g-core:service>
<g-core:price>5.95</g-core:price> -> preis 2
</g-core:shipping>
</item>
</channel>
</rss>
es gibt also zwei mal "<g-core:price>"! ich möchte nun das zweite <g-core:price> (preis 2) zb unter dem namen product_shipping_price speichern.
die liste sollte ungefähr so aussehen für das oben definierte produkt:
product_title = Oversized-Shirt
product_link =
http://www.otto.de/artikel.up?artinr=34634234
product_description = Oversized-Shirt mit dekorativ verziertem Peace-Zeichen vorne
product_price = 29.95 EUR # preis 1
product_shipping_country = de
product_shipping_service = Standard
product_shipping_price = 5.95 # preis 2
mit einer if schleife weiß ich wann ich bei shipping bin, danach soll er dann den inhalt von <g-core:price> (preis 2) in product_shipping_price speichern, ohne das er beim folgenden produkt den wert vom ersten <g-core:price> (preis 1) unter diesen namen abspeichert. der erste preis sollte ja wie beschrieben in product_price gespeichert werden
Re: sax parser - tag gruppen, doppelte tag namen
Verfasst: Montag 6. Dezember 2010, 20:28
von BlackJack
@PauleJS: Bei dem Beispiel gibt es das Problem was Du beschreibst doch gar nicht!? Da ist nur *ein* ``<price>`` innerhalb von ``<shipping>``, also gibt es da keine Mehrdeutigkeiten. Wenn Du nicht innerhalb von ``<shipping>`` bist, speicherst Du den Preis unter 'product_price' und wenn Du innerhalb von ``<shipping>`` bist, halt unter 'product_shipping_price'.
Ich nehme mal an, das die Werte aus einem ``<item>`` jeweils in einem Dictionary landen!?
Ich sehe das Problem immer noch nicht wirklich.
Re: sax parser - tag gruppen, doppelte tag namen
Verfasst: Dienstag 7. Dezember 2010, 10:32
von PauleJS
genau, alle werte sollen in eine dictionary!
ich habe nun folgenden code:
Code: Alles auswählen
types = ["title",
"link",
"description",
"guid",
"g-core:apparel_type",
"g-core:brand",
"g-core:color",
"g-core:condition",
"g-core:currency",
"g-core:expisation_date",
"g-core:id",
"g-core:image_link",
"g-core:manufacturer",
"g-core:payment_accepted",
"g-core:price",
"g-core:product_type",
"g-custom:language type",
"g-core:product_type",
"g-core:country",
"g-core:service",
"shipping_price"] # hier soll der preis fürs shipping eingetragen werden
class FeedHandler(ContentHandler):
def __init__(self):
self.data = []
self.item = None
self.type = None
self.shipping = False
def startElement(self, name, attrs):
if name == "g-core:shipping":
self.shipping = True
if name == 'item':
self.item = {} # mein dict
for i in types: self.item[i] = u""
if name in types:
self.type = name
def characters (self, ch):
ch = unicode(ch)
if self.shipping:
# ---> wie bekomme ich hier die tags innerhalb von shipping in mein dict item
if self.type and self.item != None:
self.item[self.type] +=ch
def endElement(self, name):
if name == "g-core:shipping":
self.shipping = False
if name in types: self.type = None
if name == 'item':
self.data.append(self.item)
self.item = None
data = open("RSS.xml")
parser = make_parser()
handler = FeedHandler()
parser.setContentHandler(handler)
parser.parse(data)
Re: sax parser - tag gruppen, doppelte tag namen
Verfasst: Dienstag 7. Dezember 2010, 14:32
von BlackJack
@PauleJS: Du musst das mit Deinem anderen ``if`` dort kombinieren, also innerhalb dessen zwischen "innerhalb von ``<shipping>``" und "ausserhalb von ``<shipping>``" unterscheiden.
Was Du übrigens nicht berücksichtigst, ist dass `characters()` nicht zwingend alle Daten auf einmal übergeben bekommt. Es ist möglich, dass die Methode für den gleichen Textknoten mehrfach aufgerufen wird, jeweils mit Teilen des Inhalts!
Letztlich bleibt bei mir immer noch die Frage warum es so eine umständliche "SAX mit eigenem Zustandsautomaten"-Lösung sein muss. Ist das RSS tatsächlich so gross, dass es nicht geparst in den Speicher passt?
Re: sax parser - tag gruppen, doppelte tag namen
Verfasst: Mittwoch 8. Dezember 2010, 13:54
von PauleJS
@BlackJack
ich habe es nun so geändert:
Code: Alles auswählen
def characters (self, ch):
ch = unicode(ch)
if self.type and self.item != None:
if self.shipping:
if self.item["g-core:price"]:
print self.item["g-core:price"]
else:
self.item[self.type] += ch
else:
self.item[self.type] +=ch
hier wird immer nur der preis ausserhalb von shipping angezeigt und nicht der shipping preis, innerhalb von shipping.
ist denn der ansatz deiner meinung nach richtig den shipping preis in "shipping_cost" zu speichern?
so ein feed beinhaltet mindestens 3000 items!
ideal wäre es wenn man alle items auf einmal parst und dann in eine datenbank schreiben kann. aber ich weiß leider noch nicht wie ich das machen soll
Re: sax parser - tag gruppen, doppelte tag namen
Verfasst: Mittwoch 8. Dezember 2010, 15:10
von BlackJack
@PauleJS: So kann man das machen.
Wieviele ``<item>``\s so ein Feed mindestens enthält, ist nicht so interessant, sondern eher wo die Obergrenze liegt. Wenn der grösste zu erwartende Feed verarbeitet werden kann, dann sind kleinere ja auch kein Problem.
Weil ich mich nicht mit dem XML-Namensraum herumschlagen wollte, der in Deinem Beispiel steht, habe ich `lxml.html` zum Parsen verwenden -- dann könnte das ungefähr so aussehen:
Code: Alles auswählen
from lxml import html
TYPES = [
('title', 'title'),
('link', 'link'),
('description', 'description'),
('price', 'price'),
('country', 'shipping/country'),
('service', 'shipping/service'),
('shipping_price', 'shipping/price')
]
def process_item_node(node):
result = dict()
for name, path in TYPES:
values = node.xpath('./%s/text()' % path)
result[name] = values[0] if values else ''
return result
def main():
doc = html.parse('test.xml').getroot()
result = map(process_item_node, doc.xpath('//item'))
print result
if __name__ == '__main__':
main()
Re: sax parser - tag gruppen, doppelte tag namen
Verfasst: Mittwoch 8. Dezember 2010, 16:07
von PauleJS
@ BlackJack
hui das sieht kompliziert aus! ich werde mir das heute abend mal genau anschaun
werden die daten also nach deiner methode deutlich schneller verarbeitet, als wenn man es item für item so macht wie ich es bisher hatte? wenn ich über 3000 items einlese dauert es schon ein wenig wenn man es einzeln macht.
Re: sax parser - tag gruppen, doppelte tag namen
Verfasst: Mittwoch 8. Dezember 2010, 18:13
von BlackJack
@PauleJS: Keine Ahnung ob es schneller ist, es ist IMHO deutlich einfacher vom Programm her was man durchschauen muss. Also eine Funktion die genau ein ``<item>``-Element verarbeitet, statt einer Klasse, die alles verarbeitet und das mit eigenen Zuständen die man sich merken muss und über mehrere Methoden verteilt.
Re: sax parser - tag gruppen, doppelte tag namen
Verfasst: Donnerstag 9. Dezember 2010, 09:49
von PauleJS
@ BlackJack
ich habe nun bei mir einfach ein zweites dict angelegt welches alle tags innerhalb von shipping speichert! so funktioniert es jetzt
ich werde aber deine methode auch mal ausprobieren um zu testen ob es hier schneller geht.
ausserdem habe ich auch einen csv importer der im moment zeilenweise daten einliest und in eine db schreibt, werde auch hier mal probieren deinen hierauf an zu passen, denke das die dateien dann noch schneller verarbeitet werden können.
vielen danke schonmal für deine hilfreichen tipps!