franhe
Goto Top

Manipulation von XML Dateien - Werte Zuordnung zwischen zwei Dateien

Hallo zusammen,

ich habe eine Frage bzgl. Manipulation von XML Dateien. Da ich auf diesem Gebiet sehr neu bin und eine relativ schnelle Lösung bräuchte, benötige ich eure Hilfe.

Problemstellung:
- Ich habe zwei XML Dateien. Zuordnungen aus der einen Datei sollen gelesen werden und in die andere XML Datei als Wert geschrieben werden. Dies bezüglich hatte ich schon mehrmals
gelesen, dass sich vbs am besten eignet. Ist dies richtig?

1. Datei: C:\XML\Holz.xml (als Bild in den Anhang gelegt)
- In der Holz.xml findet man unter <HZID> bei dem <Namen> Eiche_TL_BA die Nummer 2
- Diese ID müsste gespeichert werden und anschließend muss geguckt werden, welcher Wert zur ID 2 gehört.
- Dies sieht man unten -> <Value>1.0. Dies müsste jetzt auch gespeichert werden.
- Nun weiß man, dass der Wert 1.0 zum Namen Eiche_TL_BA gehört. Diese Zuordnung soll in die Datei Sorten.xml
hinzugefügt werden.

2. Datei :C\XML\Sorten.xml (als Bild in den Anhang gelegt)
- In dieser Sorten.xml müssen die Wert Zuordnungen zu den jeweiligen Namen jetzt übernommen werden.
- Das heißt, dass ich aus der der Holz.xml nun weiß, dass zum Namen Eiche_TL_BA der value 1.0 gesetzt ist und diesen möchte ich jetzt auch gerne in meine Sorten.xml eintragen. Dazu müsste ich
nach dem in diesem Fall elementName suchen und nach Übereinstimmung fragen und danach den value unter <Numeric> von 0 auf 1 setzen. Dies möchte ich mit allen Namen machen, die ich in
der Holz.xml finde. Auch z.B. in diesem Fall mit Birke_TL_BA.

Jetzt bräuchte ich eure Hilfe. Hat jemand eine Möglichkeit, wie ich dies am elegantesten lösen könnte? Vielen vielen Dank schon einmal!!!

Content-ID: 348221

Url: https://administrator.de/contentid/348221

Ausgedruckt am: 22.11.2024 um 11:11 Uhr

colinardo
Lösung colinardo 05.09.2017, aktualisiert am 06.09.2017 um 13:50:04 Uhr
Goto Top
Servus,
würde ich heutzutage eher XSLT oder Powershell dafür benutzen, hier ein Powershell-Skript:
$xml_holz = [xml](gc 'C:\XML\Holz.xml')  
$xml_sorten = [xml](gc 'C:\XML\sorten.xml')  

$xml_holz.SelectNodes("//HZDef/HZID") | %{  
    $name = $_.nextSibling.'#text'  
    [string]$value = $xml_holz.SelectSingleNode("//HZZ/HZ[HZID-Ref = $($_.'#text')]/Value").'#text'  
    $xml_sorten.SelectSingleNode("//DataEntry[@elementName = '$name']") | %{$_.DataVariant.ScalarType.Numeric.value = $value}  
}
$xml_sorten.Save('C:\XML\sorten.xml')  
Grüße Uwe
FRANHE
FRANHE 05.09.2017 aktualisiert um 16:24:58 Uhr
Goto Top
Servus Uwe,

vielen vielen Dank schon einmal. Könnte ich bzgl Powershell auch noch einmal bitte deine Hilfe bekommen? Wenn ich hier mein Skript erstelle, komme ich zu folgender Fehlermeldung. Wüsstest du wo das Problem liegt?

Gruß Franz
fehlermeldung
colinardo
Lösung colinardo 05.09.2017 aktualisiert um 16:55:17 Uhr
Goto Top
Deine XML-Datei ist ungültig! Sieht man ja schon an deiner ersten Grafik. Du hast zwei Elemente als Wurzeln und das ist in XML ungültige Syntax! Es darf nur ein Root-Element geben dem alle anderen Elemente untergeordnet sind. Der der diese XML entworfen hat hat also einen derben Fehler gemacht face-wink.
FRANHE
FRANHE 06.09.2017 um 10:59:28 Uhr
Goto Top
Servus Uwe,

vielen Dank für den Hinweis. Dies konnte ich jetzt beseitigen und entsprechend abklären, wie das passieren konnte. Es funktioniert auch alles soweit, allerdings hätte ich noch eine Frage. Würde mich freuen, wenn du mir da auch noch weiterhelfen könntest face-smile

Ich habe jetzt in der Holz_xml die HZID auf 1 gestelllt und möchte jetzt gerne den Wert von der HZID 1 übernehmen. Leider klappt das noch nicht. Er lässt die Zeile dann einfach in der Sorten.xml leer. Hast du vllt. ne Idee wie ich das Problem lösen könnte? Ich habe die Bilder in den Anhang gelegt.

Allerbesten Dank schon einmal!

