Knoten aus XML-Dateien entfernen

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.
alpha
User
Beiträge: 195
Registriert: Freitag 23. Mai 2003, 23:24
Wohnort: Ulm

Knoten aus XML-Dateien entfernen

Beitragvon alpha » Montag 8. August 2005, 10:23

Hallo Leute,

ich habe gerade Python Neuland betreten und versuche mich
an einer XML Datei die so aufgebaut ist:

Code: Alles auswählen

<?xml version="1.0"?>
<!-- ctOPCServer configuration file -->
<OPCServer>
   <MinPollRate>60000</MinPollRate>
   <AlarmServer>
      <DatabaseFileAndPath>c:\programs\centro\cmi\proto\wsl.mdb</DatabaseFileAndPath>
   </AlarmServer>
   <WSL6>
      <EquipmentId>Q4POCA-L</EquipmentId>
   </WSL6>
   <CESAR>
      <Name>Q4POCA-1</Name>
      <Namespace>
         <Entry>
            <Device>Boot</Device>
            <Unit>Geschw</Unit>
            <Parameter Vartype="VT_R4">AbTol</Parameter>
         </Entry>
         <Entry>
            <Device>Boot</Device>
            <Unit>Geschw</Unit>
            <Parameter Vartype="VT_R4">AlTol</Parameter>
         </Entry>
         <Entry>
            <Device>Boot</Device>
            <Unit>Geschw</Unit>
            <Parameter Vartype="VT_R4">Aussen</Parameter>
         </Entry>
...


Jetzt möchte ich einige Einträge rausschmeisen z.B. den folgenden Knoten,
weil da Boot und Geschw drin ist, und die Datei neu schreiben.

Code: Alles auswählen

         <Entry>
            <Device>Boot</Device>
            <Unit>Geschw</Unit>
            <Parameter Vartype="VT_R4">AlTol</Parameter>
         </Entry>


Ich hab jetzt schon über eine Stunde in der Hilfe gesucht und mir auch das
Pyxml-Paket runtergeladen, komm aber einfach nicht klar damit.
Ihr seid meine letzte Hoffnung. Könnt Ihr mir einen Ansatz sagen, wie sowas zu bewerkstelligen ist. Ich könnte natürlich das File selber durchparsen, aber da gibt es doch in den XML-Modulen (die ich sehr unübersichtlich finde) sicher einen einfacheren Weg.

Grüsse
alpha
ProgChild
User
Beiträge: 210
Registriert: Samstag 9. April 2005, 10:58
Kontaktdaten:

Beitragvon ProgChild » Montag 8. August 2005, 11:37

Erst öffnest du die Datei.

Code: Alles auswählen

import xml.dom.minidom as xmldom

doc = xmldom.parse( "datei.xml" )


Jetzt musst du eine recursive Funktion schreiben, die überprüft, ob die Kinder deines Elements

Code: Alles auswählen

name = "entry"
parent = doc

for child in parent.childNodes:
   if child.nodeType == doc.ELEMENT_NODE and \
      child.nodeName == name:
         pass


Wenn du das Richtige gefunden hast, dann musst du die Einträge nur noch löschen und mit writexml in die Datei zurück schreiben.

Code: Alles auswählen

for child in node.childNodes:
    node.removeChild( child )


Der Code ist ungetestet, sollte aber funktionieren. Es reicht allerdings nicht, die sachen Hintereinander in eine Python Datei zu schreiben...
alpha
User
Beiträge: 195
Registriert: Freitag 23. Mai 2003, 23:24
Wohnort: Ulm

Beitragvon alpha » Montag 8. August 2005, 13:58

Hallo progchild,

danke für Deine schnelle Anwort. Ich hab mal weiterprobiert.
Was ich nun nicht verstehe ist, dass ich wenn ich

Code: Alles auswählen

print parent.childNodes


nur

Code: Alles auswählen

[<DOM Comment node " ctOPCServ...">, <DOM Element: OPCServer at 0xe28238>]

als Ausgabe bekomme. ich hätte mit allen Kindknoten gerechnet.

Wie komme ich jetzt den Baum weiter runter?

Gruss
alpha
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Montag 8. August 2005, 14:55

Das sind soweit ich sehe ja auch Nodes also könnte man folgendes versuchen: parent.childNodes[0].childNodes.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
alpha
User
Beiträge: 195
Registriert: Freitag 23. Mai 2003, 23:24
Wohnort: Ulm

Beitragvon alpha » Montag 8. August 2005, 15:43

Hallo nochmal,

@ Leonidas
jupp so gehts. Aber letztendlich müsste ich die Knoten die ich abfragen will mit

