PowerShell XML - gleichen Child bei allen Nodes hinzufügen
Hallo PowerShell-Guru's,
nach stundenlangem try-and-error bin ich am Ende und die Lösung sollte an sich ganz einfach sein. Bin ganz neu mit PS unterwegs und drum fehlt mir da leider zuviel an Hintergrundwissen und zur Syntax! Ich hoffe sehr, dass mir da jemand kurz unter die Arme greifen kann.
Folgendes:
Ich erhalte ein XML-file wie folgt:
Mit Powershell muss ich bei jedem <SPAREPARTS> ein neues Child "<GROUP>XGROUP</GROUP>" hinzufügen - und zwar immer dasselbe!
Erklärung: Anschliessend gebe ich das ganze in ein CSV-file aus, wobei das neue Child dann die dritte Spalte bildet (mit immer demselben Wert).
So sollte das Ergebnis in der XML-Datei aussehen:
Das Problem ist, dass ich schon alles mögliche versucht hatte, das SOLL-Ergebnis aber nicht hinbekomme!!!
Der Teil des Scripts, welches das bewerkstelligen soll sieht derzeit so aus:
Entweder ist mein ganzer Ansatz komplett falsch, aber zumindest habe ich bei Zeile 5 "ForEach-Object ...???" ein massives Problem von wegen keiner Ahnung wie das Syntaxmässig aussehen sollte damit das Child dann auch bei allen Elementen eingefügt wird!
Vielen Dank für Eure Hilfe!
nach stundenlangem try-and-error bin ich am Ende und die Lösung sollte an sich ganz einfach sein. Bin ganz neu mit PS unterwegs und drum fehlt mir da leider zuviel an Hintergrundwissen und zur Syntax! Ich hoffe sehr, dass mir da jemand kurz unter die Arme greifen kann.
Folgendes:
Ich erhalte ein XML-file wie folgt:
<?xml version="1.0" encoding="UTF-8"?>
<PRODUCTS>
<SPAREPARTS>
<FATHER>02X_HBZ310</FATHER>
<PART>02X_HBZ103</PART>
</SPAREPARTS>
<SPAREPARTS>
<FATHER>02X_HBZ310</FATHER>
<PART>13X_EFLB1303S2</PART>
</SPAREPARTS>
...<SPAREPARTS> ...das wiederholt sich einige tausend male!
</PRODUCTS>
Erklärung: Anschliessend gebe ich das ganze in ein CSV-file aus, wobei das neue Child dann die dritte Spalte bildet (mit immer demselben Wert).
So sollte das Ergebnis in der XML-Datei aussehen:
<?xml version="1.0" encoding="UTF-8"?>
<PRODUCTS>
<SPAREPARTS>
<FATHER>02X_HBZ310</FATHER>
<PART>02X_HBZ103</PART>
<GROUP>XGROUP</GROUP>
</SPAREPARTS>
<SPAREPARTS>
<FATHER>02X_HBZ310</FATHER>
<PART>13X_EFLB1303S2</PART>
<GROUP>XGROUP</GROUP>
</SPAREPARTS>
...<SPAREPARTS> ...das wiederholt sich einige tausend male!
</PRODUCTS>
Der Teil des Scripts, welches das bewerkstelligen soll sieht derzeit so aus:
Curl $DownloadPath -o $XMLTempPath
[xml]$temp = Get-Content $XMLTempPath
$NewChild = $temp.CreateElement("XGROUP")
$NewChild.InnerText = $XGroup
ForEach-Object ...???
Set-Content $XMLImpPath
Vielen Dank für Eure Hilfe!
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 438260
Url: https://administrator.de/forum/powershell-xml-gleichen-child-bei-allen-nodes-hinzufuegen-438260.html
Ausgedruckt am: 04.05.2025 um 00:05 Uhr
7 Kommentare
Neuester Kommentar

#......
#...
foreach($node in $temp.SelectNodes('/PRODUCTS/SPAREPARTS')){
$node.appendChild($newChild.Clone()) | out-null
}
Btw. Sowas würde ich viel effizienter mit XSLT abfackeln, das wäre dann auch ums x fache schneller, das wurde nämlich genau für sowas geschaffen .

Zitat von @oliswiss:
Ha, ich habs
Die Zeile für Speichern muss dann so aussehen:
Es gibt ja die schöne Methode zum Speichern die extra dafür geschaffen wurde!Ha, ich habs
Die Zeile für Speichern muss dann so aussehen:
Set-Content -Path $XMLImpPath -Value $temp.InnerXml
$temp.Save('d:\pfad\datei.xml')
XSLT kenne ich nicht. Kann ich das denn innerhalb eines PS-Scripts verwenden?
Ja, wie das geht, findest du hier im Forum.Ein passendes XSL Stylesheet für dein obiges Vorhaben ist dieses hier
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/PRODUCTS/SPAREPARTS">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<GROUP>XGROUP</GROUP>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
https://www.freeformatter.com/xsl-transformer.html#ad-output
Uf Wiederluege

