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")
Share:
15,852
Bruce227
Author by

Bruce227

Just looking.

Updated on June 17, 2022

Comments

  • Bruce227
    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
    Bruce227 over 14 years
    well 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
    Nestor over 14 years
    Bruce227, I've added the example using System.Xml.
  • Bruce227
    Bruce227 over 14 years
    when 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
    Keith Hill over 14 years
    Do 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
    Bruce227 over 14 years
    hi 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
    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
    Bruce227 over 14 years
    no, 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
    Bruce227 over 14 years
    hi nester, the xpath examples i have looked at don't seem to have the // just the / for root and then the path.
  • Admin
    Admin over 14 years
    The 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
    Keith Hill over 14 years
    Bruce, 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
    Shashi Penumarthy about 12 years
    +1 Bruce. And I found this useful: huddledmasses.org/xpath-and-namespaces-in-powershell