Home > Software design >  Parsing an XML file with PowerShell with node from variable
Parsing an XML file with PowerShell with node from variable

Time:02-24

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)")
  • Related