Gruß
Franz
sorten_xml
holz_xml
colinardo
Lösung colinardo 06.09.2017 aktualisiert um 14:03:16 Uhr
Goto Top
Schau mal genau in deinen XML-Code face-smile im einen Knoten schreibst du den übergeordnertenKnoten HZS und im anderen HZZ, das ist dein Fehler, da kann der XPath String ja nicht mehr passen face-wink.

screenshot

Wenn du beide übergeordnete Knotennamen (HZZ/HZS) berücksichtigen musst, musst du das auch sagen!
Wenn das kein Schreibfehler von dir ist und du beide Knotenarten berücksichtigen willst schreibst du Zeile 6 so um
[string]$value = $xml_holz.SelectSingleNode("//HZ[HZID-Ref = $($_.'#text')]/Value").'#text' 

Als Lektüre zu XPath empfehle ich dir folgende Seite
https://www.w3schools.com/xml/xpath_syntax.asp
FRANHE
FRANHE 07.09.2017 um 09:03:00 Uhr
Goto Top
Servus Uwe,

das war genau mein Fehler! Jetzt funktioniert alles wie gewolltface-smile Allerbesten Dank!!

Viele Grüße
Franz
FRANHE
FRANHE 12.09.2017 um 17:28:28 Uhr
Goto Top
Hallo Uwe,

ich hätte noch eine kurze Frage hierzu.
Wenn ich oben im ersten Root BuildWarning den Namen des Attribut vor dem Durchlauf durch TPT statt THT tauschen will. Wie kann ich sowas machen?

Meine Ansätze waren das ich dies vor der Schleife mit
$xml_holz.BuildWarnings.SetAttribute... machen würde.

Funktioniert so etwas?

Vielen Dank schon einmal!

Gruß Franz
buildwarnings
colinardo
Lösung colinardo 12.09.2017 aktualisiert um 18:15:42 Uhr
Goto Top
# Attribut mit selbem Wert aber anderem Namen hinzufügen
$xml_holz.BuildWarnings.SetAttribute('TPT',$xml_holz.BuildWarnings.THT)  
# altes Attribut entfernen
$xml_holz.BuildWarnings.RemoveAttribute('THT')  
# Holz XML bei Bedarf speichern
$xml.Save("C:\XML\Holz.xml")  
FRANHE
FRANHE 13.09.2017 aktualisiert um 22:59:30 Uhr
Goto Top
Vielen Dank, Uwe.

Eine Sache wundert mich jetzt aber dennoch.

Wenn als Attribut im root Element der Namespace durch das xmlns angegeben ist funkioniert dein Skript nicht mehr.

zum Beispiel:
<BuildWarnings xmlns "Test123">

Und ich kann das Attribut auch nicht so einfach löschen oder ändern. Wie ist das zu erklären? Weißt du da weiter?
Danke schon einmal!!


Viele Grüße
Franz
colinardo
colinardo 14.09.2017 aktualisiert um 09:06:48 Uhr
Goto Top
Zitat von @FRANHE:

Vielen Dank, Uwe.

Eine Sache wundert mich jetzt aber dennoch.

Wenn als Attribut im root Element der Namespace durch das xmlns angegeben ist funkioniert dein Skript nicht mehr.
Vollkommen normal das es dann nicht mehr geht, denn mit Namespace muss man den Namespace bei den XPath Selections mit angeben! XML ist da sehr pingelig.
Such einfach mal nach "Namespacemanager" in meinen Beiträgen, das habe ich hier schon sehr oft gezeigt wie das mit Namespaces geht.
FRANHE
FRANHE 14.09.2017 um 11:00:08 Uhr
Goto Top
Hallo Uwe,

ich habe mich jetzt in deinen Beiträgen erkundigt und bin auf deinen eigenen Code gestoßen, alle Namespaces automatisch hinzufügen. Diesen habe ich jetzt auch hinzugefügt, allerdings funktioniert es noch. Siehst du vllt. meinen Fehler?

Danke schon einmal.

Gruß
Franz
fehlernamespace
FRANHE
FRANHE 14.09.2017 um 11:04:54 Uhr
Goto Top
Ich habe es hier auch noch auf eine andere Art und Weise versucht. Also den namespace manuell gesetzt.
Allerdings bekomme ich hier eine Fehlermeldung.

Gruß
Franz
fehlersuche
bild2
colinardo
colinardo 14.09.2017 aktualisiert um 12:21:32 Uhr
Goto Top
Nun ja du verwendest nur einen Namespacemanager für die holz XML bei der Abfrage in Zeile 11 verwendest du aber den Namespacemanager der Holz XML bei der Sorten-XML und da die einen anderen bzw. keinen Namespace verwendet kann er auch keine Nodes finden wenn du dort den Prefix anwendest!
Also wenn du bei der Sorten-XML einen anderen Namespace hast entweder einen zusätzlichen Namespacemanager für die Sorten-XML anlegen und auf diesen bei SelectSingleNode verweisen inkl. passendem Prefix oder wenn du keinen Namespace dort hast keine Prefixe im XPath verwenden.
FRANHE
FRANHE 14.09.2017 um 12:59:31 Uhr
Goto Top
Ahh okay, das habe ich jetzt verstanden. Nun läuft das Skript auch durch allerdings bleibt das Feld in der Sorten.xml nun komplett leer. Es sieht so aus, als würde er den $value nicht übertragen. Kannst du dir erklären woran das liegt?
Vielen Dank schon einmal für die Tipps bisher.

