Creating New Objects from REXML::Elements

E

eddieroger

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
 
P

Peter Szinek

eddieroger said:
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

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
 
B

Bob Hutchison

E

eddieroger

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.

<movie asin="B000BW7QWW" aspect="DVD" country="us" created="188189008"
currentValue="$9.96"
features="AC-3
Animated
Color
Dolby
Dubbed
Subtitled
Widescreen
NTSC
2.35:1"
fullTitle="Serenity (Widescreen Edition)" genre="Sci-Fi
Action
Futuristic
Space Adventure
Action &amp;
Adventure
Science Fiction &amp; Fantasy"
lastLookupTime="188189024" minutes="119" mpaarating="PG-13"
netrating="4.5" price="$19.98" published="20-12-2005"
publisher="Universal Studios Home Entertainment"
purchaseDate="18-12-2006" stars="Chiwetel Ejiofor
Nathan
Fillion
Gina Torres
Morena Baccarin
Adam
Baldwin
Raphael Feldman
Yan Feldman
Ron
Glass
Summer Glau
Michael Hitchcock
Glenn
Howerton
David Krumholtz
Sean Maher
Sarah
Paulson
Nectar Rose
Jewel Staite
Tamara
Taylor
Alan Tudyk
Hunter Ansley Wryn"
theatricalDate="30-09-2005" title="Serenity" upc="0025192632723"
uuid="0CEA2670-C438-4C35-95A6-35F2E21DD05E">
....
</movie>


Thanks for the help.
 
T

Tom Pollard

[...] 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. :-(

TomP
 
E

eddieroger

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.

Tom said:
[...] 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. :-(

TomP
 
B

Bob Hutchison

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 Hutchison -- 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/>
 
E

eddieroger

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
 
T

Tom Pollard

Tom said:
[...] 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. :-(

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
 

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,754
Messages
2,569,527
Members
44,999
Latest member
MakersCBDGummiesReview

Latest Threads

Top