7

I'm trying to rename an XML node using PowerShell. For example:

<configuration>
<desktops>
   <name>PC001</name>
   <domain>CORP</domain>
</desktops>
<laptops>
   <name>PC002</name>
   <domain>CORP</domain>
</laptops>
</configuration>

I want to rename the first <name> tags to <PC1name> (and </PC1name> respectively). Here's what I have, so far:

$InputFile = "NetworkConfigs.xml"
$xml = [xml](get-content $InputFile)
$root = $xml.get_DocumentElement();
#replace the node
$root.desktops.name.?
  
$xml.Save($InputFile)

I don't know how to replace the <name> tag with something else. Tips?

4 Answers 4

8

Bottom line, an XML node's name is immutable. Reference msdn.

Here's a quick example of creating a new node with the required data. Hope it helps.

$InputText = @"
<configuration>
<desktops>
<name>PC001</name>
<domain>CORP</domain>
</desktops>
<laptops>
<name>PC002</name>
<domain>CORP</domain>
</laptops>
</configuration>
"@

$xml = [xml]($inputText)
$desktopsNode = [System.Xml.XmlElement]$xml.configuration.desktops
$nameNode = $desktopsNode.SelectSingleNode('name')
$pcNameNode = $xml.CreateElement('PC1Name')
$pcNameNode.InnerText = $nameNode.InnerText
[void]$desktopsNode.AppendChild($pcNameNode)
[void]$desktopsNode.RemoveChild($nameNode)
$xml.OuterXML

Output:

<configuration><desktops><domain>CORP</domain><PC1Name>PC001</PC1Name></desktops><laptops><name>PC002</n
ame><domain>CORP</domain></laptops></configuration>
Sign up to request clarification or add additional context in comments.

2 Comments

This works mostly, I need to use a file as the input and output. So, I've replaced the $InputText with $InputFile and applied the changes which show up using $xml.OuterXML However, how can I save the XML file? I tried $xml.Save($InputFile) but that doesn't work.
The error should tell you what's wrong on the save. Is the file locked? Or does the $xml object not have a Save method? (If that's the case, you'll need to get a handle on a System.Xml.XmlDocument.) The key point is to observe the error message carefully and look at the appropriate object documentation.
4

Renaming nodes in XML is more complicated than you might expect. It's especially bad if the node is a root node, or parent with a complex hierarchy of child nodes. Most "rename" methods I've seen will clone the children and append them to the new node. This process is made a little easier if your API also includes a ReplaceChild method. (I can provide details if you need them.)

An alternative method that I have used (especially if the XML can be represented as a string) is to replace the text in the XML before converting it to XmlDocument.

$InputText = @"
<configuration>
<desktops>
<name>PC001</name>
<domain>CORP</domain>
</desktops>
<laptops>
<name>PC002</name>
<domain>CORP</domain>
</laptops>
</configuration>
"@

$regex = [regex]'(</?)name>'
$ModifiedText = $regex.Replace($InputText,"`$1PC1Name>",2)
$xml = [xml]$ModifiedText

Note that the replace statement finds and fixes the first 2 occurrences of the match--the opening and closing tag of the first element only. Remove the number to find and replace all occurrences in the string. Note also that the regular expression captures the opening tag characters, so that they can be inserted into the string match as $1.

Comments

2
$oldtag = "name"
$newtag = "PC1name"
$xml = Get-Content D:\oldfile.xml
$new = $xml -replace $oldtag, $newtag
Set-content -path D:\newfile.xml -value $new

My way is I convert the XML to a string, then replace the node (which in this case is just normal string). It works for me.

1 Comment

Very bad solution... if your string happens to appear somewhere else, you're making a bi gmistake
0

Inspired by a simple C# solution I ended up with this function (which also takes care of attributes):

Function RenameXmlNode ($oldNode, $newName) {
    $newNode = $oldNode.OwnerDocument.CreateElement($newName)

    foreach ($childNode in $oldNode.ChildNodes) {
        $newNode.AppendChild($childNode.CloneNode($true))
    }

    foreach ($attribute in $oldNode.Attributes) {
        $newNode.Attributes.Append($attribute)
    }

    $parent = $oldNode.ParentNode
    $parent.ReplaceChild($newNode, $oldNode)
    return $newNode
}

If the result is not needed, it can be ignored - the renamed node is already part of the document, the $oldNode belonged to.

Example:

$InputFile = "NetworkConfigs.xml"
[xml] $doc = Get-Content $InputFile
$nameNode = $doc.SelectSingleNode('/configuration/desktops/name')

RenameXmlNode $nameNode $nameNode.InnerText  

$xml.Save($InputFile)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.