How do I alter XML with PowerShell/XPath and save the document?
15,852
Solution 1
If you're using PowerShell 2.0 you can use the new Select-Xml cmdlet to select xml based on an XPath expression e.g.:
$xml = '<doc><books><book title="foo"/></books></doc>'
$xml | Select-Xml '//book'
Node Path Pattern
---- ---- -------
book InputStream //book
To remove nodes:
PS> $xml =[xml]'<doc><books><book title="foo"/><book title="bar"/></books></doc>'
PS> $xml | Select-Xml -XPath '//book' |
Foreach {$_.Node.ParentNode.RemoveChild($_.Node)}
title
-----
foo
bar
PS> $xml.OuterXml
<doc><books></books></doc>
Then to save to file:
$xml.Save("$pwd\foo.xml")
Get-Content foo.xml
<doc>
<books>
</books>
</doc>
Solution 2
Load Linq Xml assemblies:
[System.Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq")
[System.Reflection.Assembly]::LoadWithPartialName("System.Xml.XPath")
Load your xml (Note, you can use ::Load("file")
instead of ::Parse(...)
to load from file:
$xml = [System.Xml.Linq.XDocument]::Parse("<root> <row>Hey</row> <row>you</row> </root>")
Modify (in this case Remove the first row:
[System.Xml.XPath.Extensions]::XPathSelectElement($xml, "//row").Remove()
Save to file:
$xml.Save("MyXml.xml")
Using System.Xml (instead of System.Xml.Linq):
$doc = new-object "System.Xml.XmlDocument"
$doc.Load("MyXml_int.xml")
$node = $doc.SelectSingleNode("//row");
$node.ParentNode.RemoveChild($node)
$doc.Save("MyXml_out.xml")
Comments
-
Bruce227 about 2 years
I'm looking to use PowerShell to alter XML. I haven't been able to copy XML using XPath. I can load the XML, but I can't figure out how to list the XML with an XPath and create another XML file with what I retrieve.
$doc = new-object "System.Xml.XmlDocument" $doc.Load("XmlPath.xml")
Also, how would you add the removed XML to another XML file?
-
Bruce227 over 14 yearswell i'm doing this part of server loading applications and altering the config files for those applications. i don't want to have to load another assembly if possible. is there not a way to do this with the normal powershell? thanks
-
Nestor over 14 yearsBruce227, I've added the example using System.Xml.
-
Bruce227 over 14 yearswhen i just do the $xml | select-xml -xpath 'xpath' i don't get any output. what is being piped into the foreach. i'm not following what the select is doing. is there an easy way to replace values at a certain xpath location? thanks
-
Keith Hill over 14 yearsDo you happen to be using the PowerShell Community Extensions? If it is PSCX then I believe it is an XPathNavigator but if you're using the PowerShell 2.0 Select-Xml it is a custom object they create that has a Node property.
-
Bruce227 over 14 yearshi nestor, i tried your system.xml and it didn't work. is the "//row" the xpath value? if so i'm just getting a null when i am using the xpath i have generated. thanks
-
Nestor over 14 years"//row" works with the Xml "<root><row>Hey</row><row>you</row></root>". You need to change that to whatever xpath fits your xml. I tried my example in my machine and it worked.
-
Bruce227 over 14 yearsno, i'm not using the powershell community extensions. so are you saying that $xml | select-xml -xpath '//Configuration/ConfigXML/Configuration/DiscoveryHandlers' should work? well it doesn't for me. the xpath i'm putting doesn't seem to be working. any ideas? thanks for all the help.
-
Bruce227 over 14 yearshi nester, the xpath examples i have looked at don't seem to have the // just the / for root and then the path.
-
Admin over 14 yearsThe sample code that Keith has posted works for me, are you sure your XML and XPath are correct maybe use a tool such as pgfearo.googlepages.com/home to check your XPath against your XML.
-
Keith Hill over 14 yearsBruce, does your XML doc use XML namespaces? If so then the XPath query has to be tweaked and you have to provide namespace mappings to Select-Xml via the -Namespace parameter. If that is the case, I could provide you an example that uses an XML namespace.
-
Shashi Penumarthy about 12 years+1 Bruce. And I found this useful: huddledmasses.org/xpath-and-namespaces-in-powershell