views:

858

answers:

2

Hi,

I'm looking to use powershell to alter xml. I haven't been able with powershell to copy xml using the xpath. I can load the xml with the following:

$doc = new-object "System.Xml.XmlDocument"
$doc.Load("XmlPath.xml")

but after I get the XML I can't figure out how to list the xml with an xpath and create another xml file with what I retrieve. Also how would you add the removed xml to another xml file?

I haven't used Powershell much so just a beginner. So any help would be great.

Thanks

+1  A: 

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")
Nestor
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
Bruce227
Bruce227, I've added the example using System.Xml.
Nestor
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
Bruce227
"//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.
Nestor
hi nester, the xpath examples i have looked at don't seem to have the // just the / for root and then the path.
Bruce227
you need to learn xpath: http://msdn.microsoft.com/en-us/library/ms256122.aspx
Nestor
+2  A: 

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>
Keith Hill
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
Bruce227
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.
Keith Hill
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
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 http://pgfearo.googlepages.com/home to check your XPath against your XML.
Alan
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.
Keith Hill