Tag in einer xml Datei ersetzen

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
Pippen19
User
Beiträge: 2
Registriert: Dienstag 11. März 2025, 17:36

Hallo zäme
Ich bin neu hier und habe bis jetzt keine Erfahrung in python. Nun will ich in einem xml File, das folgendermassen beginnt, den Text des Tags <ProjectVersion> durch einen neuen (eine neue Version) ersetzen. Der Rest der Datei soll gleich bleiben.

Beginn der xml Datei:

Code: Alles auswählen

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <FileVersion>1.0.0.0</FileVersion>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{2d33b7f3-0195-487c-b677-008e32b2b56b}</ProjectGuid>
   [b] <ProjectVersion>0.0.0.5</ProjectVersion>[/b]
    <SubObjectsSortedByName>True</SubObjectsSortedByName>
    <DownloadApplicationInfo>true</DownloadApplicationInfo>
    <WriteProductVersion>false</WriteProductVersion>
    <GenerateTpy>false</GenerateTpy>
    <Name>LibWagnerComponents</Name>
    <ProgramVersion>3.1.4024.0</ProgramVersion>
...
</Project>
Nun habe ich das folgendermassen versucht:

Code: Alles auswählen

import xml.etree.ElementTree as ET

def update_project_version(file_path, file_path_new, new_version):
    # XML-Datei einlesen
    tree = ET.parse(file_path)
    root = tree.getroot()

    # <ProjectVersion>-Tag finden und aktualisieren
    for project_version in root.findall('ProjectVersion'):
        project_version.text = new_version

    # Änderungen in die XML-Datei zurückschreiben
    tree.write(file_path_new, encoding='utf-8', xml_declaration=True)

if __name__ == "__main__":
    # Name der XML-Datei (im selben Verzeichnis)
    xml_file_path = 'Example.xml'
    xml_file_path_new = 'Example_new.xml'
    
    # Neue Version
    new_version = '0.0.0.10'
    
    # Funktion aufrufen, um die Version zu aktualisieren
    update_project_version(xml_file_path, xml_file_path_new, new_version)
    print(f'Die <ProjectVersion> wurde auf {new_version} aktualisiert.')
Dabei gibt es zwei Probleme:
1. Die Version wird gar nicht updatet. Das heisst, dass das Tag nicht gefunden wurde.
2. In der Ausgabedatei hat es am Anfang jedes Tags so einen namespace Eintrag (ns0:)

<?xml version='1.0' encoding='utf-8'?>
<ns0:Project xmlns:ns0="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<ns0:PropertyGroup>
<ns0:FileVersion>1.0.0.0</ns0:FileVersion>
<ns0:SchemaVersion>2.0</ns0:SchemaVersion>
<ns0:ProjectGuid>{2d33b7f3-0195-487c-b677-008e32b2b56b}</ns0:ProjectGuid>

Wie löse ich diese beiden Probleme?
Benutzeravatar
__blackjack__
User
Beiträge: 13882
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Pippen19: Das zweite Problem ist keins, da muss man also nichts lösen.

Beim ersten ist `findall()` und eine Schleife ja schon der falsche Ansatz wenn man *ein* Element sucht. Und es wird wahrscheinlich wegen dem Namensraum nicht gefunden. Den muss man angeben wenn Namensräume verwendet werden.
“Man wirft uns vor, wir hätten kein Programm, das Programm sei nicht umsetzbar, und die anderen Parteien hätten das alles auch im Programm.“ — Pavel Mayer, Piratenpartei
Sirius3
User
Beiträge: 18185
Registriert: Sonntag 21. Oktober 2012, 17:20

Das sind Namespaces. Du mußt also nach

Code: Alles auswählen

"{http://schemas.microsoft.com/developer/msbuild/2003}ProjectVersion"
suchen. Ob der Namespace als Default angegeben ist, oder über den Namen ns0 ist egal. Das ist das selbe XML.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1196
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<FileVersion>1.0.0.0</FileVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{2d33b7f3-0195-487c-b677-008e32b2b56b}</ProjectGuid>
<ProjectVersion>0.0.0</ProjectVersion>
<SubObjectsSortedByName>True</SubObjectsSortedByName>
<DownloadApplicationInfo>true</DownloadApplicationInfo>
<WriteProductVersion>false</WriteProductVersion>
<GenerateTpy>false</GenerateTpy>
<Name>LibWagnerComponents</Name>
<ProgramVersion>3.1.4024.0</ProgramVersion>
</PropertyGroup>
</Project>
Mit lxml funktioniert es, mit xml von Python nicht.
Keine Ahnung warum, aber ist mit mittlerweile egal. Ich nutze einfach lxml, wenn ich mit xml von Python nicht weiterkomme.

Code: Alles auswählen

import lxml.etree as ET
def set_version(file, version):
    doc = ET.parse(file)
    root = doc.getroot()
    ns = {"ms": "http://schemas.microsoft.com/developer/msbuild/2003"}
    element = root.find(".//ms:ProjectVersion", namespaces=ns)
    if element is None:
        raise RuntimeError("Could not find ProjectVersion")

    element.text = str(version)
    doc.write(file)
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Pippen19
User
Beiträge: 2
Registriert: Dienstag 11. März 2025, 17:36

Vielen Dank für eure Antworten. Aus den Antworten lese ich, dass diese Namespace Angabe "ns0:" kein Fehler ist.
Und beim Suchen liegt der Fehler darin, dass ich den Namespace vergessen habe.

Frage: Gibt es bei der xml.etree.elementtree library die Möglichkeit, dass die Namespace Angabe nicht bei jedem Tag vorangestellt wird?

Denn es ist ja der Default Namespace und im originalen xml File steht auch nur die Angabe "<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">"
und bei den Kinder Tags ist dann der Namespace nicht mehr angegeben.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1196
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Ich hab ChatGPT befragt.

Um das mit ns0 wegzubekommen, kann man ein Standard-Namespace setzen: ET.register_namespace("", "NAMESPACE")

Code: Alles auswählen

import xml.etree.ElementTree as ET


def set_version(file, version):
    ET.register_namespace("", "http://schemas.microsoft.com/developer/msbuild/2003")
    doc = ET.parse(file)
    root = doc.getroot()
    ns = {"ms": "http://schemas.microsoft.com/developer/msbuild/2003"}
    element = root.find(".//ms:ProjectVersion", namespaces=ns)
    if element is None:
        raise RuntimeError("Could not find ProjectVersion")

    element.text = str(version)
    with open(file, "wb") as fd:
        fd.write(ET.tostring(root, encoding="utf-8", xml_declaration=True))
Den Header, den ich vergessen habe mitzukopieren, wird durch ET.tostring(..., xml_declartion=True) neu erstellt. Das angegebene Encoding wird in den xml header mit eingefügt.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Antworten