spsman
Goto Top

XML Node per Powershell in der Mitte einfügen

Hallo,

ich habe eine XML-Datei in der ich Elemente in der Mitte hinzufügen möchte. Genauer gesagt möchte ich die erste "SW.Blocks.CompileUnit" clonen dahinter einfügen.

Die XML:
<?xml version="1.0" encoding="utf-8"?>  
<Document>
  <Engineering version="V1.6" />  
  <DocumentInfo>
   </DocumentInfo>
  <SW.Blocks.FC ID="0">  
    <AttributeList>
    </AttributeList>
    <ObjectList>
      <MultilingualText ID="1" CompositionName="Comment">  
      </MultilingualText>
      <SW.Blocks.CompileUnit ID="4" CompositionName="CompileUnits">  
        <AttributeList>
        </AttributeList>
        <ObjectList>
        </ObjectList>
      </SW.Blocks.CompileUnit>
      <SW.Blocks.CompileUnit ID="B" CompositionName="CompileUnits">  
         <ObjectList>
        
        </ObjectList>
      </SW.Blocks.CompileUnit>
      <MultilingualText ID="12" CompositionName="Title">  
        <ObjectList>
        </ObjectList>
      </MultilingualText>
    </ObjectList>
  </SW.Blocks.FC>
</Document>

Und meine Powershell:

$ObjName=('V15','M18')  
$OPN_in ='C:\OPN_2\OPN_Test.xml'  
$OPN_Out='C:\OPN_2\OPN_OUT.xml'  

# xml Objekt erstellen
$xml = New-Object XML
# xml laden
$xml.Load($OPN_in)

$Urxml = $xml.Clone()




#Alle Grund-Nodes erfassen
$obj_nodes=$xml.Selectnodes('/Document/SW.Blocks.FC/ObjectList')  
$obj_nodes.count # gibt eine 1 aus obwohl ich 4 erwarten würde
$obj_nodes

# Abfrage des ersten 'SW.Blocks.CompileUnit' Knotens 
$Urnode = $xml.SelectSingleNode("//SW.Blocks.CompileUnit")  


# abbrechen wenn kein Knoten gefunden wurde.
if (!$Urnode){
    throw "Error, 'SW.Blocks.CompileUnit' Node not found!"  
    exit 1
}

$z=0
foreach($Obj in $objName)
{
$newnode = $Urnode.Clone()
# id anpassen
$z+=1
$newnode.Id = (100*$z).ToString()

# hänge den kopierten Knoten im selben Parent wie vom Original wieder ins XML ein
[void]$Urnode.ParentNode.AppendChild($newNode)
}

#Letztes Element anfügen
$DelNote= $Xml.SelectNodes("/Document/SW.Blocks.FC/ObjectList/MultilingualText[@CompositionName='Title']")  
$EndNode = $DelNote.clone()

#$DelNote.ParentNode
$DelNote.ParentNode.RemoveChild($DelNote) | Out-Null #Fehlermeldung

$EndNode.Count

[void]$Urnode.ParentNode.AppendChild($EndNode)


#$Tempnode.ParentNode.AppendChild($Tempnode)

# speichere das geänderte xml unter neuem Namen
$xml.Save($OPN_Out)

FehlerMeldung:

Das Argument "0" mit dem Wert "System.Xml.XPathNodeList" für "RemoveChild" kann nicht in den Typ "System.Xml.XmlNode" konvertiert werden: "Der Wert
"System.Xml.XPathNodeList" vom Typ "System.Xml.XPathNodeList" kann nicht in den Typ "System.Xml.XmlNode" konvertiert werden."
In C:\Mailbox\01_Projekte\Roskow\Node_anfügen.ps1:47 Zeichen:1

back-to-top$DelNote.ParentNode.RemoveChild($DelNote) | Out-Null

