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!