Wie kann ich einen Beitrag als gelöst markieren? nicht vergessen.
Servus @oliswiss,
Für das Beispiel sind deine Daten (xml und xlst) hier direkt im Code hinterlegt (deswegen ist die Funktion mit MemoryStreams und Readers etwas aufgebläht), die können selbstverständlich auch aus Dateien kommen. Diese Funktion gibt das Resultat direkt als String aus.
Alternativ akzeptiert die folgende vereinfachte Funktion direkt die entsprechenden Dateien per Pfadangabe und gibt das Ergebnis ebenfalls direkt als Datei aus:
Grüße Uwe
Zitat von @139374:
Ja, wie das geht, findest du hier im Forum.
damit du dir das nicht zusammensuchen musst hier das ganze noch XSLT-Transformation direkt in der Powershell:Ja, wie das geht, findest du hier im Forum.
Für das Beispiel sind deine Daten (xml und xlst) hier direkt im Code hinterlegt (deswegen ist die Funktion mit MemoryStreams und Readers etwas aufgebläht), die können selbstverständlich auch aus Dateien kommen. Diese Funktion gibt das Resultat direkt als String aus.
function Transform-XML {
param(
[string]$stylesheet,[string]$xml
)
try{
$xslt = New-Object system.xml.xsl.xslcompiledtransform
$xsltstream = New-Object System.IO.MemoryStream
$xmlstream = New-Object System.IO.MemoryStream
$outputstream = New-Object System.IO.MemoryStream
$xsltbuffer = [System.Text.Encoding]::UTF8.GetBytes($stylesheet)
$xmlbuffer = [System.Text.Encoding]::UTF8.GetBytes($xml)
$xsltstream.Write($xsltbuffer,0,$xsltbuffer.length)
$xmlstream.Write($xmlbuffer,0,$xmlbuffer.length)
$xsltstream.Position = 0
$xmlstream.Position = 0
$xsltreader = [System.Xml.XmlReader]::Create($xsltstream)
$xmlreader = [System.Xml.XmlReader]::Create($xmlstream)
$xslt.Load($xsltreader)
$args = [System.Xml.Xsl.XsltArgumentList]::new()
$xslt.Transform($xmlreader,$args,$outputstream)
$outputstream.Position = 0
$result = [System.IO.StreamReader]::new($outputstream).ReadToEnd()
$xsltstream.Dispose()
$xmlstream.Dispose()
$xsltreader.Dispose()
$xmlreader.Dispose()
$outputstream.Dispose()
return $result
}catch{
write-error $_.Exception
}
}
$myxml = @'
<?xml version="1.0" encoding="UTF-8"?>
<PRODUCTS>
<SPAREPARTS>
<FATHER>02X_HBZ310</FATHER>
<PART>02X_HBZ103</PART>
</SPAREPARTS>
<SPAREPARTS>
<FATHER>02X_HBZ310</FATHER>
<PART>13X_EFLB1303S2</PART>
</SPAREPARTS>
</PRODUCTS>
'@
$mystylesheet = @'
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/PRODUCTS/SPAREPARTS">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<GROUP>XGROUP</GROUP>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
'@
Transform-XML -stylesheet $mystylesheet -xml $myxml
Ergebnis:
<?xml version="1.0" encoding="utf-8"?>
<PRODUCTS>
<SPAREPARTS>
<FATHER>02X_HBZ310</FATHER>
<PART>02X_HBZ103</PART>
<GROUP>XGROUP</GROUP>
</SPAREPARTS>
<SPAREPARTS>
<FATHER>02X_HBZ310</FATHER>
<PART>13X_EFLB1303S2</PART>
<GROUP>XGROUP</GROUP>
</SPAREPARTS>
</PRODUCTS>
Alternativ akzeptiert die folgende vereinfachte Funktion direkt die entsprechenden Dateien per Pfadangabe und gibt das Ergebnis ebenfalls direkt als Datei aus:
function Transform-XML{
param(
[string]$xsltfile,[string]$xmlfile,[string]$xmlfileout
)
try{
$xslt = New-Object system.xml.xsl.xslcompiledtransform
$xslt.Load($xsltfile)
$xslt.Transform($xmlfile,$xmlfileout)
}catch{
throw $_.Exception.Message
}
}
Transform-XML -xsltfile 'D:\transform.xslt' -xmlfile 'D:\test.xml' -xmlfileout 'D:\test_new.xml'