Unit Testing with REXML questions

Hello all,

I'm using REXML to build some XML from a rails app. I'm unit testing
the output also using REXML... and I have these questions :

Given

<a>
  <b>one</b>
  <c>two</c>
  <d>
    <e>three</e>
    <f>four</f>
  </d>
</a>

I want to use XPath to tell me how many <d> there are under <a> ?

I want to use XPath to iterate the _names_ of the items under <d>
(Does this make sense in XML World. This one is not necessarily a
requirement, but I uncovered this need while experimenting in IRB.) ?

Thanks in advance!
Peter Fitzgibbons

one specific <a> or all <a> tags???
But, you should be able to do:
root.elements( "/a/d" ).size
and that should return the count of ALL <d> elements under any <a> tag
root.elements( "/a[1]/d" ).size
should return the count of <d> elements under the first <a> tag ( it does
appear that the index operator in xpath is one-based not zero-based ).
Hope that helps.
j.

···

On 10/14/05, Peter Fitzgibbons <peter.fitzgibbons@gmail.com> wrote:

Hello all,

I'm using REXML to build some XML from a rails app. I'm unit testing
the output also using REXML... and I have these questions :

Given

<a>
<b>one</b>
<c>two</c>
<d>
<e>three</e>
<f>four</f>
</d>
</a>

I want to use XPath to tell me how many <d> there are under <a> ?

I want to use XPath to iterate the _names_ of the items under <d>
(Does this make sense in XML World. This one is not necessarily a
requirement, but I uncovered this need while experimenting in IRB.) ?

Thanks in advance!
Peter Fitzgibbons

--
"http://ruby-lang.org -- do you ruby?"

Jeff Wood

HI Jeff,

xmltest.rb :
require 'rexml/document'

xmlin = <<EOD
<a>
<b>one</b>
<c>two</c>
<d>
   <e>three</e>
   <f>four</f>
</d>
</a>
EOD

xml = REXML::Document.new(xmlin)
puts xml.elements['/a/d'].size
puts xml.elements['/a/d']

output :
5
<d>
   <e>three</e>
   <f>four</f>
</d>

xml.elements['/a/d'] returns the entire xml tree under/including /a/d

I want this to return 1 (the number of "d" elements in the list)

Ah, well I now understand...
using xml.elements[] does not return the same object as
REXML::XPath.match, which returns an array of results.

Thank you.

Hi Peter,

What you want is to get the array of specific nodes, isn't it??
If it's true, see code below:

xmltest.rb :
require 'rexml/document'

xmlin = <<EOD
<a>
  <b>one</b>
  <c>two</c>
  <d>
    <e>three</e>
    <f>four</f>
  </d>
</a>
EOD

xml = REXML::Document.new(xmlin)
puts xml.elements.to_a('/a/d')

···

--
then, you can iterate with the nodes of 'd', including knowing
the number of 'd' nodes with '.size' method, right??

Regards,

umitanuki

Peter Fitzgibbons wrote:

HI Jeff,

xmltest.rb :
require 'rexml/document'

xmlin = <<EOD
<a>
<b>one</b>
<c>two</c>
<d>
   <e>three</e>
   <f>four</f>
</d>
</a>
EOD

xml = REXML::Document.new(xmlin)
puts xml.elements['/a/d'].size
puts xml.elements['/a/d']

output :
5
<d>
   <e>three</e>
   <f>four</f>
</d>

xml.elements['/a/d'] returns the entire xml tree under/including /a/d

I want this to return 1 (the number of "d" elements in the list)

Peter,

Actually... i don't understand why you got "5" when you did size...
that was one element.

