How to iterate the irregularly-named children of an Xml.XmlElement in Powershell?

11,608

Solution 1

First: You need to use Get-Member -Force ... which will show you everything. Note with particular interest the get_* methods which represent properties which for some reason aren't exposed as properties in PowerShell. So when you see get_ChildNodes in the member list, it means there's a .ChildNodes property on the object (even though PowerShell hides it for some reason).

Second: So therefore, there are lots of ways, including the get-member method you hinted at (I append the Format-Table because it makes it easier to tell that you got something):

  1. $xmlData.data.SelectNodes("*") | ft name, OuterXml
  2. $xmlData.data.ChildNodes | ft name, OuterXml
  3. $xmlData.data | gm -type Property | % { $xmlData.data.($_.Name) } |
    Where { $_ -is [Xml.XmlElement] } | ft Name, OuterXml

Solution 2

For some reason Get-Member doesn't display the other properties System.Xml.XmlElement provides. Here is the full member list: http://msdn.microsoft.com/en-us/library/system.xml.xmlelement_members.aspx

As you can see, there is a ChildNodes property, so you can do this:

(Select-Xml -Path "file.xml" -XPath "//xml/data").Node.ChildNodes | Where-Object { $_.Name -eq "foo" }

Share:
11,608
tenpn
Author by

tenpn

UK games programmer with C++, Lua, C#, Python and Powershell experience, specialising in AI.

Updated on August 03, 2022

Comments

  • tenpn
    tenpn over 1 year

    I have an XML file of the following format:

    <xml>
        <data>
            <foo float="99.0"/>
            <bar float="12.0"/>
            <tribble bool="true"/>
            ...
            <flibble int="1"/>
        </data>
    </xml>
    

    If I fetch that data in Powershell, I can see all the child elements of data with a Get-Memeber:

    > $xmlData = [xml](Get-Content myfile.xml)
    > $xmlData.data | Get-Member
        ...
        foo     Property    System.Xml.XmlElement ...
        bar     Property    System.Xml.XmlElement ...
        tribble Property    System.Xml.XmlElement ...
        ...
    

    And I can access each child element individually. But how would I iterate over all the children, processing them with pipes? I'd love to be able to write something like this:

    > $xmlData.data.Children | ?{$_ -eq "foo"}
    

    ...But alas that's just wishful thinking.

    EDIT: Ok so I can reflect on the properties like this:

    > $xmlData.data | get-member -memberType Property | ?{$_.Name -eq "foo"}
    

    But I can't then go from the property (above I'm operating on a MemberDefinition) to the actual child element. Or can I?

  • tenpn
    tenpn over 13 years
    Huh, interesting that get-member isn't always exhaustive. I'll check msdn next time. Thanks!
  • Keith Hill
    Keith Hill over 13 years
    I believe the reason get_ChildNodes isn't listed by default is that folks like me complained that the output of Get-Member was too damn noisy by default. Especially when it listed get_Prop, set_Prop and Prop. Not even Visual Studio Intellisense lists compiler generated methods. And you've found that you can force PowerShell to display those methods.
  • Sheep
    Sheep almost 5 years
    If you use the -View All parameter to Get-Member, it will show you all the properties, but it still won't show you the get_Prop methods. From reading the man page for Get-Member I guess properties like OuterXml are in the base .Net object, but not adapted for the PowerShell extended type system.