Re.Mark

My Life As A Blog

Ruby Tuesday #6 : A little XML

leave a comment »

Last week I wrote some code to download the public timeline from Twitter.  The public timeline is in XML format, so we need a little code to translate it into something more readable.  Before getting to the XML reading, I moved the code from last week into a new file called, very imaginatively, Twitter.rb.  I also discovered that the name I gave the method (getUrl) isn’t very Rubylike, so I changed it (to get_url).  Now, I’m not the biggest fan of underscores, but part of this learning Ruby business is to learn the culture and customs as well as the language itself.

Next, I decided that it would be good to have a class representing a tweet and another class representing a user.  I put both of them in the Twitter file.  Here are those classes:

class Tweet
  attr_reader :created, :id, :text, :source, :truncated, :user

  def initialize(created, id, text, source, truncated, user)
    @created = created
    @id = id
    @text = text
    @source = source
    @truncated = truncated
    @user = user
  end
end

class User
  attr_reader :id, :name, :screen_name, :location,
    :description, :image_url, :url, :protected

    def initialize(id, name, screen_name, location, description, image_url,
    url, protected, followers_count)
       @id = id
       @name = name
       @screen_name = screen_name
       @location = location
       @description = description
       @image_url = image_url
       @url = url
       @protected = protected
       @followers_count = followers_count
    end
end

I’ve used the attr_reader method to create read-only attributes which are set in the initialise method of each class.  For those who, like me, are new to Ruby the initialise method performs a similar purpose to a constructor.  The funny @ signs denote instance variables.  I could have made these classes by using attr_accessor (which creates a getter and a setter), but I like this style of object.  I expect I’ll find a simpler way of doing it as I go along.

Next we need to read XML into these objects.  I created a class called Translator and in it created a method called xml_to_tweets (and a method it calls called element_to_user.)  Here’s the class:

class Translator
  def xml_to_tweets(xml)
    tweets = []
    xml_document = Document.new(xml)
    root = xml_document.root
    root.elements.each("status") do |element|
      tweets << Tweet.new(element.elements["created_at"].text,
      element.elements["id"].text,
      element.elements["text"].text,
      element.elements["source"].text,
      element.elements["truncated"].text,
      element_to_user(element.elements["user"]))
    end
    tweets
  end


  def element_to_user(element)
    User.new(element.elements["id"].text,
    element.elements["name"].text,
    element.elements["screen_name"].text,
    element.elements["location"].text,
    element.elements["description"].text,
    element.elements["profile_image_url"].text,
    element.elements["url"].text,
    element.elements["protected"].text,
    element.elements["followers_count"].text)
  end
end

REXML is a conformant XML processor, so if you’ve done any XML programming before, it’ll be familiar.  Three things to note here.  Firstly, this code is using the REXML library (more info here) so I had to add 2 lines to the top of the file.  Those lines are:

require 'rexml/document'
include REXML

Secondly, for my fellow Ruby noobs, note that the value of the last expression in a method is returned (no return statement needed, although you can put it in if it you like.)

Thirdly, for the noobs again, note the array syntax.  A new array is created with the [] syntax and new elements are added with the << operator.

So, all that’s required now is some code to see if it works.  I used this code:

require 'Twitter' 


translator = Translator.new

translator.xml_to_tweets(get_url('http://twitter.com/statuses/public_timeline.xml')).each do |tweet|
  puts "#{tweet.user.screen_name} says #{tweet.text}"
end

The output of that is a lot friendlier than the XML I was outputting last week, and it was fairly easy to write.  Next week I’ll need to extend the code to call some of the other methods of the Twitter API. 

Advertisements

Written by remark

May 20, 2008 at 8:25 pm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: