如何使用PowerShell定位XML元素并添加带属性的子元素
解决PowerShell定位XML元素并追加子元素的问题
需要给XML中Key属性为ToolSetManager的<Record>元素追加3个带<Path>和<Title>子节点的<ToolSet>节点。以下是正确实现方案:
原XML结构
<?xml version="1.0" encoding="utf-8"?> <UserPreferences Version="3"> <Record Key="ProfileManager"> <Path>C:\Users\bob\AppData\Roaming\Software\21\</Path> </Record> <Record Key="Measurement Creation Context"> <SnapOrthogonal>False</SnapOrthogonal> <SnapContent>True</SnapContent> </Record> <Record Key="WebFavoritesList" /> <Record Key="DefaultsManager" /> <Record Key="ToolSetManager"> <ToolSet> <Path>Tool Set 1.btx</Path> <Title>Tool Set 1</Title> </ToolSet> <ToolSet> <Path>My Tool Set.btx</Path> <Title>My Tool Set</Title> </ToolSet> </Record> <Record Key="RecentFileList" /> <Record Key="TemplateData" /> . </Record> </UserPreferences>
用户原错误代码
$xml = [xml](Get-Content "$env:appdata\software\21\UserPreferences.xml") #Loop to find the Element with the Key "ToolSetManager" #Hopefully there is a simpler/direct way to get here? $allRecordKeys = $xml.UserPreferences.Record.key foreach ($Key in $allRecordKeys) { if ($Key -eq "ToolSetManager") { $newElement1 = $xml.CreateElement("ToolSet") $newElement1.SetAttribute("Path", "Null.btx") $newElement1.SetAttribute("Title", "Null") # This is where I can't figure out what should go before the .appendChild...: $xml.RevuUserPreferences.Record.ToolSetManager.AppendChild($newElement1) $xml.save("$env:appdata\software\21\UserPreferences.xml") } }
正确实现步骤
1. 快速定位目标节点
不用循环遍历,直接用两种方式快速定位Key="ToolSetManager"的<Record>节点:
# 方式1:XPath直接查询(最快捷) $targetRecord = $xml.SelectSingleNode("//Record[@Key='ToolSetManager']") # 方式2:PowerShell属性筛选 $targetRecord = $xml.UserPreferences.Record | Where-Object { $_.Key -eq "ToolSetManager" }
2. 批量创建并追加子元素
注意:原XML中<Path>和<Title>是<ToolSet>的子节点,不是属性,需修正创建逻辑:
# 定义要添加的3组ToolSet数据 $newToolSets = @( @{ Path = "New Tool Set 1.btx"; Title = "New Tool Set 1" }, @{ Path = "New Tool Set 2.btx"; Title = "New Tool Set 2" }, @{ Path = "New Tool Set 3.btx"; Title = "New Tool Set 3" } ) foreach ($ts in $newToolSets) { # 创建ToolSet父节点 $toolSetNode = $xml.CreateElement("ToolSet") # 创建Path子节点并赋值 $pathNode = $xml.CreateElement("Path") $pathNode.InnerText = $ts.Path $toolSetNode.AppendChild($pathNode) | Out-Null # 创建Title子节点并赋值 $titleNode = $xml.CreateElement("Title") $titleNode.InnerText = $ts.Title $toolSetNode.AppendChild($titleNode) | Out-Null # 将ToolSet节点追加到目标Record下 $targetRecord.AppendChild($toolSetNode) | Out-Null }
3. 保存修改后的XML
$xml.Save("$env:appdata\software\21\UserPreferences.xml")
完整正确代码
# 加载XML文件 $xmlPath = "$env:appdata\software\21\UserPreferences.xml" $xml = [xml](Get-Content $xmlPath) # 定位目标Record节点 $targetRecord = $xml.SelectSingleNode("//Record[@Key='ToolSetManager']") # 定义要添加的3组ToolSet数据 $newToolSets = @( @{ Path = "New Tool Set 1.btx"; Title = "New Tool Set 1" }, @{ Path = "New Tool Set 2.btx"; Title = "New Tool Set 2" }, @{ Path = "New Tool Set 3.btx"; Title = "New Tool Set 3" } ) # 批量创建并追加子元素 foreach ($ts in $newToolSets) { $toolSetNode = $xml.CreateElement("ToolSet") $pathNode = $xml.CreateElement("Path") $pathNode.InnerText = $ts.Path $toolSetNode.AppendChild($pathNode) | Out-Null $titleNode = $xml.CreateElement("Title") $titleNode.InnerText = $ts.Title $toolSetNode.AppendChild($titleNode) | Out-Null $targetRecord.AppendChild($toolSetNode) | Out-Null } # 保存修改 $xml.Save($xmlPath)
关键修正说明
- 原代码错误将
<Path>和<Title>当成属性处理,实际是子节点,需用CreateElement创建并设置InnerText。 - 用XPath或
Where-Object直接筛选目标节点,避免无效遍历,逻辑更简洁可靠。 - 修正了原代码中错误的节点引用
$xml.RevuUserPreferences,对应XML根节点UserPreferences。
内容的提问来源于stack exchange,提问作者ITSteve
相关产品推荐
相关产品推荐

