0

To fetch the value of an XML element in powershell, we can simply write out the path by treating the elemnts as if they were properties of a PowerShell object; i.e. $xml.RootElement.ChildElement.GrandChild.

However, if the element we're interested in has an attribute associated, to get the text value we need to drill down to the text node; i.e. $xml.RootElement.ChildElement.GrandChild.'#text'.

Sadly when the element doesn't have an attribute, we can't use the text node; i.e. in that scenarion, $xml.RootElement.ChildElement.GrandChild.'#text' does not work.

Clear-Host
$example = [xml](@"
<demo>
    <element attribute='1'>10</element>
    <element>20</element>
</demo>
"@)

"just the element"
$example.demo.element 
"element's text"
$example.demo.element.'#text' 

I've written a nasty workaround for this, but suspect that's the wrong approach / that PowerShell has a more elegant way to resolve this issue.

My Nasty Workaround:

function Get-TextNode {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]
        $xmlElement
    )
    process {
        if($xmlElement.Attributes.Count -eq 0) {
            $xmlElement
        } else {
            $xmlElement.'#text'
        }
    }
}

$example.demo.element | Get-TextNode 
JohnLBevan
  • 22,735
  • 13
  • 96
  • 178
  • ps. I noticed that adding `$xmlElement.GetType()` to my command shows that the type of the element changes according to whether or not any attributes are present; i.e. if they are it's an `XmlElement`, if there aren't, it's a `String`.. – JohnLBevan Oct 03 '16 at 14:21

1 Answers1

1

The SelectNodes function works around this issue:

i.e.

$example.SelectNodes('/demo/element').'#text'

or

$example.SelectNodes('/demo/element/text()').Value

work as expected.

It's also possible to update nodes in this way:

Clear-Host

$example = [xml](@"
<demo>
    <x>5</x>
    <element attribute='1'>10</element>
    <element>20</element>
</demo>
"@)

$example.OuterXml
#Result: <demo><x>5</x><element attribute="1">10</element><element>20</element></demo>

$example.SelectNodes('/demo/element/text()') | %{ 
    $_.value = $_.ParentNode.ParentNode.SelectSingleNode('./x/text()').Value  
}

$example.OuterXml
#Result: <demo><x>5</x><element attribute="1">5</element><element>5</element></demo>
JohnLBevan
  • 22,735
  • 13
  • 96
  • 178