Code: Alles auswählen

print parent.childNodes[1].childNodes[7].childNodes[3].childNodes


ansprechen. Gibts da keinen MoveDown Befehl oder so, damit ich das ganze per rekursion erledigen kann. In der Hilfe hätte ich keinen solchen Befehl bei 13.6.2.2 Node Objects gefunden. Oder ist das die falsche Stelle?

Ich hoffe Ihr könnt mir noch einmal helfen, da ich nun schon auf dem richtigen Weg bin.

Danke
alpha
Clython
User
Beiträge: 151
Registriert: Samstag 21. August 2004, 13:58
Wohnort: Schweiz, BE-2500

Beitragvon Clython » Montag 8. August 2005, 21:50

Kommentar am Rande:

Du hättest auch einfach XSLT dafür gebrauchen können...
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Montag 8. August 2005, 23:59

Clython hat geschrieben:einfach XSLT

Ich würde es eher "kompliziert XSLT" schreiben und mich nach einer Python-Lösung umsehen..

So habe ich es immer noch nicht geschafft mit XSLT XML so zu bearbeiten dass XHTML rauskommt, dass von Firefox akzeptiert wird. Dabei sollte das eigentlich nicht so schwer sein :evil: Aber das nur so nebenbei.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Clython
User
Beiträge: 151
Registriert: Samstag 21. August 2004, 13:58
Wohnort: Schweiz, BE-2500

Beitragvon Clython » Dienstag 9. August 2005, 09:04

Es braucht einiges an Einarbeitungszeit, aber es ist auch ein mächtiges Tool. Der Fehler lag wohl weniger an XSLT, sondern an deinem XHTML Code, den du dafür schreiben musstest. Ich hab es bisher auch noch nie geschafft validen Code zu generieren.
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Dienstag 9. August 2005, 11:41

Der Code war durchaus in Ordnung der generiert wurde, ich habe ihn mit Sablotron und xsltproc generieren lassen und in eine Datei gespeichert, die hat Firefox angezeigt ohne murren. Aber als ich Firefox die XML-Datei öffnen ließ, die das XSLT eingebunden hat, damit sein TransforMiiX daraus XHTML generiert, hat das nicht mehr funktioniert. Aber vielleicht geht es nur wenn die Dateien Online sind, damit Firefox einen Content-Type bekommt, mit dem er das als XHTML auffasst. Na, keine Ahnung.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
alpha
User
Beiträge: 195
Registriert: Freitag 23. Mai 2003, 23:24
Wohnort: Ulm

Beitragvon alpha » Mittwoch 10. August 2005, 09:21

Ich denke mit dem Parsen komm ich soweit klar. Aber kann mir bitte jemand noch ein paar Zeilen posten, wie ich das ganze wieder in ein XML File bekomme?
Mit writexml komm ich leider garnicht klar

Ganz konkret:

Code: Alles auswählen

from xml.dom import minidom
doc = minidom.parse( "C:\\temp\\namespace_neu\\PoclA\\ctOPCServer.xml" )
...

wie kann ich ein verändertes "doc" wieder speichern?

Danke für eure Hilfe
alpha
ProgChild
User
Beiträge: 210
Registriert: Samstag 9. April 2005, 10:58
Kontaktdaten:

Beitragvon ProgChild » Mittwoch 10. August 2005, 11:22

alpha hat geschrieben:wie kann ich ein verändertes "doc" wieder speichern?


Ganz einfach:

Code: Alles auswählen

f = open( 'neu.xml', 'w' )
doc.writexml( f )
f.close()
alpha
User
Beiträge: 195
Registriert: Freitag 23. Mai 2003, 23:24
Wohnort: Ulm

Beitragvon alpha » Mittwoch 10. August 2005, 15:38

AHHHHHH...
Das war zu einfach :-)
Danke vielmals... hatte vergessen das Outputfile mitzugeben... peinlich :oops:
alpha
User
Beiträge: 195
Registriert: Freitag 23. Mai 2003, 23:24
Wohnort: Ulm

Beitragvon alpha » Freitag 12. August 2005, 10:02

Leider gibts noch ein Problem.
Ich gehe ja jetzt rekusiv durch den Baum durch. Wenn ich beim
<Entry> angekommen bin schau ich nach <Device> <Unit> und <Parameter>. Wenn mir die Inhalte nciht passen will ich <Entry> löschen. Jetzt bin ich aber schon in <Entry>... ist das ein Problem, denn laut Docu kann man ja nur einen Kindknoten löschen. Gibts da noch eine andere Löschfunktion?

