Search code examples
arraysxmlpowershellfor-loopcdata

PowerShell for loop not adding last value from previously looped arrays


I am totally stumped. I am reading data from an XML file into two separate arrays, which is then grouped together in a third array by indices (i.e. ($array-element[0], $array2-element[0])):

This is what my XML kinda looks like:

XML

<RESULTS>
    <ROW>
        <COLUMN NAME="ATTR1"><![CDATA[123456ABCDEF]]></COLUMN>
        <COLUMN NAME="ATTR2"><![CDATA[0.0.0.0]]></COLUMN>
        <COLUMN NAME="ATTR3"><![CDATA[Hello World]]></COLUMN>
        <COLUMN NAME="ATTR4"><![CDATA[Lorem ipsum]]></COLUMN>
        <COLUMN NAME="ATTR5"><![CDATA[This is some text]]></COLUMN>
    </ROW>
</RESULTS>

This is my PowerShell script that reads ATTR2 and ATTR3 into two separate arrays:

PowerShell (first two arrays)

$array = @()
$array2 = @()

foreach ($name in $xmldata.RESULTS.ROW.COLUMN.Where{ $_.NAME -eq "ATTR3"}.'#cdata-section')
{
    $array += $name
}

foreach ($version in $xmldata.RESULTS.ROW.COLUMN.Where{ $_.NAME -eq "ATTR2"}.'#cdata-section')
{
    $array2 += $version
}

It returns the desired result.

Then I group the matching indices from each array into a new array ($array3):

PowerShell (third array)

$array3 = @()

for($i = 0; $i -lt $array.Length; $i++)
{
    $array3 += $array[$i] + ", " + $array2[$i]
    $i++
}

It returns the desired result (see below):

Result

Hello World, 0.0.0.0
(so on and so forth...)

However, the last for-loop refuses to add the last values from $array and $array2 into $array3.

$array.Length tells me the length of $array and $array2 are 896 even though there are only 895 elements. When I return $array[896] I get zero results. When I return $array[895] it returns the last value I am looking for.

And if the length of the array is indeed 896, then $i should stop at 895, correct? So, I assume it would be grabbing the final value (indexed at 895). So, why is my for-loop not adding the final value?


Solution

  • The immediate problem with your for loop is that you've already specified that $i++ should be executed after each iteration in the loop signature ($i = 0; $i -lt $array.Length; $i++), but then you manually call $i++ inside the body as well.

    That being said, the real solution is to not split the columns into 2 arrays in the first place. Instead, create a new object for each ROW node in the XML when you first iterate over it:

    # assign all output from `foreach` loop to `$array`
    $array = foreach($row in $xmldata.RESULTS.ROW){
      # create new object with the pertinent details as property values
      [pscustomobject]@{
        Name = $row.COLUMN.Where{ $_.NAME -eq "ATTR3"}.'#cdata-section'
        Version = $row.COLUMN.Where{ $_.NAME -eq "ATTR2"}.'#cdata-section'
      }
    }
    

    Now, $array will contain one object per ROW node, each with their own Name and Version property