Gruß
Franz
fehler1
colinardo
Lösung colinardo 14.09.2017 aktualisiert um 13:15:40 Uhr
Goto Top
Du hast in Zeile 10 den Node HZID-Ref nicht mit dem Prefix versehen face-wink. Deswegen findet er keinen Node und somit hat die Variable auch keinen Wert, Ergo: Leer.
Einfach schritt für Schritt kommentieren und die Variablen auf der Konsole ausgeben lassen oder die XPath Selections manuell testen, so lernst du am meisten von der Powershell diesem Thread,
FRANHE
FRANHE 14.09.2017 um 21:16:46 Uhr
Goto Top
Vielen Dank Uwe! Das hat wirklich geholfen! Also natürlich ist es im ersten Moment schöner die Antwort direkt zu bekommen, jedoch hat diesmal durch deine kleinen Hilfestellungen wirklich "Klick" gemacht! Besten Dank!

Das mit Kommentaren hört sich gut an. Was ich auch schön öfters gelesen habe, das Programm mit den Powershell Tools zu debuggen. Was hältst du davon?

Gruß Franzface-smile
FRANHE
FRANHE 15.09.2017 um 10:09:19 Uhr
Goto Top
Uuund ich hätte noch eine Frage zu einer Erweiterung und würde mich freuen, wenn du mir da einen Ratschlag geben könntest.
Und zwar will ich dieses Schema jetzt wieder in mehreren Unterordnern ausführen. Prinzipiell weiß ich auch wie das funktionieren könnte, allerdings ist mir der Weg nicht ganz klar.

Ich habe wieder beliebig namige Testordner und ich möchte das Skript in allen Ordnern ausführen lassen zwischen den Dateien. Mir ist in meinem Aufbau mit den verschachtelten Schleifen auch der Fehler klar, allerdings komme ich hier irgendwie nicht weiter.

Gibt es hier sowas wie: Foreach($value_a in $ Value_a -AND $value_b in $ Value_b)?

Vielen Dank schon einmal.

Gruß Franz
unterordner
beliebige_unterordner
aufbau_unterordner
colinardo
colinardo 15.09.2017, aktualisiert am 17.09.2017 um 08:32:19 Uhr
Goto Top
p.s. es gibt hier Code-Tags für deinen Quellcode: <code> Quellcode </code>. Da ist leichter für uns da wir sonst den Code nicht kopieren können.

Hier mit Kommentaren für jede Zeile:
# für jeden Unterordner von 'C:\XML' 
gci 'C:\XML' -Directory | %{  
    # öffnen der Sorten.xml
    $xml_sorten = [xml](gc "$($_.Fullname)\Sorten.xml")  
    # Für jede XML-Datei im Holz-Ordner
    gci "$($_.Fullname)\Holz\*.xml" | %{  
        # XML in Objekt laden
        $xml_holz = [xml](gc $_.Fullname)
        # Namespacemanager erstellen
        $ns = new-Object System.Xml.XmlNamespaceManager $xml_holz.NameTable
        $ns.AddNamespace("ns",$xml_holz.DocumentElement.NamespaceURI)  
        # Für jeden HZID Knoten ...
        $xml_holz.SelectNodes("//ns:HZDef/ns:HZID",$ns) | %{  
            # speichere Name in Variable
            $name = $_.nextSibling.'#text'  
            # hole Wert mit Referenz auf HZID Wert und speichere diesen in Variablen '$value'' 
            [string]$value = $xml_holz.SelectSingleNode("//ns:HZZ/ns:HZ[ns:HZID-Ref = $($_.'#text')]/ns:Value",$ns).'#text'  
            # setze die Info in die sorten.xml
            $xml_sorten.SelectSingleNode("//DataEntry[@elementName = '$name']",$ns) | %{$_.DataVariant.ScalarType.Numeric.value = $value}  
        }
    }
    # Speichern der Sorten.xml
    $xml_sorten.Save($_.Fullname)
}
Hoffe das war es jetzt für diesen Fred.

Grüße Uwe

p.s. sorry das ich im Moment nicht immer zeitnah antworten kann da ich gerade sozusagen im "Outback" bin und nicht immer Zugang zum Web habe.

Dankesgrüße können wie immer hier abgeladen werden face-wink.
FRANHE
FRANHE 16.09.2017 um 16:52:16 Uhr
Goto Top
Hallo Uwe,

vielen Dank dafür!! Das hat mir wirklich viel geholfen.
Und das war es auch für diesen Fred face-smile

Gruß Franz