使用PowerShell设置XML节点内的属性

3

我有一个包含以下节点的Xml文件:

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

首先,我需要获取featureName为DBServer的targetPaths的值。 然后,我想更改以下内容的值:

ItemTarget featureName="DBServer" targetPaths="$targetPath;"   

to

ItemTarget featureName="DBServer" targetPaths="$targetPath;$concate_TargetPath"

您的XML似乎无效:元素类型“VersionData”必须后跟属性规范、“>”或“/>”。 - Theo
1个回答

4

首先,您需要通过更改XML来修复它。

<VersionData Type="Upgrade" 
</VersionData>

为了

<VersionData Type="Upgrade" />

如果您有一个有效的xml文件,可以按照以下方法更新属性值:

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


更新:使用XPath查找要更新的节点


根据您的评论,我理解原始问题中并不明确的部分实际上更复杂。

如果您需要仅更改名为name且其值等于特定值的属性为ItemTarget节点中的targetPaths属性并且这些节点在DataFileItem节点内,那么如果新路径尚未存在,则需要通过添加新路径来更改targetPaths属性。到目前为止我说得对吗?

在这种情况下,请尝试以下内容:

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


更新:不区分大小写查找要更新的节点


由于上述代码使用区分大小写的XPath查找要更新的节点,因此无法处理任何需要以不区分大小写的方式比较namefeatureName的情况。

因此,这里提供一种新方法,可以使用不区分大小写的比较来获取要更新的项目:

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

我需要在xml中仅更改特定DBServer的属性,而不是所有DBServer。只有DataFileItem name="$name"和ItemTarget.featureName='DBServer'且$newPath不在ItemTarget.targetPaths中的那个。 - GBi
@user84129 啊哈,从最初的问题描述中并没有表达得很清楚。我已经为您更新了我的答案。 - Theo
谢谢。它就像魔法一样运作。现在我也更好地理解了这个概念。 - GBi
@user84129 很高兴听到我的代码对你有用。你可以考虑点击旁边的淡淡的勾号图标来接受这个答案。这样做可以帮助其他人更容易地找到答案,如果他们有类似的问题。 - Theo
@user84129,我已经更新了我的答案,还提供了一段代码,可以以不区分大小写的方式查找要更新的节点。干杯! - Theo
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接