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?
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>
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.
$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.
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)
精彩评论