Ich bekomm immer die Fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "F:\scripts\python\ctxml.py", line 43, in ?
    walknode(rootNode, outFile, level)
  File "F:\scripts\python\ctxml.py", line 13, in walknode
    walknode(node, outFile, level+1)
  File "F:\scripts\python\ctxml.py", line 13, in walknode
    walknode(node, outFile, level+1)
  File "F:\scripts\python\ctxml.py", line 28, in walknode
    node.removeChild(node)
  File "C:\Programme\Python24\Lib\site-packages\_xmlplus\dom\minidom.py", line 169, in removeChild
    raise xml.dom.NotFoundErr()
NotFoundErr: Node does not exist in this context


Noch meinen Code vergessen:

Code: Alles auswählen

def walknode(parent, outFile, level):
    for node in parent.childNodes:
        if node.nodeType == Node.ELEMENT_NODE:
            printLevel(outFile, level)
            outFile.write('Element: %s\n' % node.nodeName)
            if node.nodeName != "Entry":
                walknode(node, outFile, level+1)
            else: # wir sind da wo wir hin wollen
                """ Prüfen, ob wir den Knoten entfernen müssen """
                for values in delvalues:
                    found = 0
                    for value in values:
                        if value != "":
                            if node.childNodes[1].childNodes[0].nodeValue == value:
                                found = found + 1
                            if node.childNodes[3].childNodes[0].nodeValue == value:
                                found = found + 1
                            if node.childNodes[5].childNodes[0].nodeValue == value:
                                found = found + 1
                            if found == len(values):
                                """ Knoten zum Entfernen gefunden """
                                node.removeChild(node)


Hoffentlich habt ihr noch einen rettenden Tip für mich.
Danke
alpha
ProgChild
User
Beiträge: 210
Registriert: Samstag 9. April 2005, 10:58
Kontaktdaten:

Beitragvon ProgChild » Freitag 12. August 2005, 10:36

alpha hat geschrieben:

Code: Alles auswählen

node.removeChild(node)

Node kann nicht Gleichzeitig Eltern- und Kindelement sein. removeChild löscht das Kindelement eines Knotens. Im obrigen Fall ist node gleichzeitig sein Elternteil und sein Kind. Das geht ja mal nicht ;)
Pü-Ton
User
Beiträge: 67
Registriert: Donnerstag 8. Mai 2008, 07:52

Beitragvon Pü-Ton » Donnerstag 10. Juli 2008, 12:02

Ich schrieb hier mal rein, weil ich ein ähnliches Problem habe wie alpha ursprünglich hatte.
Nur, dass ich nicht den ganzen Knoten "Entry" sondern nur das Kind "Unit" löschen will...
Eigentlich will ich den Inhalt aus Unit mit einem anderen Ihnalt einer Liste ersetzen...

Also:

Code: Alles auswählen

<?xml version="1.0" ?>
<environment>
    <Info>
        <Name>Ich bin`s</Name>
        <Version>die dritte</Version>
        <Date>gestern</Date>
    </Info>
    <Variables>
        <Tag>
            <Name>Essen</Name>
            <Value>Obst</Value>
        </Tag>
        <Tag>
            <Name>ooo</Name>
            <Value>aaa</Value>
        </Tag>
    </Variables>
</environment>


ist das urspüngliche XML-File.

In einer Liste steht jetzt

Code: Alles auswählen

Array=[Gemüse, rrr]


und nun soll also "Obst" mit "Gemüse" und "aaa" mit "rrr" ersetzt werden...

Bin schon kräftig am experimentieren, seh aber nicht so ganz den richtigen Weg:

Code: Alles auswählen

for elements in xml.getElementsByTagName('Variables'):
            for node in elements.childNodes:
                if node.nodeType == xml.ELEMENT_NODE and node.nodeName == "Tag":
                    for value in xml.getElementsByTagName("Tag"):
                        if value.nodeType == xml.ELEMENT_NODE:
                            print value
                            node.removeChild(node)


Und als Fehlermeldung kommt:

Code: Alles auswählen


<DOM Element: Tag at 0x12fe0f8>

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python25\lib\lib-tk\Tkinter.py", line 1403, in __call__
    return self.func(*args)
  File "C:\Python25\TSQTP\func.py", line 474, in save
    node.removeChild(node)
  File "C:\Python25\lib\xml\dom\minidom.py", line 164, in removeChild
    raise xml.dom.NotFoundErr()
NotFoundErr


heisst das jetzt, dass es keinen Knoten mehr innerhalb "Tag" gibt?

Gibt es eine einfache Methode mit replace.Child()? Wenn ja, hat jm ein Bsp ?

Danke schonmal

Wer ist online?

Mitglieder in diesem Forum: Bing [Bot]