maj
maj

Reputation: 29

How to remove nested in nested element from xml file

I need to Compare new names with name in XML file if name doesn't match then I would like to remove that actor from XML file, if the name doesn't existed then I would like to add it in.

$file = [xml]@'
<?xml version="1.0"?>
<data>
    <title>Name</title>
    <date>2019 Jan 01</date>
    <actor>
        <name>Actor Name 1</name>
        <type>Actor</type>
        <thumb>image.jpg</thumb>
    </actor>

    <actor>
        <name>Actor Name 2</name>
        <type>Actor</type>
        <thumb>image.jpg</thumb>
    </actor>

    <genre>genre1</genre>
    <genre>genre2</genre>
</data>
'@

I try below code but it doesn't work

    $file = New-Object System.Xml.XmlDocument
    $file.Load($file_path)
    $file_data=$file.DocumentElement
    
   $oldarray =  $file_data.actor
    $newarray=@(
        "Actor 3",
        "Actor Name 1"
        )
    
    Compare-Object -IncludeEqual -ReferenceObject $oldArray -DifferenceObject $newarray | Where-Object  {
        $w=$_.InputObject
        
        if($_.SideIndicator -eq "=>"){
            $a = $file_data.appendChild($file.CreateElement("actor"))
            $a.AppendChild($file.CreateElement("name")).InnerText=$w.Trim()
            $a.AppendChild($file.CreateElement("type")).InnerText="Actor"
        }
    
        if($_.SideIndicator -eq "<="){
            $file_data.SelectSingleNode("//actor[text()='$w']") | foreach {[void]$_.parentnode.removechild($_)}
    
       }
    }

Upvotes: 0

Views: 153

Answers (1)

Mathias R. Jessen
Mathias R. Jessen

Reputation: 174690

Start by removing <actor> nodes where the <name> is not in the list of new names:

$file = New-Object System.Xml.XmlDocument
$file.Load($file_path)
$file_data=$file.DocumentElement

$newNames = @(
  "Actor 3"
  "Actor Name 1"
)

# Use XPath to select all <name> nodes nested under an <actor> node
$existingNameNodes = $file.SelectNodes('//actor/name') 

# Filter against the list of new names
$removableNameNodes = $existingNameNodes |Where-Object InnerText -notin $newNames

$removableNameNodes |ForEach-Object {
    # Resolve parent <actor> node
    $actor = $_.ParentNode
    # Remove <actor> from its own parent
    $actor.ParentNode.RemoveChild($actor) |Out-Null
}

Now we just need to add the ones not already in the list:

$existingNameNodes = $file.SelectNodes('//actor/name') 

# Filter the new list against the existing names
$namesToAdd = $newNames |Where-Object { $_ -notin $existingNameNodes.InnerText }

foreach($name in $namesToAdd){
    # Create new <actor> and <name> nodes
    $newActorNode = $file.CreateElement('actor')
    $newActorName = $file.CreateElement('name')
    $newActorName.InnerText = $name

    # Nest new <name> under new <actor>, nest <actor> under <data> 
    $file.data.AppendChild(
        $newActor.AppendChild(
            $newActorName
        )
    ) |Out-Null
}

Upvotes: 1

Related Questions