Bestimmte TAGS aus BMECAT heraus ziehen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
marlboro1980
User
Beiträge: 12
Registriert: Donnerstag 22. November 2007, 14:30

Hallo. Folgender Code erzeugt mir eine Endlosschliefe. Wäre schön wenn jemand dazu eine Idee hat.

Code: Alles auswählen

for node in xmldoc.getElementsByTagName("ARTICLE"):
	s = xmldoc.getElementsByTagName("SUPPLIER_AID")
	for node in s:
		file.write(node.toxml())
		l = xmldoc.getElementsByTagName("ARTICLE_DETAILS")
		for node in l:
			file.write(node.toxml().encode('utf8'))
			m = xmldoc.getElementsByTagName("MIME")
			for node in m:
				file.write(node.toxml().encode('utf8'))
Ich habe folgenden Code geschrieben. Problem das ich habe er schreibt mir in die datei:



<SUPPLIER_AID></SUPPLIER_AID><ARTICLE_DETAILS>
<DESCRIPTION_SHORT></DESCRIPTION_SHORT>
<DESCRIPTION_LONG></DESCRIPTION_LONG>
</ARTICLE_DETAILS>^
<MIME>
<MIME_TYPE>image/jpeg</MIME_TYPE>
<MIME_SOURCE>920_mas_022.jpg</MIME_SOURCE>
<MIME_DESCR>920_mas_022.jpg</MIME_DESCR>
<MIME_ALT>920_mas_022.jpg</MIME_ALT>
<MIME_PURPOSE>data_sheet</MIME_PURPOSE>
</MIME><MIME>
<MIME_TYPE>image/jpeg</MIME_TYPE>
<MIME_SOURCE>920_fot_031.jpg</MIME_SOURCE>
<MIME_DESCR>920_fot_031.jpg</MIME_DESCR>
<MIME_ALT>920_fot_031.jpg</MIME_ALT>
<MIME_PURPOSE>normal</MIME_PURPOSE>
</MIME><MIME>
<MIME_TYPE>image/jpeg</MIME_TYPE>
<MIME_SOURCE>920_fot_030.jpg</MIME_SOURCE>
<MIME_DESCR>920_fot_030.jpg</MIME_DESCR>
<MIME_ALT>920_fot_030.jpg</MIME_ALT>
<MIME_PURPOSE>thumbnail</MIME_PURPOSE>
</MIME><MIME>
<MIME_TYPE>image/jpeg</MIME_TYPE>
<MIME_SOURCE>920_fot_032.jpg</MIME_SOURCE>
<MIME_DESCR>920_fot_032.jpg</MIME_DESCR>
<MIME_ALT>920_fot_032.jpg</MIME_ALT>
<MIME_PURPOSE>detail</MIME_PURPOSE>

An die dieser Stelle sollte er jetzt eigentlich zum nächsten Article gehen. Tut er aber nicht. In gewisser Weise macht er das schon nur geht er direkt zum nächsten Mimebereich des nächsten Artikels ohne die SUPPLIER_AID etc mitreinzuschreiben.

Ich habe schon versucht die Schleife umzustrukturieren, aber ohne Erfolg.

Grüße Marlboro
Zuletzt geändert von marlboro1980 am Freitag 30. November 2007, 09:47, insgesamt 1-mal geändert.
BlackJack

Das ist keine Endlosschleife, nur eine die sehr lange läuft. Sagen wir es gibt 3 <ARTICLE>, die gehst Du in der äussersten Schleife durch. Für jeden <ARTICLE> gibst Du dann *alle* <SUPPLIER_AID> im *ganzen* Dokument durch, nicht nur die zu dem ersten <ARTICLE>, und für jeden <SUPPLIER_AID> gehst Du dann *alle* <ARTICLE_DETAILS> im *ganzen* Dokument durch usw.

Du darfst einfach nicht immer das *ganze* Dokument durchsuchen, sondern nur unter dem Teilbaum, den Du eine Schleife darüber gefunden hast.
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Wenn ich nicht ganz schief liege, dürfte das das BME_CAT-format sein, also ein vermutlich recht großer Katalog, das kann schonmal dauern.

Mit for-schleifen kann man nur endlosschleifen hinbekommen, wenn man über eine endlose Menge iteriert, was bei [], (), etc ausgeschlossen sein dürfte.
marlboro1980
User
Beiträge: 12
Registriert: Donnerstag 22. November 2007, 14:30

