0

I am looking for a way to iterate through an XML API-based response and display the entire XML tree in the following format:

node\node = VALUE
node\node\node = VALUE
node\node\node2 = VALUE

I have a script that works for some XML output but fails on others:

    function Get-XMLTree($xml) {
        $nodesWithText = $xml.SelectNodes("//*[text()]")
    
        foreach($node in $nodesWithText) {
            #Start with end of path (element-name of the node with text-value)
            $path = $node.LocalName
            
            #Get parentnode
            $parentnode = $node.ParentNode
    
            #Loop until document-node (parent of root-node)
            while($parentnode.LocalName -ne '#document') {
    
                #If sibling with same LocalName (element-name) exists
                if(@($parentnode.ParentNode.ChildNodes | Where-Object { $_.LocalName -eq $parentnode.LocalName }).Count -gt 1){
                    #Add text-value to path
                    $path = "{0}\$path" -f ($parentnode.'#text').Trim()
                }
    
                #Add LocalName (element-name) for parent to path
                $path = "$($parentnode.LocalName)\$path"
    
                #Go to next parent node
                $parentnode = $parentnode.ParentNode
            }
    
            #Output "path = text-value"
            "$path = $(($node.'#text').Trim())"
        }
    }

For some XML responses, this works without a hitch. For others, I receive errors similar to the below:

InvalidOperation: /script1.ps1:51:17
Line |
  51 |                  $path = "{0}\$path" -f ($parentnode.'#text').Trim()
     | You cannot call a method on a null-valued expression.

Any help is appreciated

Metshrine
  • 11
  • 3

2 Answers2

1

Fixed it! Here is the final function


function Get-XMLTree($xml) {
    $nodesWithText = $xml.SelectNodes("//*[text()]")
    foreach($node in $nodesWithText)
    {    
        #Start with end of path (element-name of the node with text-value)
        $path = $node.LocalName

        #Get parentnode
        $parentnode = $node.ParentNode

        #Loop until document-node (parent of root-node)
        while($parentnode.LocalName -ne '#document')
        {
            #If sibling with same LocalName (element-name) exists
            if(@($parentnode.ParentNode.ChildNodes | Where-Object { $_.LocalName -eq $parentnode.LocalName }).Count -gt 1)
            {
                #Add text-value to path
                if($parentnode.'#text')
                {
                    $path = "{0}\$path" -f ($parentnode.'#text').Trim()
                }
            }

            #Add LocalName (element-name) for parent to path
            $path = "$($parentnode.LocalName)\$path"

            #Go to next parent node
            $parentnode = $parentnode.ParentNode
        }

        #Output "path = text-value"
        "$path = $(($node.'#text').Trim())"
    }
}
Metshrine
  • 11
  • 3
0

XSLT seems like the tool for this job to extract information from an xml format.

This answer gives the gist of how to apply xslt in powershell. Or, using one of many other XSLT tools ....

As @mclayton asked - if you can provide the original xml, someone might be able to give you a quick xslt to extract the information you are looking for.

dajo
  • 909
  • 10
  • 16