Anmelden Registrieren

Badges

Follow Peter Bouda on Google Plus

Feeds

Neueste BlogeinträgeBlog

Tag-Name per Qt-XML im XML-DOM ersetzen

Bearbeitet am Donnerstag, 17. März 2011, 17:06 Uhr von pbouda

In der XML-DOM-Spezifikation gibt es leider keine einfache Möglichkeit, innerhalb eines XML-Dokuments den Namen eines Elements (bzw. den Namen eines XML-Tags) zu ersetzen. Man hat also beispielsweise folgendes XML-Dokument:

<doc>
  <tag attr="true">Ich will einen neuen Namen</tag>
  <tag><i>Und</i> ich auch</tag>
</doc>

Und will am Ende folgendes Dokument bekommen:

<doc>
  <neuertag attr="true">Ich will einen neuen Namen</neuertag>
  <neuertag><i>Und</i> ich auch</neuertag>
</doc>

Mit regulären Ausdrücken kein Problem, werdet ihr sagen; spätestens mit bedingtem Ersetzen (z.B. je nach Attribut) und verschachtelten XML-Elementen wird das aber irgendwann mit dem Standardsatz an regulären Ausdrücken unmöglich. Es gibt zwar z.B. in .NET eine Erweiterung namens Balanced Groups, da wird es aber selbst für meine Perl-gestählten Verhältnisse sehr unschön. Etwas einfacher geht es dann doch noch übers XML-DOM, indem ihr einfach die entsprechenden Tags heraussucht und dann alle Attribute und Kind-Elemente in einen neuen Knoten kopiert. In Python sieht das dann etwa so aus, ich verwende hier die Qt-XML-Bibliothek:

# -*- coding: utf8 -*-

from PyQt4 import QtXml, QtCore

text = '<doc><tag attr="true">Ich will einen neuen Namen</tag><tag><i>Und</i> ich auch</tag></doc>'

parser = QtXml.QDomDocument()
parser.setContent(text)
nodes = parser.elementsByTagName("tag")

# Alle Nodes in einer Liste speichern, das DOM wollen wir ja ändern
node_list = []
for i in range(0,nodes.length()):
    n = nodes.at(i)
    node_list.append(n)
    
    
for n in node_list:
    n_parent = n.parentNode()
    new_content = parser.createElement('neuertag')
    
    attr_map = n.attributes()
    new_attributes = new_content.attributes()
    for j in range(attr_map.length()):
        new_attributes.setNamedItem(attr_map.item(j))
    
    child_nodes = n.childNodes()
    for j in range(child_nodes.length()):
        c = child_nodes.at(j)
        new_content.appendChild(c.cloneNode())

    n_parent.replaceChild(new_content, n)

qstring = QtCore.QString()
textStream = QtCore.QTextStream(qstring)
parser.save(textStream, 0)
text = unicode(qstring)

print text

Das Kopieren der Attribute passiert in den Zeilen 22-25, die Kind-Elemente werden von der Schleife in 27-30 übernommen. cloneNode() sorgt dafür, das tatsächlich per deep copy eine Kopie des gesamten Elements angelegt wird, samt Unterelementen. Auch in diesem einfachen Fall nicht viel komplizierter als reguläre Ausdrücke, dafür aber noch mächtiger.