Gut das Problem habe ich verstanden. Danke. Nur weiss ich immer noch nicht wie ich die Schleife umschreiben muss damit ich jeden Artikel nur einmal durchgehe. Im Übrigen ist es ein BMECAT und ja es sind viele Artikel ;)
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Du musst einfach nur den jeweils aktuellen Knoten weiterverwenden, die Erklärung warum findest du 3 Posts über diesem.

Code: Alles auswählen

for node in xmldoc.getElementsByTagName("ARTICLE"): 
    s = node.getElementsByTagName("SUPPLIER_AID") # statt xmldoc.get...
    for node in s: 
    #usw
Jan-Peer
User
Beiträge: 166
Registriert: Dienstag 2. Oktober 2007, 10:55

Ich weiß nicht, ob es so günstig ist, immer "node" als Laufvariable zu benutzen - erstens könnte es ja durchaus sein, daß man noch auf den höherliegenden Knoten zugreifen möchte, und zum anderen weiß man irgendwann überhaupt nicht mehr, an welchem Knoten man denn jetzt eigentlich dran ist ...
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

…und im Übrigen bin ich der Meinung XPATH und lxml rocken.
TUFKAB – the user formerly known as blackbird
marlboro1980
User
Beiträge: 12
Registriert: Donnerstag 22. November 2007, 14:30

Code: Alles auswählen

from xml.dom import minidom
xmldoc = minidom.parse('/input.xml')
file = open('/output.xml',"a")

file.write('<root>')
for node in xmldoc.getElementsByTagName("ARTICLE"):
	s = node.getElementsByTagName("SUPPLIER_AID")
	for node1 in s:
		file.write('<ARTILCE>')
		file.write(node1.toxml())
		l = node.getElementsByTagName("DESCRIPTION_SHORT")
		for node2 in l:
			file.write(node2.toxml().encode('utf8'))
			k = node.getElementsByTagName("DESCRIPTION_LONG")
			for node3 in k:
				file.write(node3.toxml().encode('utf8'))		
				m = node.getElementsByTagName("MIME")
                                for node4 in m:
					file.write(node4.toxml())
				file.write('</ARTICLE>')
file.write('</root>')
file.close()
Hier die Lösung um aus einem BMECAT:
Artikelnummer,
Kurzbeschreibung,
Langbeschreibung,
Bildpfad

herauszuziehen.


Danke für die Hilfe. Grüße Marlboro
BlackJack

Das mag funktionieren, sieht aber sehr suspekt aus. Die verschachtelten Schleifen sollten sicher nicht so verschachtelt sein. Das dürfte so nur funktionieren, wenn alles ausser <MIME> genau einmal innerhalb eines <ARTICLE> vorkommt. Dann braucht man aber keine ``for``-Schleifen; schon gar nicht so komisch verschachtelt.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ich verstehe nicht, wieso Du eine Pseudo XML Datei per Hand in die Datei schreibst. Außerdem mischt Du das Parsing und das wegschreiben ... ich hätte dabei ein komisches Gefühl!

Ich würde Dir raten, einen neuen XML-Baum parallel zum Parsen aufzubauen und im Anschluss dann wegzuschreiben! Dadurch hast Du garantiert valides XML. Außerdem wird die Datei erst geschrieben, wenn das Parsen sauber abgeschlossen wurde.

Ciao,
Hyperion
marlboro1980
User
Beiträge: 12
Registriert: Donnerstag 22. November 2007, 14:30

BlackJack hat geschrieben:Das mag funktionieren, sieht aber sehr suspekt aus. Die verschachtelten Schleifen sollten sicher nicht so verschachtelt sein. Das dürfte so nur funktionieren, wenn alles ausser <MIME> genau einmal innerhalb eines <ARTICLE> vorkommt. Dann braucht man aber keine ``for``-Schleifen; schon gar nicht so komisch verschachtelt.
Ich bin absoluter Anfänger was die Python-Programmierung angeht. Im Grunde bin ich BWLer und kein Programmierer. Ob die Schleifen so Verschachtelt sein müssen oder nicht kann ich nicht sagen. Für BME_CATS funktioniert das Skript jedoch immer, da diese XMLs so genormt sind, dass der Aufbau immer identisch ist, egal von wem man ein BMECAT bekommt. Somit existieren pro <ARTICLE> immer nur ein <SUPPLIER_AID> etc.

