How to parse a nested XML using PowerShell

39 views Asked by At

I'm going to parse a nested xml file using PowerShell. Is there a way to traverse its childnodes and the nodes of its child one by one?

For example:

<?xml version="1.0"?>
<root xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
  <Node1 name="A"/>
  <Node2 name="B"/>
  <Node3>
    <Element1 id="1" type="Element">
      <State value = "live" /State>
      <Child1 name="dogName">
        <SubChild1 id="11111">
        </SubChild1>
      </Child1>
      <Child2>
        <SubChild2 name="color" value="red" />
        <SubChild2 name="skin" value="none" />
        <SubChild2 name="other" value="lost" />
      </Child2>
      <Child3>
        <SubChild3>FlagMark=GO</SubChild3>
        <SubChild3>Dog</SubChild3>
      </Child3>
    </Element1>
    <Element2 id="2" type="Element">
      <State value = "live">
      <Child1 name="catName">
        <SubChild1 id="22222">
        </SubChild1>
      </Child1>
      <Child2>
        <SubChild2 name="color" value="brown" />
        <SubChild2 name="skin" value="thick" />
        <SubChild2 name="other" value="unknown" />
      </Child2>
      <Child3>
        <SubChild3>FlagMark=Run</SubChild3>
        <SubChild3>Cat</SubChild3>
      </Child3>
    </Element2>
    <Element3>
      ...
    </Element3>
  </Node3>
</root>

How can I get each child node of by its name and value? How can I get child nodes of one by one and print?

1

There are 1 answers

0
Ian Boyd On

Here's how you can parse XML inside PowerShell; one special trick is the use of the [xml] type accelerator

  1. Create a variable to hold the XML string:

    # Declare our XML string
    $xmlContent = @"
    <?xml version="1.0"?>
    <root xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
      <Node1 name="A"/>
      <Node2 name="B"/>
      <Node3>
        <Element1 id="1" type="Element">
          <State value = "live"/>
          <Child1 name="dogName">
            <SubChild1 id="11111"/>
          </Child1>
          <Child2>
            <SubChild2 name="color" value="red"/>
            <SubChild2 name="skin" value="none"/>
            <SubChild2 name="other" value="lost"/>
          </Child2>
          <Child3>
            <SubChild3>FlagMark=GO</SubChild3>
            <SubChild3>Dog</SubChild3>
          </Child3>
        </Element1>
        <!-- ...snip... -->
      </Node3>
    </root>
    "@
    
  2. Use the [xml] type accelerator to parse the string into XML:

    # Convert the string to XML with the [xml] type accelerator
    $xml = [xml]$xmlContent
    
  3. Use .selectNodes to get a child, e.g. Child2:

    # Get all Child2 nodes
    $child2Nodes = $xml.SelectNodes("//Child2")
    
  4. Iterate over each <Child2> node, and each of its <SubChild> nodes

    # Get a child
    foreach ($child2 in $child2Nodes) {
       # Iterate over each subchild
       foreach ($subChild2 in $child2.ChildNodes) {
          # Print their names and values
          Write-Host "SubChild2 Name: $($subChild2.getAttribute('name')), Value: $($subChild2.getAttribute('value'))"
       }
    }
    

You can then use the same idea to enumerate Child3:

# Get all Child3 nodes
$child3Nodes = $xml.SelectNodes("//Child3")

foreach ($child3 in $child3Nodes) {
    # Iterate over each child of Child3 and print
    foreach ($subChild3 in $child3.ChildNodes) {
        # Print SubChild3 content
        Write-Host "SubChild3 Content: $($subChild3.'#text')"
    }
}