I am writing a fairly substantial Posh module to be a CLI front-end to a set of RESTful Web Services. I have an odd problem I have been able to characterize, but not finding a clean solution to.
I do not always know what attributes to expect, and some nodes may have a certain attribute, other nodes may not have that attribute. My problem is sometimes (read: often) if an attribute is not present in all nodes, it will not be passed down the pipeline for any node. It appears to be related to what attributes are in the first node in the XML.
For a very simple example, consider this is the contents of an XML file example.xml:
<members>
<member>
<name>Joe</name>
<rank>Grand Poobah</rank>
<serialnumber>1234</serialnumber>
</member>
<member>
<name>Fred</name>
<serialnumber>1234</serialnumber>
</member>
</members>
I import it and assign it to an XML cast variable:
[xml]$stuff = Get-Content .\example.xml
Then I pipe it to format-table (or out-gridview, export-csv, etc.)
$stuff.members.member | ft -AutoSize
name rank serialnumber
---- ---- ------------
Joe Grand Poobah 1234
Fred 1234
Works great.
Now, if the FIRST node does not have the rank attribute:
<members>
<member>
<name>Fred</name>
<serialnumber>1234</serialnumber>
</member>
<member>
<name>Joe</name>
<rank>Grand Poobah</rank>
<serialnumber>1234</serialnumber>
</member>
</members>
Now, when I do the same import and pass it out the pipe, the "rank" attribute is not passed down the pipeline.
$stuff.members.member | ft -AutoSize
name serialnumber
---- ------------
Fred 1234
Joe 1234
I can force it by explicitly naming the attributes:
$stuff.members.member | select-object -Property name, rank, serialnumber | ft
name rank serialnumber
---- ---- ------------
Fred 1234
Joe Grand Poobah 1234
Explicitly naming the attributes is a recipe for bugs, as attributes can be added without warning. I want to keep the code flexible to deal with new attributes if possible.
I thought I could use "select-object -property *" but that adds a lot of PowerShell inserted XML stuff I do not want, and still does not pipe the rank attribute.
$stuff.members.member | select-object -Property *| ft -AutoSize
name serialnumber LocalName NamespaceURI Prefix NodeType ParentNode OwnerDocument IsEmpty Attributes
---- ------------ --------- ------------ ------ -------- ---------- ------------- ------- ----------
Fred 1234 member Element members #document False {}
Joe 1234 member Element members #document False {}
Anyone familiar with any good ways to deal with this situation? I have not found any good clues on a Google search.
The XML element definitely is "passed down the pipe". What you are looking at is a peculiarity of format-table
: It only looks at the first object in a list to figure out which columns to print.
This mainly is for performance reasons. Otherwise format-table
would have to iterate the list twice - once to figure out which properties to output, and a second time to actually output them. Plus, more often than not, items in a list are uniform.
In all other cases, the rule "explicit is better than implicit" applies:
$stuff.members.member | ft name, rank, serialnumber -AutoSize
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With