back-to-top~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : NotSpecified: (face-smile , MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument

Wie kann ich die Fehlermeldung beheben bzw. den letzten Node Löschen bzw. die Newnode an einer bestimmten Position einfügen?

Content-ID: 1321169535

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

Ausgedruckt am: 19.11.2024 um 01:11 Uhr

149569
Lösung 149569 29.09.2021 aktualisiert um 10:11:49 Uhr
Goto Top
Dafür gibt's die
XmlNode.InsertAfter(XmlNode, XmlNode) Methode

$DelNote.ParentNode.RemoveChild($DelNote)
Tja, schau doch mal genau hin, in $DelNote (Lach face-big-smile, wieder so ein typischer Vertipper für die du hier bekannt bist) wählst du mit SelectNodes mehrere Knoten aus, aber die RemoveChild Methode kann wie der Name doch schon vermuten lässt immer nur einen einzelnen Knoten löschen, du übergibst aber eine Liste vom Typ System.Xml.XPathNodeList du mit SelectNodes ausgewählt hast. Willst du mehrere Knoten löschen itterierst du über die Liste der Knoten und löschst dann das Objekt in der Schleife.
$delnodes = $Xml.SelectNodes("/Document/SW.Blocks.FC/ObjectList/MultilingualText[@CompositionName='Title']")  
foreach($delnode in $delnodes){
    $delnode.ParentNode.RemoveChild($delnode)
}
SPSman
SPSman 29.09.2021 um 11:08:43 Uhr
Goto Top
Zitat von @149569:

Dafür gibt's die
XmlNode.InsertAfter(XmlNode, XmlNode) Methode

$DelNote.ParentNode.RemoveChild($DelNote)
Tja, schau doch mal genau hin, in $DelNote (Lach face-big-smile, wieder so ein typischer Vertipper für die du hier bekannt bist) wählst du mit SelectNodes mehrere Knoten aus, aber die RemoveChild Methode kann wie der Name doch schon vermuten lässt immer nur einen einzelnen Knoten löschen, du übergibst aber eine Liste vom Typ System.Xml.XPathNodeList du mit SelectNodes ausgewählt hast. Willst du mehrere Knoten löschen itterierst du über die Liste der Knoten und löschst dann das Objekt in der Schleife.
> $delnodes = $Xml.SelectNodes("/Document/SW.Blocks.FC/ObjectList/MultilingualText[@CompositionName='Title']")  
> foreach($delnode in $delnodes){
>     $delnode.ParentNode.RemoveChild($delnode)
> }
> 

Leider sehe weder einen Schreibfehler, noch wähle ich nach meinem Verständnis mehr als 1 Node aus:
append

Kannst du mir erklären wo mein Denkfehler ist?
149569
149569 29.09.2021 aktualisiert um 11:35:53 Uhr
Goto Top
Zitat von @SPSman:
Leider sehe weder einen Schreibfehler, noch wähle ich nach meinem Verständnis mehr als 1 Node aus:
append

Kannst du mir erklären wo mein Denkfehler ist?
Ja, dein Denkfehler liegt darin das egal ob es einer oder mehrere Knoten sind die zurückgegeben werden, die SelectNodes()-Methode immer ein Objekt vom Typ System.Xml.XPathNodeList ausgibt, aber RemoveChild ein Objekt vom Typ System.Xml.XmlNode erwartet, z.B. der von SelectSingleNode oder einen einzelnen Knoten einer SelectNodes Liste indem man diesen explizit mittels Index aus der Liste auswählt ....SelectNodes(".....") ! Steht doch schon in der Fehlermeldung wenn man sie denn mal lesen würde face-confused

Powershell arbeitet objektorientiert und dazu gehören explizit definierte Objektklassen die du einhalten musst und das tust du hier nun mal nicht!

Hier ist wohl mal dringend ein Grundkurs fällig, Powershell Leitfaden für Anfänger
SPSman
SPSman 30.09.2021 um 12:12:26 Uhr
Goto Top
Hi, ok habe ich verstanden.

Allerdings mache ich es jetzt einfach mit .InsertAfter. DA muss ich halt nur das Array von hinten durchlaufen und schick isses.

...

## CSV sortierung umdrehen
$CSV_reseve=$CSVData.Clone()
for ($i=1; $i -lt $CSVData.Length; $i++) {
$CSV_reseve[$i]= $CSVData[$CSVData.Length-$i]

}
...

# hänge den kopierten Knoten im selben Parent wie vom Original wieder ins XML ein
$Bsp_NW.ParentNode.InsertAfter($NEU_NW,$Bsp_NW)
149569
149569 30.09.2021 aktualisiert um 12:16:49 Uhr
Goto Top
Tipp: Es gibt auch InsertBefore

Dann auch bitte den Haken am Beitrag nicht vergessen.