REXML and Date interaction

Hi,

I have a problem parsing dates from XML. I have this little program
which produces an error, and I was able to fix it by moving the date
parsing into a class that is distinct from the xml processing. Below
is a broken version and the error it prints, and then a working
version with the correct output. I would be grateful if anyone could
explain what is going wrong here. It looks like it turns the class
Date into a string Constant.

Thanks,
Bob E.

Broken Version

#!/usr/bin/env ruby

require ‘rexml/document’
require ‘date’

class DateFun

def parse(xml)
doc = REXML::Document.new(xml)
elems = doc.root.get_elements(’//body/dateelement[@date]’)
elems.map { |s|
s.attributes[“date”].to_s
}.sort
end

def sorted_dates_from(xml)
sorted_dates = parse(xml)
sorted_dates.map { |d| Date.parse(d)}.sort
end
end

xmlDates = <<HERE

HERE

sorted_dates = DateFun.new.sorted_dates_from(xmlDates)
sorted_dates.each { |d| puts d.to_s}

Produces

NoMethodError: undefined method parse' for "2005/224":String from /Users/bobevans/Documents/projects/rubyplay/brokendate.rb:18:insorted_dates_from’
from /Users/bobevans/Documents/projects/rubyplay/brokendate.rb:18:in
`sorted_dates_from’
from /Users/bobevans/Documents/projects/rubyplay/brokendate.rb:26
from (irb):1835
from /usr/local/lib/ruby/1.8/rexml/element.rb:1182

Working Version

#!/usr/bin/env ruby

require ‘rexml/document’
require ‘date’

class DateFun
include REXML

def parse(xml)
doc = Document.new(xml)
elems = doc.root.get_elements(’//body/dateelement[@date]’)
elems.map { |s|
s.attributes[“date”].to_s
}.sort
end
end

class Other
def sorted_dates_from(xml)
sorted_dates = DateFun.new.parse(xml)
sorted_dates.map { |d| Date.parse(d)}.sort
end
end

xmlDates = <<HERE

HERE

sorted_dates = Other.new.sorted_dates_from(xmlDates)
sorted_dates.each { |d| puts d.to_s}

Produces:

1954-02-05
1970-02-06
1973-12-28

Hi –

On Mon, 27 Nov 2006, Robert E. wrote:

Hi,

I have a problem parsing dates from XML. I have this little program which
produces an error, and I was able to fix it by moving the date parsing into a
class that is distinct from the xml processing. Below is a broken version and
the error it prints, and then a working version with the correct output. I
would be grateful if anyone could explain what is going wrong here. It looks
like it turns the class Date into a string Constant.

Your broken version worked for me. What version of Ruby are you
using?

David

Hi,

Thanks for running it, indeed that broken version works, and I
must’ve corrupted my irb session. So, I tried it again and discovered
more precisely the problem. If I include REXML in the class instead
of explicitly specifying REXML::Document, then I get the problem.
Which, I can just “not do that” for now, but it is still curious what
is happening. Here is a version that seems to produce the error still.

Thanks for the sanity check,

Bob E.

Better Broken

#!/usr/bin/env ruby

require ‘rexml/document’
require ‘date’

class DateFun

BEGIN Different

include REXML

END Different

def parse(xml)

BEGIN Different

 doc = Document.new(xml)

##End Different

 elems = doc.root.get_elements('//body/dateelement[@date]')
 elems.map { |s|
   s.attributes["date"].to_s
 }.sort

end

def sorted_dates_from(xml)
sorted_dates = parse(xml)
sorted_dates.map { |d| Date.parse(d)}.sort
end
end

xmlDates = <<HERE

HERE

sorted_dates = DateFun.new.sorted_dates_from(xmlDates)
sorted_dates.each { |d| puts d.to_s}

Produces

./brokendate.rb
./brokendate.rb:18:in sorted_dates_from': undefined methodparse’
for “2005/224”:String (NoMethodError)
from ./brokendate.rb:18:in `sorted_dates_from’
from ./brokendate.rb:26

Hi –

On Mon, 27 Nov 2006, Robert E. wrote:

elems = doc.root.get_elements(’//body/dateelement[@date]’)
elems.map { |s|
s.attributes[“date”].to_s
}.sort
end

def sorted_dates_from(xml)
sorted_dates = parse(xml)
sorted_dates.map { |d| Date.parse(d)}.sort

What’s happening is that you’re bringing REXML::Date into scope. You
need to do:

::Date.parse

to get the top-level Date constant.

David

On Nov 26, 2006, at 2:22 PM, [email protected] wrote:

What’s happening is that you’re bringing REXML::Date into scope. You
need to do:

::Date.parse

to get the top-level Date constant.

David

Ah cool. I didn’t realize there was a REXML::Date class, but I
suspected it might be something like that, and I didn’t realize I
could do just ::Date to fully qualify top level modules.

Thanks,
Bob E.

Hi –

On Mon, 27 Nov 2006, Robert E. wrote:

David

Ah cool. I didn’t realize there was a REXML::Date class, but I suspected it
might be something like that, and I didn’t realize I could do just ::Date to
fully qualify top level modules.

REXML::Date is actually a constant, but same idea.

David