[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Idiomatic way for collecting elements using REXML?

John Lam

5/19/2005 2:16:00 PM

I'm writing some REST-ian code to talk to the Amazon Web Services
since there are some bugs in SOAP4R (which I'll explain in a future
mail).

While manually parsing the XML that is returned from Amazon's REST
interface, I wound up writing the following code:

item.details = []
doc.elements.each('ItemLookupResponse/Items/Item') do |item|
# construct an item_detail
item_details << item_detail
end

This doesn't *feel* right. I wanted to use collect() but it's not
implemented in REXML. Is there a more Ruby-esque approach to gathering
some objects into an array while parsing XML?

Thanks
-John


4 Answers

james_b

5/19/2005 2:30:00 PM

0

John Lam wrote:
> I'm writing some REST-ian code to talk to the Amazon Web Services
> since there are some bugs in SOAP4R (which I'll explain in a future
> mail).
>
> While manually parsing the XML that is returned from Amazon's REST
> interface, I wound up writing the following code:
>
> item.details = []
> doc.elements.each('ItemLookupResponse/Items/Item') do |item|
> # construct an item_detail
> item_details << item_detail
> end
>
> This doesn't *feel* right. I wanted to use collect() but it's not
> implemented in REXML. Is there a more Ruby-esque approach to gathering
> some objects into an array while parsing XML?

require 'rexml/document'
doc = REXML::Document.new( "<a><b><c>1</c><c>2</c><c>3</c></b></a>")
p doc.elements.to_a( '/a/b/c' ).collect { |e| e.text }



James
--
http://www.ru...
http://www.r...
http://catapult.rub...
http://orbjson.rub...
http://ooo4r.rub...
http://www.jame...


John Lam

5/19/2005 2:38:00 PM

0

Thanks - that did the trick!

-John
http://www.iu...

> require 'rexml/document'
> doc = REXML::Document.new( "<a><b><c>1</c><c>2</c><c>3</c></b></a>")
> p doc.elements.to_a( '/a/b/c' ).collect { |e| e.text }


Gavin Kistner

5/19/2005 2:46:00 PM

0

On May 19, 2005, at 8:15 AM, John Lam wrote:
> item.details = []
> doc.elements.each('ItemLookupResponse/Items/Item') do |item|
> # construct an item_detail
> item_details << item_detail
> end
>
> This doesn't *feel* right. I wanted to use collect() but it's not
> implemented in REXML. Is there a more Ruby-esque approach to gathering
> some objects into an array while parsing XML?

You seem to have left a detail out of your code (where does
'item_detail' come from?) but that's generally what I do in similar
circumstances.

Alternatively, you could write your own #collect method:

class REXML::Elements
def collect( xpath=nil )
vals = []
self.each(xpath){ |el| vals << yield el }
vals
end
end

Or, perhaps you could modify the existing each method to return an
array with no block supplied:

class REXML::Elements
alias_method :__each :each
def each( xpath=nil, &block )
if block_given?
__each( xpath, &block )
else
els = []
__each( xpath ){ |el| els << el }
els
end
end
end

Then you could simply:
item_details = doc.elements.each( '...' ).collect{ ... }


But then this is really exactly what Xpath.match does:
item_details = XPath.match( doc, 'ItemLookupResponse/Items/
Item' ).collect{ ... }

(Aside: What possessed the author of the REXML library to put all the
XPath stuff in its own class with class methods? Why not simply
"doc.match( my_xpath )"? Whenever I see a class method that takes a
single object for an argument to set scope, it screams to me that it
should be a method on that object.)

Hope that helps,


--
(-, /\ \/ / /\/

SER

5/29/2005 12:28:00 PM

0

> Aside: What possessed the author of the REXML library to put all the
> XPath stuff in its own class with class methods? Why not simply

Three things. First, XPath is not part of the XML spec -- it is its
own spec, and has nothing to do with the tree (DOM) parser aside from
the association an implementor makes. Second, because *someday*,
you'll be able to use XPaths on things other than the DOM parser.

But the primary reason is historical. There isn't really any reason
why there couldn't be an Element#match function that delegates to an
XPath instance. Suggestions for improvements are always welcome,
although I warn you that I'm not prone to trolling the newsgroups for
them.

--- SER