My XML has elements like:
<?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>
I need to append 3 new ToolSets to the tree.
I can't figure out how to select the element Record Key = "ToolSetManager" to so I can append data to that particular element.
My code:
$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")
}
}
To select the node having Key
equal to ToolSetManager
you can use SelectSingleNode
with the following XPath:
$node = $xml.SelectSingleNode("//Record[@Key='ToolSetManager']")
Then $node
should look like:
Key ToolSet
--- -------
ToolSetManager {ToolSet, ToolSet}
Then if you wanted to add a new <ToolSet>
to <Record Key="ToolSetManager">
, the code is a bit more annoying, what you currently have will not generate the same <ToolSet>
nodes as the ones your XML has, you'd get something like this using your current approach:
<ToolSet Path="Null.btx" Title="Null" />
When what you want is most likely:
<ToolSet>
<Path>Null.btx</Path>
<Title>Null</Title>
</ToolSet>
The easiest way could be by cloning one of those elements and then updating its values, i.e.:
$clone = $node.ToolSet[0].Clone()
$clone.Path = 'Null.btx'
$clone.Title = 'Null'
$null = $node.AppendChild($clone)
Another way, much more manual can be:
# Create <ToolSet>
$toolset = $xml.CreateElement('ToolSet')
# Create <Path>
$path = $xml.CreateElement('Path')
# Add Null.txt to <Path>
$null = $path.AppendChild($xml.CreateTextNode('Null.btx'))
# Add <Path> to <ToolSet>
$null = $toolset.AppendChild($path)
# Create <Title>
$title = $xml.CreateElement('Title')
# Add Null to <Title>
$null = $title.AppendChild($xml.CreateTextNode('Null'))
# Add <Title> to <ToolSet>
$null = $toolset.AppendChild($title)
# Add <ToolSet> to <Record Key="ToolSetManager">
$null = $node.AppendChild($toolset)
Then if you save the updated $xml
(there you can use $xml.Save('path\to\xml')
) it should look like:
<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>
<ToolSet>
<Path>Null.btx</Path>
<Title>Null</Title>
</ToolSet>
</Record>