And yes, an element contains it's children ... but they aren't going
to be iterated over unless you did something like /a/d/* or something
like that.

what do you get when you run

count = 0 ; xml.elements( '/a/d' ).each { count += 1 ) ; puts count

... of course umitanuki's to_a should also simply return an array of 1 length.

j.

···

On 10/16/05, umitanuki <yasagure@umitanuki.net> wrote:

Hi Peter,

What you want is to get the array of specific nodes, isn't it??
If it's true, see code below:

xmltest.rb :
require 'rexml/document'

xmlin = <<EOD
<a>
  <b>one</b>
  <c>two</c>
  <d>
    <e>three</e>
    <f>four</f>
  </d>
</a>
EOD

xml = REXML::Document.new(xmlin)
puts xml.elements.to_a('/a/d')

--
then, you can iterate with the nodes of 'd', including knowing
the number of 'd' nodes with '.size' method, right??

Regards,

umitanuki

Peter Fitzgibbons wrote:
> HI Jeff,
>
> xmltest.rb :
> require 'rexml/document'
>
> xmlin = <<EOD
> <a>
> <b>one</b>
> <c>two</c>
> <d>
> <e>three</e>
> <f>four</f>
> </d>
> </a>
> EOD
>
> xml = REXML::Document.new(xmlin)
> puts xml.elements['/a/d'].size
> puts xml.elements['/a/d']
>
>
> output :
> 5
> <d>
> <e>three</e>
> <f>four</f>
> </d>
>
> xml.elements['/a/d'] returns the entire xml tree under/including /a/d
>
> I want this to return 1 (the number of "d" elements in the list)
>
>
>

--
"http://ruby-lang.org -- do you ruby?"

Jeff Wood

Hi Jeff, and Peter,

I also got "5" with this code:

xml.elements['/a/d'].size

And then I checked your code like:

xml.elements('/a/d') ,

it failed with message
" in 'elements': wrong number of arguments(1 for 0) (Argument Error) ".

Is it the difference of REXML version??
My REXML is 3.1.2.1.

Regards,

umitanuki

Jeff Wood wrote:

···

Peter,

Actually... i don't understand why you got "5" when you did size...
that was one element.

And yes, an element contains it's children ... but they aren't going
to be iterated over unless you did something like /a/d/* or something
like that.

what do you get when you run

count = 0 ; xml.elements( '/a/d' ).each { count += 1 ) ; puts count

... of course umitanuki's to_a should also simply return an array of 1 length.

j.

On 10/16/05, umitanuki <yasagure@umitanuki.net> wrote:

Hi Peter,

What you want is to get the array of specific nodes, isn't it??
If it's true, see code below:

xmltest.rb :
require 'rexml/document'

xmlin = <<EOD
<a>
<b>one</b>
<c>two</c>
<d>
   <e>three</e>
   <f>four</f>
</d>
</a>
EOD

xml = REXML::Document.new(xmlin)
puts xml.elements.to_a('/a/d')

--
then, you can iterate with the nodes of 'd', including knowing
the number of 'd' nodes with '.size' method, right??

Regards,

umitanuki

Peter Fitzgibbons wrote:

HI Jeff,

xmltest.rb :
require 'rexml/document'

xmlin = <<EOD
<a>
<b>one</b>
<c>two</c>
<d>
  <e>three</e>
  <f>four</f>
</d>
</a>
EOD

xml = REXML::Document.new(xmlin)
puts xml.elements['/a/d'].size
puts xml.elements['/a/d']

output :
5
<d>
  <e>three</e>
  <f>four</f>
</d>

xml.elements['/a/d'] returns the entire xml tree under/including /a/d

I want this to return 1 (the number of "d" elements in the list)

--
"http://ruby-lang.org -- do you ruby?"

Jeff Wood

Because the each method returns the collection, you can actually just do this (odd-looking) hack:
     puts xml.elements.each('/a/d'){}.size

(The block is required, but may be empty.)

···

On Oct 16, 2005, at 9:07 AM, Jeff Wood wrote:

count = 0 ; xml.elements( '/a/d' ).each { count += 1 ) ; puts count

My code was :

puts xml.elements['/a/d'].size

in previous post.

···

On 10/17/05, umitanuki <yasagure@umitanuki.net> wrote:

Hi Jeff, and Peter,

I also got "5" with this code:

xml.elements['/a/d'].size

And then I checked your code like:

xml.elements('/a/d') ,

it failed with message
" in 'elements': wrong number of arguments(1 for 0) (Argument Error) ".

Is it the difference of REXML version??
My REXML is 3.1.2.1.

Regards,

umitanuki

Jeff Wood wrote:
> Peter,
>
> Actually... i don't understand why you got "5" when you did size...
> that was one element.
>
> And yes, an element contains it's children ... but they aren't going
> to be iterated over unless you did something like /a/d/* or something
> like that.
>
> what do you get when you run
>
> count = 0 ; xml.elements( '/a/d' ).each { count += 1 ) ; puts count
>
> ... of course umitanuki's to_a should also simply return an array of 1 length.
>
> j.
>
> On 10/16/05, umitanuki <yasagure@umitanuki.net> wrote:
>
>>Hi Peter,
>>
>>What you want is to get the array of specific nodes, isn't it??
>>If it's true, see code below:
>>
>>xmltest.rb :
>>require 'rexml/document'
>>
>>xmlin = <<EOD
>><a>
>> <b>one</b>
>> <c>two</c>
>> <d>
>> <e>three</e>
>> <f>four</f>
>> </d>
>></a>
>>EOD
>>
>>xml = REXML::Document.new(xmlin)
>>puts xml.elements.to_a('/a/d')
>>
>>--
>>then, you can iterate with the nodes of 'd', including knowing
>>the number of 'd' nodes with '.size' method, right??
>>
>>Regards,
>>
>>
>>umitanuki
>>
>>
>>Peter Fitzgibbons wrote:
>>
>>>HI Jeff,
>>>
>>>xmltest.rb :
>>>require 'rexml/document'
>>>
>>>xmlin = <<EOD
>>><a>
>>> <b>one</b>
>>> <c>two</c>
>>> <d>
>>> <e>three</e>
>>> <f>four</f>
>>> </d>
>>></a>
>>>EOD
>>>
>>>xml = REXML::Document.new(xmlin)
>>>puts xml.elements['/a/d'].size
>>>puts xml.elements['/a/d']
>>>
>>>
>>>output :
>>>5
>>><d>
>>> <e>three</e>
>>> <f>four</f>
>>> </d>
>>>
>>>xml.elements['/a/d'] returns the entire xml tree under/including /a/d
>>>
>>>I want this to return 1 (the number of "d" elements in the list)
>>>
>>>
>>>
>>
>>
>>
>
>
> --
> "http://ruby-lang.org -- do you ruby?"
>
> Jeff Wood
>
>
>

true.

···

On 10/19/05, Gavin Kistner <gavin@refinery.com> wrote:

On Oct 16, 2005, at 9:07 AM, Jeff Wood wrote:
> count = 0 ; xml.elements( '/a/d' ).each { count += 1 ) ; puts count

Because the each method returns the collection, you can actually just
do this (odd-looking) hack:
     puts xml.elements.each('/a/d'){}.size

(The block is required, but may be empty.)

--
"http://ruby-lang.org -- do you ruby?"

Jeff Wood

My mistake

I meant for the param to be sent to "each"

count = 0
xml.elements.each( "/a/d" ) { count += 1 }
puts count

j.

···

On 10/17/05, Peter Fitzgibbons <peter.fitzgibbons@gmail.com> wrote:

On 10/17/05, umitanuki <yasagure@umitanuki.net> wrote:
> Hi Jeff, and Peter,
>
> I also got "5" with this code:
>
> xml.elements['/a/d'].size
>
> And then I checked your code like:
>
> xml.elements('/a/d') ,
>
> it failed with message
> " in 'elements': wrong number of arguments(1 for 0) (Argument Error) ".
>
> Is it the difference of REXML version??
> My REXML is 3.1.2.1.
>
> Regards,
>
>
> umitanuki
>
>
> Jeff Wood wrote:
> > Peter,
> >
> > Actually... i don't understand why you got "5" when you did size...
> > that was one element.
> >
> > And yes, an element contains it's children ... but they aren't going
> > to be iterated over unless you did something like /a/d/* or something
> > like that.
> >
> > what do you get when you run
> >
> > count = 0 ; xml.elements( '/a/d' ).each { count += 1 ) ; puts count
> >
> > ... of course umitanuki's to_a should also simply return an array of 1 length.
> >
> > j.
> >
> > On 10/16/05, umitanuki <yasagure@umitanuki.net> wrote:
> >
> >>Hi Peter,
> >>
> >>What you want is to get the array of specific nodes, isn't it??
> >>If it's true, see code below:
> >>
> >>xmltest.rb :
> >>require 'rexml/document'
> >>
> >>xmlin = <<EOD
> >><a>
> >> <b>one</b>
> >> <c>two</c>
> >> <d>
> >> <e>three</e>
> >> <f>four</f>
> >> </d>
> >></a>
> >>EOD
> >>
> >>xml = REXML::Document.new(xmlin)
> >>puts xml.elements.to_a('/a/d')
> >>
> >>--
> >>then, you can iterate with the nodes of 'd', including knowing
> >>the number of 'd' nodes with '.size' method, right??
> >>
> >>Regards,
> >>
> >>
> >>umitanuki
> >>
> >>
> >>Peter Fitzgibbons wrote:
> >>
> >>>HI Jeff,
> >>>
> >>>xmltest.rb :
> >>>require 'rexml/document'
> >>>
> >>>xmlin = <<EOD
> >>><a>
> >>> <b>one</b>
> >>> <c>two</c>
> >>> <d>
> >>> <e>three</e>
> >>> <f>four</f>
> >>> </d>
> >>></a>
> >>>EOD
> >>>
> >>>xml = REXML::Document.new(xmlin)
> >>>puts xml.elements['/a/d'].size
> >>>puts xml.elements['/a/d']
> >>>
> >>>
> >>>output :
> >>>5
> >>><d>
> >>> <e>three</e>
> >>> <f>four</f>
> >>> </d>
> >>>
> >>>xml.elements['/a/d'] returns the entire xml tree under/including /a/d
> >>>
> >>>I want this to return 1 (the number of "d" elements in the list)
> >>>
> >>>
> >>>
> >>
> >>
> >>
> >
> >
> > --
> > "http://ruby-lang.org -- do you ruby?"
> >
> > Jeff Wood
> >
> >
> >
>
>
>
>

My code was :

puts xml.elements['/a/d'].size

in previous post.

--
"http://ruby-lang.org -- do you ruby?"

Jeff Wood

I didn't know such a code but it's seemed so useful.
Tanks,

umitanuki

Jeff Wood wrote:

···

My mistake

I meant for the param to be sent to "each"

count = 0
xml.elements.each( "/a/d" ) { count += 1 }
puts count

j.

On 10/17/05, Peter Fitzgibbons <peter.fitzgibbons@gmail.com> wrote:

On 10/17/05, umitanuki <yasagure@umitanuki.net> wrote:

Hi Jeff, and Peter,

I also got "5" with this code:

xml.elements['/a/d'].size

And then I checked your code like:

xml.elements('/a/d') ,

it failed with message
" in 'elements': wrong number of arguments(1 for 0) (Argument Error) ".

Is it the difference of REXML version??
My REXML is 3.1.2.1.

Regards,

umitanuki

Jeff Wood wrote:

Peter,

Actually... i don't understand why you got "5" when you did size...
that was one element.

And yes, an element contains it's children ... but they aren't going
to be iterated over unless you did something like /a/d/* or something
like that.

what do you get when you run

count = 0 ; xml.elements( '/a/d' ).each { count += 1 ) ; puts count

... of course umitanuki's to_a should also simply return an array of 1 length.

j.

On 10/16/05, umitanuki <yasagure@umitanuki.net> wrote:

Hi Peter,

What you want is to get the array of specific nodes, isn't it??
If it's true, see code below:

xmltest.rb :
require 'rexml/document'

xmlin = <<EOD
<a>
<b>one</b>
<c>two</c>
<d>
  <e>three</e>
  <f>four</f>
</d>
</a>
EOD

xml = REXML::Document.new(xmlin)
puts xml.elements.to_a('/a/d')

--
then, you can iterate with the nodes of 'd', including knowing
the number of 'd' nodes with '.size' method, right??

Regards,

umitanuki

Peter Fitzgibbons wrote:

HI Jeff,

xmltest.rb :
require 'rexml/document'

xmlin = <<EOD
<a>
<b>one</b>
<c>two</c>
<d>
<e>three</e>
<f>four</f>
</d>
</a>
EOD

xml = REXML::Document.new(xmlin)
puts xml.elements['/a/d'].size
puts xml.elements['/a/d']

output :
5
<d>
<e>three</e>
<f>four</f>
</d>

xml.elements['/a/d'] returns the entire xml tree under/including /a/d

I want this to return 1 (the number of "d" elements in the list)

--
"http://ruby-lang.org -- do you ruby?"

Jeff Wood

My code was :

puts xml.elements['/a/d'].size

in previous post.

--
"http://ruby-lang.org -- do you ruby?"

Jeff Wood