3

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"
1
  • Your XML seems invalid: Element type VersionData must be followed by either attribute specifications, > or />. Commented Dec 16, 2018 at 12:15

1 Answer 1

4

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')


UPDATE: Finding nodes to update using XPath


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')


UPDATE: Finding nodes to update Case Insensitively


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')
Sign up to request clarification or add additional context in comments.

7 Comments

I need to change the attribute for a specific DBserver and not for All DBServer over the xml. only the one that DataFileItem name="$name" and ItemTarget. featureName='DBServer' and $newPath -notin ItemTarget.targetPaths
@user84129 Aha, this all was not clear from reading the original question. I have updated my answer for you.
Thanks. It Works like a Magic. Now I also understand better the concept.
@user84129 Glad to hear my code works for you. You might consider accepting the answer by clicking the faint checkmark icon next to it. By doing so, this helps others to find the answer easier if they have a similar question.
@user84129 Ah, sorry, didn't realize that.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.