Reputation: 31
I have an Xml File which include nodes that looks like:
<Installation>
<VersionData Type="Upgrade"
</VersionData>
<DeploymentData>
<DataFileGroup enable="True">
<DataFileItem name="file2.exe.config" enable="True" installMode="Both" sourceFolder="C:\files\" distributionType="AddReplace" >
<ItemTarget featureName="AppServer" targetPaths="$targetPath/folder3;"/>
<ItemTarget featureName="WebServer" targetPaths="$targetPath/folder1;"/>
<ItemTarget featureName="DBServer" targetPaths="$targetPath;"/>
</DataFileItem>
</DataFileGroup>
</DeploymentData>
</Installation>
$xmlFile = "C:\work\myXML.xml"
$xml = [xml](Get-Content $xmlFile)
$xml.Load($xmlFile)
First I need to to get the value of targetPaths where featureName is DBServer
.
Then I want to change the value of:
ItemTarget featureName="DBServer" targetPaths="$targetPath;"
to
ItemTarget featureName="DBServer" targetPaths="$targetPath;$concate_TargetPath"
Upvotes: 3
Views: 5331
Reputation: 61068
First, you will need to fix your XML by changing
<VersionData Type="Upgrade"
</VersionData>
to
<VersionData Type="Upgrade" />
Once you have a valid xml file, you can do this to update the attribute values:
$xmlFile = "C:\work\myXML.xml"
[xml]$xml = Get-Content $xmlFile -Raw
# find all nodes 'ItemTarget' with featureName 'DBServer'
$nodes = $xml.SelectNodes("//ItemTarget[@featureName='DBServer']")
foreach ($node in $nodes) {
# change the value of the 'targetPaths' attribute
# because of the dollar signs, use single quotes here if this should be the literal value.
# if you mean to have these values expanded from variables with these names, use double quotes
$node.targetPaths = '$targetPath;$concate_TargetPath'
}
# save the changes to a new xml file
$xml.Save('C:\work\myXML_Updated.xml')
From your comment, I understand there is more to it than was clear in the original question.
If you need to only change the targetPaths
attribute for ItemTarget
nodes that are in node DataFileItem
which has an attribute called name
and the value thereof is equal to a specific value, THEN the targetPaths
attribute needs to be changed by adding a new path to it IF this new path is not already present.
(Am I correct so far?)
In that case, try this:
# this is the name attribute to search for the DataFileItem node
$dataFileName = "file2.exe.config"
# this is the path to add to the 'targetPaths' attribute if not already present
$newPath = "SomeNewPathToAppend"
$xmlFile = 'C:\work\myXML.xml'
[xml]$xml = Get-Content $xmlFile -Raw
# find all nodes 'ItemTarget' with featureName 'DBServer' within the 'DataFileItem' node that has attribute $dataFileName
$nodes = $xml.SelectNodes("//DataFileItem[@name='$dataFileName']/ItemTarget[@featureName='DBServer']")
foreach ($node in $nodes) {
# split the current value by the semicolon and remove empty elements
$paths = $node.targetPaths.Split(";", [System.StringSplitOptions]::RemoveEmptyEntries)
# check if the $newPath is not already in this array
if ($paths -notcontains $newPath) {
# change the value of the 'targetPaths' attribute by adding the $newPath to it
$paths += $newPath
$node.targetPaths = "{0};" -f ($paths -join ';')
}
}
# save the changes to a new xml file
$xml.Save('C:\work\myXML_Updated.xml')
Because the above code uses Case Sensitive XPath to find the nodes you want to update, it cannot handle cases where any of the name
or featureName
should be compared in a case insensitive manner.
So here's a new approach that will get you the items to update using case insensitive comparison:
# this is the name attribute to search for the DataFileItem node
$dataFileName = "file2.exe.config"
# this is the path to add to the 'targetPaths' attribute if not already present
$newPath = "SomeNewPathToAppend"
$xmlFile = 'C:\work\myXML.xml'
[xml]$xml = Get-Content $xmlFile -Raw
# find all 'DataFileItem' nodes that have attribute 'name' equal to $dataFileName (case insensitive)
$nodes = $xml.GetElementsByTagName("DataFileItem") | Where-Object { $_.name -eq $dataFileName }
# or do it like this:
# $nodes = $xml.ChildNodes.DeploymentData.DataFileGroup.DataFileItem | Where-Object { $_.name -eq $dataFileName }
# within these 'DataFileItem' nodes, find all 'ItemTarget' elements where attribute 'featureName' equals "DBServer" (case insensitive)
$nodes.ItemTarget | Where-Object { $_.featureName -eq "DBServer" } | ForEach-Object {
# split the current value by the semicolon and remove empty elements
$paths = $_.targetPaths.Split(";", [System.StringSplitOptions]::RemoveEmptyEntries)
# check if the $newPath is not already in this array
if ($paths -notcontains $newPath) {
# change the value of the 'targetPaths' attribute by adding the $newPath to it
$paths += $newPath
$_.targetPaths = "{0};" -f ($paths -join ';')
}
}
# save the changes to a new xml file
$xml.Save('C:\work\myXML_Updated.xml')
Upvotes: 4