I have multiple XML files (with different file names) where I need to replace elements and text with new values, but only if they are contained in a specific root element. I'm rather new to replacing data in files with PowerShell and have searched for replacing one occurrence, but with no luck.
If root element is Source then replace element ABCD with element WXYZ and replace text 123456 with 987654 within the <RoutingID> line.
My issue is that the <RoutingID>123456</RoutingID> line occurs in other root elements and I don't want to replace the text 123456 in those other areas (data in root element Attending stays as is).
<Source>
<ABCD> ---> Replace <ABCD> with <WXYZ>
<RoutingID>123456</RoutingID> ---> Replace <RoutingID>123456</RoutingID> with <RoutingID>987654</RoutingID>
</ABCD> ---> Replace </ABCD> with </WXYZ>
</Source>
<Attending>
<JKLM>
<RoutingID>123456</RoutingID>
</JKLM>
</Attending>
I was using the following to change the elements, which works:
Get-ChildItem $fileList | ForEach {
(Get-Content $_ | ForEach { $_ -replace '<ABCD>', '<WXYZ>' }) |
Set-Content $_
}
Get-ChildItem $fileList | ForEach {
(Get-Content $_ | ForEach { $_ -replace '</ABCD>', '</WXYZ>' }) |
Set-Content $_
}
But when I use the same method for the RoutingID, it changes the RoutingID value in every occurrence, regardless of which root element the RoutingID appears.
Get-ChildItem $fileList | ForEach {
(Get-Content $_ | ForEach { $_ -replace '<RoutingID>123456</RoutingID>', '<RoutingID>987654</RoutingID>' }) |
Set-Content $_
}
Any assistance is greatly appreciated!
Don't edit structured texts like xml, csv, yml or json using simple text replacements. It may work for simple cases but will fail quickly for more complicated situations. PowerShell already has built-in support for those formats so just use the ConvertTo-*/ConvertFrom-* family or built-in types to deal with them, specifically ConvertTo-Xml and the [xml] type accelerator
$inputFile = "path\to\input.xml"
$outputFile = "path\to\output.xml" # Set to the same as input to overwrite
# Load the XML file and process
[xml]$xmlContent = Get-Content -Path $inputFile
if ($xmlContent.SelectSingleNode("//Source")) {
# Replace <ABCD> element with <WXYZ>
$abcdNode = $xmlContent.SelectSingleNode("//Source/ABCD")
if ($abcdNode) {
$wxyzNode = $xmlContent.CreateElement("WXYZ")
# Copy child nodes
foreach ($child in $abcdNode.ChildNodes) {
$newChild = $child.Clone()
if ($newChild.Name -eq "RoutingID" -and $newChild.InnerText -eq "123456") {
$newChild.InnerText = "987654"
}
$wxyzNode.AppendChild($newChild)
}
[void]$abcdNode.ParentNode.ReplaceChild($wxyzNode, $abcdNode)
}
# Also replace any other RoutingID=123456 under Source
$routingNodes = $xmlContent.SelectNodes("//Source//RoutingID[.='123456']")
foreach ($node in $routingNodes) {
$node.InnerText = "987654"
}
}
# Save the modified XML
$xmlContent.Save($outputFile)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With