Hello dear fellow Powershell users,
I'm trying to parse xml files, which can differ in structure. Therefore, I want to access the node values based on the node structure received from a variable.
Example
#XML file
$xml = [xml] @'
<node1>
<node2>
<node3>
<node4>test1</node4>
</node3>
</node2>
</node1>
'@
Accessing the values directly works.
#access XML node directly -works-
$xml.node1.node2.node3.node4 # working <OK>
Accessing the values via node information from variable does not work.
#access XML node via path from variable -does not work-
$testnodepath = 'node1.node2.node3.node4'
$xml.$testnodepath # NOT working
$xml.$($testnodepath) # NOT working
Is there a way to access the XML node values directly via receiving node information from a variable?
PS: I am aware, that there is a way via Selectnode, but I assume that is inefficient since it basically searching for keywords.
#Working - but inefficient
$testnodepath = 'node1/node2/node3/node4'
$xml.SelectNodes($testnodepath)
I need a very efficient way of parsing the XML file since I will need to parse huge XML files. Is there a way to directly access the node values in the form $xml.node1.node2.node3.node4 by receiving the node structure from a variable?
CodePudding user response:
You can split the string containing the property path into individual names and then dereference them 1 by 1:
# define path
$testnodepath = 'node1.node2.node3.node4'
# create a new variable, this will be our intermediary for keeping track of each node/level we've resolved so far
$target = $xml
# now we just loop through each node name in the path
foreach($nodeName in $testnodepath.Split('.')){
# keep advancing down through the path, 1 node name at a time
$target = $target.$nodeName
}
# this now resolves to the same value as `$xml.node1.node2.node3.node4`
$target
CodePudding user response:
You might use the ExecutionContext ExpandString
for this:
$ExecutionContext.InvokeCommand.ExpandString("`$(`$xml.$testnodepath)")
test1
If the node path ($testnodepath
) comes from a parameter argument, you might want to prevent any malicious code injections by striping of any character that is not a word character or a dot (.
):
$securenodepath = $testnodepath -Replace '[^\w\.]'
$ExecutionContext.InvokeCommand.ExpandString("`$(`$xml.$securenodepath)")