From: Gavin Kistner Date: 2005-05-19T23:46:04+09:00 Subject: Re: Idiomatic way for collecting elements using REXML? --Apple-Mail-1-767805386 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=US-ASCII; delsp=yes; format=flowed 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, -- (-, /\ \/ / /\/ --Apple-Mail-1-767805386--