Home > Mobile >  Powershell XML .GetAttribute() & filter $nulls
Powershell XML .GetAttribute() & filter $nulls

Time:08-13

Given xml with a series of <Set> elements that should all have an id attribute, I need to validate that, and then process only those elements that do have an id. I had thought that

$elementIDs = $elements.GetAttribute('id')

would only return actual values, as in an element that either did not have the attribute or the attribute was blank would not be included in the array. Not so, I can get blank values back. Later, when I iterate through that list I can test for a blank id

foreach ($id in $elementIDs) {
    if ($id) {

But I would rather just have a clean list. I thought perhaps I could method chain, like so

$elementIDs = $elements.HasAttribute('id').GetAttribute('id')

but method chaining isn't an option here. So I thought .Where() might work. Either

$elementIDs = $elements.GetAttribute('id').Where({$_ -ne $Null})

or

$elementIDs = $elements.GetAttribute('id').Where({$args -ne $Null})

or even

$elementIDs = $elements.GetAttribute('id').Where({param ($id) $id -ne $Null})

But none seems to work. So, is there a simple, elegant way to do this, or am I stuck with $Nulls in my array and a conditional?

CodePudding user response:

Try something like this on your actual xml and see if it works:

$elements = $xml.SelectNodes('//Set[@id]');
$elementIDs = $elements.GetAttribute('id')
echo $elementIDs

CodePudding user response:

To offer PowerShell-native alternatives to Jack Fleeting's helpful XPath-based answer:

Note that the .GetAttribute() method returns an empty string, not $null, if a given XML element doesn't have an attribute with the given name.

The ability of PowerShell's comparison operators to operate on arrays, in which case they act as filters, makes removing the empty-string return values easy:

@($elements.GetAttribute('id')) -ne ''

Assuming that none of your <Set> elements (also) have <id> child elements, an even simpler solution that uses PowerShell's adaptation of the XML DOM is possible:

$elements.id

Note:

  • Both attributes and child elements are surfaced as if they were regular properties.

  • Unlike when using member-access enumeration with true, type-native properties, where a $null is emitted for each object that doesn't have the specified property, with the XML adaptation nothing is emitted, which - conveniently - returns only actual id attributes / elements.

  • Related