Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

count xml child nodes

2,001 views
Skip to first unread message

Mike Bates

unread,
Apr 6, 2010, 5:44:08 AM4/6/10
to
As a newbie to PS I'm very impressed as to what it can do, but I'm
having trouble understanding some of the subtleties. I'm trying to
process a large XML file, roughly of the form shown in the code
snippet below, but have hit an issue I don't understand. The code that
explains this is...

$xW = [xml]@'
<W>
<X xID="1">
<Y yID="20">
<Z zID="201"/>
</Y>
<Y yID="30">
<Z zID="301"/>
<Z zID="302"/>
</Y>
</X>
</W>
'@
write-host First Y Node Z count = $xW.W.X.Y[0].Z.Count
write-host Second Y Node Z count = $xW.W.X.Y[1].Z.Count

The output from this is:

First Y Node Z count =
Second Y Node Z count = 2

I was expecting the first output line to indicate a count of 1.

What I'm trying to achieve is to output a csv file of the form
xID,yID,zID where zID is a null value if there are no Z child nodes,
or there are multiple xID,yID lines when more than one Z child node
exists in a Y node.

HC

Chris Dent

unread,
Apr 6, 2010, 6:08:39 AM4/6/10
to
The first of those is a single value, it has no Count property because
it's type is XmlElement not Object[] (in the case of 1, an object array
where each member is XmlElement).

See:

$xW.W.X.Y[0].Z.GetType()
$xW.W.X.Y[1].Z.GetType()
$xW.W.X.Y[1].Z | %{ $_.GetType() }

You can force it to be an array (remember to do it for index 1 if you
don't know how many children it has first):

write-host First Y Node Z count = ([Array]($xW.W.X.Y[0].Z)).Count
write-host Second Y Node Z count = ([Array]($xW.W.X.Y[1].Z)).Count

Or you can use Measure-Object:

write-host First Y Node Z count = ($xW.W.X.Y[0].Z | Measure-Object).Count
write-host Second Y Node Z count = ($xW.W.X.Y[1].Z | Measure-Object).Count

HTH

Chris

Clint B

unread,
Apr 6, 2010, 11:50:52 AM4/6/10
to
Using a little XPATH you can avoid the whole "is it an array" issue (and
scale to more nodes a little easier):

$xw.SelectNodes("/W/X/Y") | % { $_.createnavigator().evaluate("count(./Z)")}

1
2

And if you want the output labeled:
$xw.SelectNodes("/W/X/Y") | % { $i = 1 } { $count =
$_.createnavigator().evaluate("count(./Z)") ; "Y Node Z Count #{0} :
{1}" -f $i++,$count }

For some good reads on XML/XPATH & PowerShell:
http://www.pluralsight.com/community/blogs/dan/archive/2006/11/25/42506.aspx
http://www.pluralsight.com/community/blogs/dan/archive/2006/11/28/43561.aspx
http://powershell.com/cs/blogs/tobias/archive/2009/01/17/xml-part-1-playing-with-rss-feeds-and-xml-content.aspx
http://powershell.com/cs/blogs/tobias/archive/2009/02/02/xml-part-2-write-add-and-change-xml-data.aspx

HTH :)

--
v(^_^)~Clint
http://outputredirection.blogspot.com

Larry__Weiss

unread,
Apr 6, 2010, 1:51:22 PM4/6/10
to

stej

unread,
Apr 7, 2010, 2:08:16 AM4/7/10
to
Good suggestions guys!
Note as well that there are living .NET objects in the background, so
you can use

PS> $xW.w.x.Y[0].haschildnodes
True
PS> $xW.w.x.Y[0].childnodes.count
1

0 new messages