1

I'm trying to write some powershell that will update the value of a xml key value pair based on the value of another key value pair in the same node. Example xml:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <plugins>
  <plugin pluginType="plugin1" polling_internal="2" polling_unit="M" enabled="true">
      <params>
        <add key="Server" value="server1.local" />
        <add key="database" value="databasename1" />
      </params>
    </plugin>
  <plugin pluginType="plugin2" polling_internal="2" polling_unit="M" enabled="true">
      <params>
        <add key="Server" value="server2.local" />
        <add key="database" value="databasename2" />
      </params>
    </plugin>
 </plugins>
</configuration>

The real file has hundreds of plugins in it. I want to find all instances of databases called databasename1 - <add key="database" value="databasename1" and update the corresponding Server key with server name server2.local for example.

I know this can be done with select-xml and xpath, but its beyond me. Any assistance much appreciated.

ItsNotMyStrongPoint
  • 137
  • 1
  • 4
  • 10
  • possible duplicate of [Matching a node based on a sibling's value with XPath](http://stackoverflow.com/questions/912194/matching-a-node-based-on-a-siblings-value-with-xpath) – Ansgar Wiechers Aug 08 '14 at 14:53

2 Answers2

1

You can use this XPath to get all value attribute according to the criteria you explained (xpath formatted for readability) :

//plugin
    /params[add[@key='database' and @value='databasename1']]
        /add[@key='Server']
            /@value

The most complicated part (line 2 in above xpath) means search <params> node with criteria : has child node <add> having attribute key value equals "database" and attribute value value equals "databasename1". The rest is similar to what demonstrated in the other answer :

[XML]$xml = #load XML file
$xpath = "/configuration/plugins/plugin/params[add[@value='databasename1' and @key ='database']]/add[@key='Server']/@value"
$nodes = $xml.SelectNodes($xpath)

foreach ($n in $nodes) {
    $n.value = "server2.local"
}
#save XML back to file
har07
  • 88,338
  • 12
  • 84
  • 137
0

Something like this should do the trick:

[Xml]$oXml = Get-Content oldfile.xml

$sXPath = "/configuration/plugins/plugin/params/add[@value='databasename1']"
$cChildren = $oXml.SelectNodes($sXPath)

foreach ($oChild in $cChildren) {
    $oParent = $oChild.get_ParentNode()
    $oServer = $oParent.ChildNodes | Where-Object { $_.key -eq "Server" }
    $oServer.value = "server2.local"
}

$oXml.OuterXml | Out-File newfile.xml

Should be doable with less code if you use a more complex XPath.

Alexander Obersht
  • 3,215
  • 2
  • 22
  • 26