Creating New Objects from REXML::Elements

Hello group,

I’m new to using REXML to parse documents, but quickly getting the hang
of it. Something, however, is giving me a little trouble, so I could
use some help. I’m trying to create a new object, specifically a Movie
from elements in Delicious Library’s XML data file (a Mac program,
found at http://www.delicious-monster.com). Basically, the XML file
stores the good stuff in tag attributes, and I’d rather make a new
objects from the attributes. I can pull the attributes, and puts proves
I’m pulling right, but when I try to push my new objects into an array,
the class identifies itself as an REXML::Element instead of a Movie.

This is the method that puts the new Movies into the array.
def get_movies
temp = @library.root
temp.elements.each(‘items/movie’) { |movie|
@movies.push(Movie.new(movie.attributes[‘uuid’],
movie.attributes[‘fullTitle’], movie.attributes[‘asin’],
movie.attributes[‘mpaarating’], movie.attributes[‘minutes’],
movie.attributes[‘published’], movie.attributes[‘price’]))
puts movie.attributes[‘fullTitle’]
}
end

But, irb tells me this:
irb(main):025:0> movies.class
=> Array
irb(main):026:0> movies[1].class
=> REXML::Element

Am I doing something completely wrong? Shouldn’t the values of the
attributes be passed directly to the constructor and I get a new object
of class Movie?

Thanks for the help,
Eddie

On 21-Dec-06, at 3:05 AM, Peter S. wrote:

Can you send the full code? Are you sure that e.g. Movie.new does
not return a REXML::Element for example? Anyway, I can not really
figure this out without seeing the full code.

And the XML as well.

Cheers,
Bob

Cheers,
Peter


Bob H. – blogs at <http://www.recursive.ca/
hutch/>
Recursive Design Inc. – http://www.recursive.ca/
Raconteur – http://www.raconteur.info/
xampl for Ruby – http://rubyforge.org/projects/xampl/

eddieroger wrote:

the class identifies itself as an REXML::Element instead of a Movie.
}
end

Can you send the full code? Are you sure that e.g. Movie.new does not
return a REXML::Element for example? Anyway, I can not really figure
this out without seeing the full code.

Cheers,
Peter

__
http://www.rubyrailways.com

On Dec 21, 2006, at 1:40 AM, eddieroger wrote:

[…] when I try to push my new objects into an array,
the class identifies itself as an REXML::Element instead of a Movie.
[…]
irb tells me this:
irb(main):025:0> movies.class
=> Array
irb(main):026:0> movies[1].class
=> REXML::Element

I’ve encountered precisely this same problem! I use REXML to pull
values out of an XML document and into an object; but, instead of my
objects, I end up with an Array of REXML::Element’s. :frowning:

TomP

Here is the full Ruby code:

require ‘rexml/document’
include REXML

class DeliciousLibrary

#usual_path is the path of the DL XML file (until v2). Unless this
script is on a server, this works.
@@usual_path = “#{ENV[‘HOME’]}/Library/Application Support/Delicious
Library/Library Media Data.xml”

@@medium_covers = “#{ENV[‘HOME’]}/Library/Application
Support/Delicious Library/Medium Covers/” #requires UUID for
identification

def initialize(file = @@usual_path)
@library = Document.new(File.new(file))
@movies = Array.new
end

def get_library_as_xml
@library.root
end

def get_movies
temp = @library.root
temp.elements.each(‘items/movie’) { |movie|
@movies.push(Movie.new(movie.attributes[‘uuid’].to_str,
movie.attributes[‘fullTitle’], movie.attributes[‘asin’],
movie.attributes[‘mpaarating’], movie.attributes[‘minutes’],
movie.attributes[‘published’], movie.attributes[‘price’]))
puts movie.attributes[‘fullTitle’]
}
end

def get_shelves
@library.root.elements[‘items/shelves’]
end

end

class Movie
#Some Supplimental Classes
def initialize(uuid, fullTitle, asin, mpaarating, minutes, published,
price)
@uuid = uuid
@fullTitle = fullTitle
@asin = asin
@mpaarating = mpaarating
@minutes = minutes
@published = published
@price = price
end
attr_reader :uuid, :fullTitle, :asin, :mpaarating, :minutes,
:published, :price
end

The XML file is about 7000 lines long, os here’s a snippet. i don’t
think you really want 7000 lines of code listed anyway.



Thanks for the help.

On 21-Dec-06, at 9:25 AM, eddieroger wrote:

def get_movies
temp = @library.root
temp.elements.each(‘items/movie’) { |movie|
@movies.push(Movie.new(movie.attributes[‘uuid’].to_str,
movie.attributes[‘fullTitle’], movie.attributes[‘asin’],
movie.attributes[‘mpaarating’], movie.attributes[‘minutes’],
movie.attributes[‘published’], movie.attributes[‘price’]))
puts movie.attributes[‘fullTitle’]
}
end

Have you tried to_str on all of the arguments?

Cheers,
Bob


Bob H. – blogs at <http://www.recursive.ca/
hutch/>
Recursive Design Inc. – http://www.recursive.ca/
Raconteur – http://www.raconteur.info/
xampl for Ruby – http://rubyforge.org/projects/xampl/

On Dec 22, 2006, at 1:20 AM, eddieroger wrote:

Have you solved this?

No, not yet. I’ll try to find some more time to play with it (and
try Bob’s suggestion) this evening.

TomP

Not exactly what I did right, but I managed to get it. Basically, its
the same as before, but I replaced my get_movies and get_library with
this:

def get_library
@library
end

def get_movies
allmovies = Array.new
temp = get_library
temp = temp.root
temp.elements.each(‘items/movie’) { |movie|
tempm = Movie.new(movie.attributes[‘uuid’].to_s,
movie.attributes[‘title’].to_s, movie.attributes[‘asin’].to_s,
movie.attributes[‘mpaarating’].to_s, movie.attributes[‘minutes’].to_s,
movie.attributes[‘published’].to_s, movie.attributes[‘price’].to_s)
allmovies << tempm
}
return allmovies
end

So, @movies isn’t initialized any more, and I just return the array of
Movies to irb or whatever calls it. I realized that I needed it there
more anyway, and if i really want it automatically created, I’ll just
set @movies = get_movies in the constructor. Also, notice the .to_s
after each attribute. I’m not sure if its necessary, but that’s just
how it is for now. Thanks for the help, all.

Eddie

On Dec 22, 2006, at 1:20 AM, eddieroger wrote:

I’ve encountered precisely this same problem! I use REXML to pull
values out of an XML document and into an object; but, instead of my
objects, I end up with an Array of REXML::Element’s. :frowning:

Have you solved this?

Finally. I realized I’d made the bone-headed mistake of not
specifying an explicit return value in my function that processed the
REXML fragment. What I had was

class Evcase
def from_rexml ( record )
record.each_element do |el|
begin
self.send(“ev_#{el.name.downcase}=”, el.text)
rescue
Evcase.create_accessors(el.name.downcase)
retry
end
end
end
end

This was used from code that looked like

doc.root.get_elements(‘PROBLEM_RECORD’).each do |rec|
@cases << Evcase.new.from_rexml(rec)
end

This latter code depends on the Evcase object being returned from the
_from_rexml method; instead, it was returning the REXML element
(‘record’) that had been passed in. I’m not sure why it took me so
long to see that. Hope this helps someone else…

TomP

Have you solved this? A fancy workaround, perhaps? Short of actually
making strings equivalent to the pieces, I am running out of ideas,
except the inefficiency of that kills me. I guess I’ll give that a shot
and post an update if I get it to work.