# -*- rd -*-

= Tutorial.en

$Id: Tutorial.en 316 2004-02-13 10:10:04Z kou $

Sorry for my funny English :-(

== require

Describe it if you want to handle RSS 1.0:

  require 'rss/1.0'

Describe it If you want to handle RSS 0.9x:

  require 'rss/0.9'

Describe it If you want to handle RSS 2.0:

  require 'rss/2.0'

You can describe one, two or three of them at once. Describe
it if you want to handle RSS 0.9x/1.0:

  require 'rss/0.9'
  require 'rss/1.0'

Describe it if you want to handle RSS 0.9x/1.0/2.0:

  require 'rss/1.0'
  require 'rss/2.0'

You don't need describing it because of RSS 2.0 includes RSS
0.9x:

  require 'rss/0.9'


You can describe below items:

  require 'rss/dublincore'
  require 'rss/syndication'
  require 'rss/content'
  require 'rss/trackback'

You are availabe to use ((<Dublin
Core|URL:http://web.resource.org/rss/1.0/modules/dc/>))
module,
((<Syndication|URL:http://web.resource.org/rss/1.0/modules/syndication/>))
module,
((<Content|URL:http://web.resource.org/rss/1.0/modules/content/>))
module and
((<TrackBack|URL:http://madskills.com/public/xml/rss/module/trackback/>))
module if you require them.

However, Content module is supporting only content:encoded.

== Parsing

Use RSS::Parser class to parsing RSS. RSS::Parser.parse
parse RSS of String object. It returns RSS::RDF object when
parsing RSS 1.0, or RSS::Rss object when parsing RSS
0.9x/2.0. If parsed String is not RSS 0.9x/1.0/2.0 it
returns nil or raise a exception that is subclass of
RSS::Error.

For example, usage of parsing RSS 1.0 with validation is
below where variable (({rss_source})) is String of RSS 1.0.

  require 'rss/1.0'
  rss = RSS::Parser.parse(rss_source, true)

If secend argument of RSS::Parser.parse is abbreviated it is
reffered to as true. So above can describe below.

  require 'rss/1.0'
  rss = RSS::Parser.parse(rss_source)

First parsing RSS with validation, and if it is not valid
parse with non validation.

  require 'rss/1.0'
  rss = nil
  begin
    rss = RSS::Parser.parse(rss_source)
  rescue RSS::InvalidRSSError
    rss = RSS::Parser.parse(rss_source, false)
  end

It is good when you doesn't know what version of RSS that
you want to parsing. Below code first parse as RSS 1.0 with
validation, and if validation if failed parse as RSS
0.9x/(destroied)1.0/2.0 with non validation.

  require 'rss/1.0'
  require 'rss/2.0'
  rss = nil
  begin
    rss = RSS::Parser.parse(rss_source)
  rescue RSS::InvalidRSSError
    rss = RSS::Parser.parse(rss_source, false)
  end


Require rss/dublincore, rss/syndication, rss/content and/or
rss/trackback before RSS::Parser.parse when you want to
parse elements of Dublin Core, Syndication, Content and/or
TrackBack module.

  require 'rss/1.0'
  require 'rss/2.0'
  require 'rss/dublincore'
  require 'rss/syndication'
  require 'rss/content'
  require 'rss/trackback'
  rss = nil
  begin
    rss = RSS::Parser.parse(rss_source)
  rescue RSS::InvalidRSSError
    rss = RSS::Parser.parse(rss_source, false)
  end

=== Handling of unknown elements.

Parser's default behavior is ignore unknown (not specified
in specifications) element. Specify third argument of
RSS::Parser.parse if you want parser to raise exception when
comes across unknown element. Whereat parser raises
RSS::UnknownTagError exception when comes across unknown
element. RSS::UnknownTagError is subclass of
RSS::InvalidError.

If you want to parse RSS 1.0 strictly, describe like below (this is default):

  RSS::Parser.parse(rss_source, true, false)

== Parsed RSS

A parsed RSS is changed to RSS::RDF, RSS::RDF::Channel,
RSS::Rss, and so on object from String object. Each object
has some accessors that has name same of each child element
to access child element.

=== reader

A way of refference a channel element that child element of
a rdf:RDF is below:

  rss = RSS::Parser.parse(rss_source)
  rss.channel # => /rdf:RDF/channel; RSS::RDF::Channel

If the element dosen't have any child elements and any
attributes, accessor returns String. If the element is not
required, accessor may returns nil. This is same as the
element has some child elements or some attributes.

  rss = RSS::Parser.parse(rss_source)
  rss.channel.description # => /rdf:RDF/channel/text(); String

A way to accessing the attribute is same as above. A way of
accessing rdf:about attribute of channel element is like
below. The attribute avlue is String or nil.

  rss = RSS::Parser.parse(rss_source)
  rss.channel.about # => /rdf:RDF/channel/@about; String or nil

A way to accessing the element that may have some child
elements of same name is same as above. But if you don't
specify any argument to reader, returns first child
element. For example, a way of accessing item element that
child element of rdf:RDF element is like below:

  rss = RSS::Parser.parse(rss_source)
  rss.channel.item # => /rdf:RDF/item; RSS::RDF::Channel::Item

A way of accessing the third item element is like below. Not
abbreviated arguments of reader is handled same as arguments
of Array#[].

  rss = RSS::Parser.parse(rss_source)
  rss.channel.item(2) # => /rdf:RDF/item[3]; RSS::RDF::Channel::Item

Plural of a child element name is a reader which get all
children. A way of accessing all item element is like below.

  rss = RSS::Parser.parse(rss_source)
  rss.channel.item # => /rdf:RDF/item; [RSS::RDF::Channel::Item, ...]

=== writer

A way of setting channel element that child element of
rdf:RDF element is like below. You can specify the first
argument of RSS::RDF::Channel.new to value of rdf:about.

  rss = RSS::Parser.parse(rss_source)
  rss.channel = RSS::RDF::Channel.new(rdf_about_value)

A way of setting value of attribute is same as above.

  rss = RSS::Parser.parse(rss_source)
  rss.channel.about = "http://cozmixng.www.cozmixng.org/"

When existing some child elements that have same name is
same as above. But if arguments size is only one, this is
added.

  rss = RSS::Parser.parse(rss_source)
  item = RSS::RDF::Item.new(rdf_about_value)
  rss.item = item
  rss.item(-1) == item # => true

If arguments size is equal or greater two, they are handled
same as arguments of Array#[]=.

  rss = RSS::Parser.parse(rss_source)
  item = RSS::RDF::Item.new(rdf_about_value)
  rss.send(:item=, 0, item)
  rss.item == item # => true

This library have `set_<element_name>' as alias. You can use
this not use Object#send.

  rss = RSS::Parser.parse(rss_source)
  item = RSS::RDF::Item.new(rdf_about_value)
  rss.set_item(0, item)
  rss.item == item # => true

== Sample1 - List items

Let's write a script that parse RSSs and display list of
values of item elements.

First, require to be able to parse RSS 0.9x/1.0/2.0.

  require 'rss/1.0'
  require 'rss/2.0'

Parsed RSSs are saved in files and assume thir name is
provided as command line arguments.

  ARGV.each do |fname|
    rss_source = nil
    File.open(fname) do |f|
      rss_source = f.read
    end

    rss = nil
    begin
      rss = RSS::Parser.parse(rss_source, false)
    rescue RSS::Error
    end

    if rss.nil?
      puts "#{fname} is not RSS 0.9x/1.0/2.0."
    else
      print_items(rss)
    end
  end

And define print_items method.

RSS::RDF and RSS::Rss has some convenience methods; items
and image.

Items method returns array of /rdf:RDF/item elements when
RSS::RDF, or /rss/channel/item elements when RSS::Rss.

Image method returns /rdf:RDF/image element when RSS::RDF,
or /rss/channel/image element when RSS::Rss.

  def print_items(rss)
    rss.items.each do |item|
      puts "#{item.title} : #{item.description}"
    end
  end

You can use RSS::RDF#output_encoding= or
RSS::Rss#output_encoding= to change output encoding. If
specify encoding that can't be converted raise exception
that is RSS::UnknownConvertmethod object.

Let's rewrite above print_items to output UTF-8.

  def print_items(rss)
    begin
      rss.output_encoding = "UTF-8"
    rescue RSS::UnknownConversionMethodError
    end
    rss.items.each do |item|
      puts "#{item.title} : #{item.description}"
    end
  end

== Sample2 - Display items sorted with update tiem

Next, let's display items sorted with update time using date
attribute of Dublin Core module.

This library has accessor that name `dc_<element_name>' to
access elements of Dublin Core module. By the way it has
accessor that name `sy_<element_name>' to access elements of
Syndication module and Content modules's one is
`content_<element_name>'.

Required files are below:

  require 'rss/1.0'
  require 'rss/dublincore'

Parsed RSSs are saved in files and assume thir name is
provided as command line arguments same as sample1.

  items = []
  ARGV.each do |fname|
    rss_source = nil
    File.open(fname) do |f|
      rss_source = f.read
    end

    rss = nil
    begin
      rss = RSS::Parser.parse(rss_source, true)
    rescue RSS::Error
    end

    if rss.nil?
      puts "#{fname} is not RSS 1.0."
    else
      begin
        rss.output_encoding = "iso-8859-1"
      rescue RSS::UnknownConversionMethodError
      end
      rss.items.each do |item|
        items << item if item.dc_date
      end
    end
  end
  print_items(items)

And define method print_items.

Item#dc_date returns Time object or nil. (({items})) dosen't
have nil, so we can sort like bolow:

  def print_items(items)
    items.sort do |x, y|
      y.dc_date <=> x.dc_date
    end.each do |item|
      puts "#{item.dc_date.localtime.iso8601} : #{item.title} : #{item.description}"
    end
  end
