Loop through xml elements

82,667

Solution 1

Use XPATH instead to find all nodes with a SID attribute like so:

$objs = @()
$nodes = $userfile.SelectNodes("//*[@SID]")
foreach ($node in $nodes) {
    $sid = $node.attributes['SID'].value
    $dispName = $node.attributes['DISPLAYNAME'].value
    $obj = new-object psobject -prop @{SID=$sid;DISPNAME=$dispName}
    $objs += $obj
}
$objs

Here's an example with output:

$xml = [xml]@"
<doc>
  <foo SID='foosid' DISPLAYNAME="foodisp">
    <bar SID='barsid' DISPLAYNAME="bardisp"/>
    <baz>
      <blech SID='blechsid' DISPLAYNAME="blechdisp"/>
    </baz>
  </foo>
</doc>
"@

$objs = @()
$nodes = $xml.SelectNodes("//*[@SID]")
foreach ($node in $nodes) {
    $sid = $node.attributes['SID'].value
    $dispName = $node.attributes['DISPLAYNAME'].value
    $obj = new-object psobject -prop @{SID=$sid;DISPNAME=$dispName}
    $objs += $obj
}
$objs

Outputs:

SID                       DISPNAME                
---                       --------                
foosid                    foodisp                 
barsid                    bardisp                 
blechsid                  blechdisp               

Solution 2

You can also reference the child nodes when you are iterating through the childNodes:

$j.LocalName (the name of the child element)
$j.InnerXml  (the Xml content of the child node)
Share:
82,667
adean
Author by

adean

Updated on March 19, 2020

Comments

  • adean
    adean about 4 years

    I have the following:

    $aMyArray = $null
    
    
    [xml]$userfile = Get-Content C:\AppSense\Scripts\AmPolicyConversion\AM_dev.xml
    
    $i = 0
    FOREACH ($j in $userfile.ChildNodes){
    
        FOREACH($k in $j.DocumentElement) {
    
        }
    
        $i = $i + 1
    }
    

    I am trying to figure out how to loop through each element within powershell.

    Then check for an attribute of SID on the element.

    If exists get attribute value and put that value into an object and for the same element grab second attribute DISPLAYNAME and place into same object. We will create an array of objects.

    I know I am way off but hope you can help.

    • carlpett
      carlpett over 11 years
      Could you add some more detail? Such as, do you know what the xml will look like? Powershell allows you to access by name in that case, which I've found makes code much easier to read
  • Anicho
    Anicho over 11 years
    I assume you'd want to add a statement that checks if sid is null before creating multiple new obj empty objects, so you get an array of objs that are relevant.
  • Keith Hill
    Keith Hill over 11 years
    Since the XPATH specifies that the SID attribute exists on the element, I wouldn't expect a null value for SID - perhaps an empty string.
  • Anicho
    Anicho over 11 years
    you are correct, I am just saying to be efficient on whats stored in memory. looks like they extracting data of ad based users there might be 1000s so each object would take up x amount of memory, even if they store 0 properties it just saves a bit of space for later on?
  • adean
    adean over 11 years
    @Keith HillThanks for the help, hhowever the above doesn't seem to traverse subnodes
  • adean
    adean over 11 years
    I have been using <code> $nodes = $userfile.SelectNodes("/*/*/*[@SID]") </code> to get various levels down but i really need a -recursive to traverse the whole tree. I have working code using find and replace by bringing in the XML file as text but that's more of a workaround than a solution.
  • Keith Hill
    Keith Hill over 11 years
    The XPATH expression "//*" says to search every XML element (node), no matter where it is in the hierarchy of elements.