letztes Objekt in einer XML finden

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
kruphi
User
Beiträge: 21
Registriert: Donnerstag 25. Juli 2013, 14:57

Nach dem Ihr mir letztes mal schon so klasse geholfen habt, bräuchte ich noch einmal eure Hilfe!

In meinem XML Objekt muss ich die Jahrgänge an einer bestimmten Stelle finden. Diese stehen wie unten an einem Beispiel beschrieben immer in einem Tag. Bei jedem Jahrgang wird ein neuer Tag eingefügt. Ich musst immer den letzten finden. Es können halt mal einmal Jahrgangsdaten auftauchen, aber auch mal 3 oder 4 Einträge.

Code: Alles auswählen

<mitglied>
    <personen>...</personen>
    ......
    ......
    <jahrgangsliste>
              <Jahrgangsdaten>
              <klasse> 12 </klasse>
              </jahrgangsdaten>
    </jahrgangsliste>
</mitglied>
mein Funktionen sehen bislang wie folgt aus. Mein Ansatz ist mit der Funktion rueck() heraus zu finden ob es noch einen nächsten Wert gibt. Gibt es da nicht einen eleganteren Weg?
Vielleicht etwas mit x.getElementsByTagName(y)[l].lastChild.nodeValue oder ähnliches.

Code: Alles auswählen


def rueck(l,x,y):

    try:
        wert = x.getElementsByTagName(y)[l].firstChild.nodeValue 
        return True
    except:
        return False
def getIt(x,y): #Gibt das Element zurück 
    try:
        return x.getElementsByTagName(y)[0].firstChild.nodeValue
    except:
        return ""
    file = open("hash.txt", "r") # read mode
    h = pickle.load(file)

def getIt2(x,y): #Gibt zweite das Element zurück 
Vielen Dank jetzt schon mal an dieser Stelle!
BlackJack

@kruphi: Ich würde ja einfach `lxml.etree` und XPath verwenden.

Ansonsten könntest Du über alle Kindknoten vom <mitglied>-Knoten iterieren und immer wenn ein <jahrgangsliste>-Knoten kommt, den an einen Namen binden. Nach der Schleife ist dann der letzte <jahrgangsliste>-Knoten an diesen Namen gebunden.
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

@kruphi: Ich würde ja ElementTree aus der Standardbibliothek nehmen. Für jeden Mitglied-Knoten gibt Dir dann member.find('jahrgangsliste/jahrgansdaten')[-1] das letzte Tag zurück.
kruphi
User
Beiträge: 21
Registriert: Donnerstag 25. Juli 2013, 14:57

es gibt doch eine Funktion mit dem getElementsByTagName(y)[l].lastChild.nodeValue die gibt mir allerdings nicht die richtigen Ergebnisse aus
BlackJack

@kruphi: Es gibt aber auch die ElementTree-API über das Modul aus der Standardbibliothek oder, etwas aufgebohrt, aus `lxml.etree`. Diesen DOM-Mist würde ich nur verwenden wenn man mich bedroht. ;-)
kruphi
User
Beiträge: 21
Registriert: Donnerstag 25. Juli 2013, 14:57

Leider laufen die anderen Teile des Programms schon mit minidom und ich will jetzt nicht alles umstricken!

Ich habe jetzt eine Lösung gefunden die mir das letzt Element anzeigt.

Code: Alles auswählen

def rueck(l,x,y):
    try:
        wert = x.getElementsByTagName(y)[l].firstChild.nodeValue 
        return True
    except:
        return False
def getLast(x,y):
    wert=0
    l=0
    while rueck(l,x,y):
        wert=x.getElementsByTagName(y)[l].firstChild.nodeValue
        l = l+1
    return wert   
Das wäre mein Lösungsansatz!
BlackJack

@kruphi: Oh, mann. :roll: Umständlicher geht es wohl kaum. Mach Dir mal klar wie viel unnötige Arbeit hier verrichtet wird. Wie oft immer und immer wieder der gleiche XML-Unterbaum nach den immer gleichen Knoten abgesucht wird, und wie oft eine Liste mit diesen Knoten erstellt, *einer* davon genommen, und alles wieder verworfen wird. Obwohl die Liste jedes mal den *gleichen Inhalt* hat.

Ausserdem sind die Namen sauschlecht. `x` und `y` kann man ja für Koordinaten verwenden, aber doch nicht für XML-Knoten und Tagnamen. Wenn man da `node` und `tag_name` verwendet, wird es gleich *viel* verständlicher. Bei `l` besteht zusätzlich zu dem nichtssagenden Namen bei vielen Schriftarten noch eine leichte Verwechslungsgefahr mit `I` und `1`.

Ein nacktes ``except`` ist ebenfalls eine schlechte Idee. Damit werden *alle* Ausnahmen behandelt, auch welche mit denen man gar nicht rechnet, und die man auf diese Weise niemals zu Gesicht bekommt. Man sollte dort immer die konkret erwartete(n) Ausnahme(n) angeben, oder dafür sorgen, dass nicht erwartete Ausnahmen nicht einfach „verschluckt” werden. Die `rueck()`-Funktion erscheint mir auch etwas zu spezialisiert und kurz, als dass es sich lohnen würde die als einzelne Funktion zu haben. Das hätte man auch gleich in die andere Funktion integrieren können.

Ungetestet:

Code: Alles auswählen

def get_last(node, tag_name, default=0):
    result = default
    for element in node.getElementsByTagName(tag_name):
        try:
            result = int(element.firstChild.nodeValue)
        except IndexError:
            pass    # Intentionally ignored.
    return result
kruphi
User
Beiträge: 21
Registriert: Donnerstag 25. Juli 2013, 14:57

@BlackJack: Danke für deine Kritik/Verbesserungsvorschläge, nur so werde meine Programme nicht nur lauffähig sondern auch effizient!
Wie gesagt ich bin erst seit 3 Woche dabei und freue mich über solche Vorschläge.
Ich habe diese soeben in mein Code eingebunden und alles läuft.

Besten Dank hierfür !
Antworten