Die PSEUDO-XML schreibe ich per Hand in die Datei damit ich das ganze als XLS-Daten öffnen kann. Das ORIGINAL BMECAT ist zu sehr verschacheltet als das ich es direkt in EXCEL reinladen könnte. Die Daten müssen dann im EXCEL noch manuell angepasst werden. Das nimmt mir leider kein Skript ab.

Grüße Marlboro
BlackJack

Noch was zu Deinem letzten Quelltext: Eine XML-Datei im "append"-Modus zu öffnen ist in der Regel falsch. An eine komplette XML-Datei kann man nichts anhängen weil es nur ein Wurzelelement geben darf.

Ich habe hier mal mit `ElementTree` etwas geschrieben, was die gleiche Ausgabe ergeben sollte wie Dein Quelltext: http://paste.pocoo.org/show/13222/

Dort sind keine unnötigen Schleifen und das einlesen und extrahieren der Knoten ist von der Ausgabe getrennt. Die Ausgabe ist auch nicht fehleranfällig "per Hand", sondern über einen neuen Element-Baum gelöst in den einfach die extrahierten Knoten eingefügt werden.

Das ist so allerdings schlecht als Tabelle vewendbar, weil am Ende jedes Artikeldatensatzes ja die "platt geklopften" MIME-Elemente stehen. Nach Deiner Beschreibung soll da nur ein Pfad zu einem Bild stehen!? Dann sollte man nur den MIME-Knoten mit dem Bild bzw. eventuell sogar nur den Pfad in das Ergebnis aufnehmen. Wenn man dann noch mit dem `csv`-Modul in eine CSV-Datei schreibt, liessen sich die Daten vielleicht sogar ohne grosse Nachbearbeitung in Excel importieren.

Die Umformung des XML liesse sich übrigens auch mit XSLT durchführen.
marlboro1980
User
Beiträge: 12
Registriert: Donnerstag 22. November 2007, 14:30

XSLT war auch mein erster Gedanke, da die Struktur dort eher HTML, XML ähnelt und nicht einer Programmiersprache. Aber entweder lag es an meinen XSLT-TAGS oder an der zu tief verschachtelten Struktur des BMECATS, das ich mit XSLT keine Vernünftigen Ergebnisse heraus bekommen habe.
Ich habe meinen CODE auch nochmal umgestellt, so das er nur eins von den fünf MIME-TAGs rausschreibt. Das habe ich über

Code: Alles auswählen

if node == "<MIME_PORPUSE>normal</MIME_PORPUSE>"
                                    file.write(node.parentNode.toxml()
gemacht. Ich werde mich wohl vorerst damit nicht weiter mit der Thematik auseinandersetzten, weil das eigentlich nicht mein Job ist aber, rein privat habe ich gefallen an Phyton gefunden. Auch XSLT ist nicht uninteressant. Ich werde wohl beides ein wenig vertiefen.
BlackJack

Angepasste Version des Python-Skripts: http://paste.pocoo.org/show/13328/

Bei XSLT gibt's keine Beschränkung durch die Verschachtelungstiefe. Besonders komplex ist diese Transformation auch nicht. Für so kleine Sachen eignet sich XMLStarlet ganz gut wenn man sich die etwas langatmigen Formulierungen in XSLT sparen möchte. Der Aufruf sähe in diesem Falle folgendermassen aus:

Code: Alles auswählen

xmlstarlet select \
    -t -e "root" \
        -m "//ARTICLE" \
            -e "article" \
                -c "SUPPLIER_AID" \
                -c "ARTICLE_DETAILS/DESCRIPTION_SHORT" \
                -c "ARTICLE_DETAILS/DESCRIPTION_LONG" \
                -c "MIME_INFO/MIME/MIME_PURPOSE[text()='normal']/.." \
    new_catalog_ok.xml
Das Äquivalent in XSLT:

Code: Alles auswählen

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">
  <xsl:template match="/">
    <root>
      <xsl:for-each select="//ARTICLE">
        <article>
          <xsl:copy-of select="SUPPLIER_AID"/>
          <xsl:copy-of select="ARTICLE_DETAILS/DESCRIPTION_SHORT"/>
          <xsl:copy-of select="ARTICLE_DETAILS/DESCRIPTION_LONG"/>
          <xsl:copy-of select="MIME_INFO/MIME/MIME_PURPOSE[text()='normal']/.."/>
        </article>
      </xsl:for-each>
    </root>
  </xsl:template>
</xsl:stylesheet>
Edit: Das XSLT von Hand ein wenig aufgeräumt und vereinfacht.
Antworten