Search code examples
xmlpowershellxpathxmldocumentxmlnode

Powershell: select XML node value into variable by element index


I have this PowerShell script which I use to parse through different aspects of an XML-file. Therefore, I Would like to retrieve the value of a specific XML-node and save it into a variable. This node I would like to select, exists multiple times in the XML-file, so I need to be able to mention the specific number of the node I want to retrieve.

XML-file:

<lvl1>
    <lvl2>
        <lvl3>
            <lvl4>test1</lvl4>
            <lvl4>test2</lvl4>
            <lvl4>test3</lvl4>
        </lvl3>
    </lvl2>
</lvl1>

Powershell scripts I've tried:

1 returning nothing and no errors

[xml] $response = get-content "FilePath\Resp.xml"
[string] $Var = $response.SelectSingleNode('lvl1/lvl2/lvl3/lvl4[2]').InnerText

2 returning error: "cannot index into a null array."

[xml] $response = get-content "FilePath\Resp.xml"
$Var = $response.lvl1.lvl2.lvl3.lvl4[2].'#text'

Solution

  • BACON essentially provided the crucial pointers in comments on the question:

    Using PowerShell's dot notation directly returns the text content of leaf elements (elements with only a text child node), so there's no need for '.#text':

    # Note: `.lvl4` is an *array* provided by PowerShell, so the index is 
    #       0-based. Therefore, [2] retrieves the *3rd* element.
    $response.lvl1.lvl2.lvl3.lvl4[2]  # -> 'test3'
    

    Note that PowerShell exposes the multiple lvl4 elements as an array, so indexing into that array is 0-based.


    Your XPath-based command should work as-is, but note that indices in XPath are 1-based, so [2] would refer to the 2nd element:

    $response.SelectSingleNode('lvl1/lvl2/lvl3/lvl4[2]').InnerText # -> 'test2'
    
    # Equivalent commands:
    $response.SelectSingleNode('lvl1/lvl2/lvl3/lvl4[2]').'#text'
    $response.SelectSingleNode('lvl1/lvl2/lvl3/lvl4[2]/text()').Value