Idiomatic way for collecting elements using REXML?

J

John Lam

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 =3D []
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
 
J

James Britt

John said:
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.ruby-doc.org
http://www.rubyxml.com
http://catapult.rubyforge.org
http://orbjson.rubyforge.org
http://ooo4r.rubyforge.org
http://www.jamesbritt.com
 
G

Gavin Kistner

--Apple-Mail-1-767805386
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
charset=US-ASCII;
delsp=yes;
format=flowed

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,
 
S

SER

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,054
Latest member
LucyCarper

Latest Threads

Top