summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2004-01-28 03:46:13 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2004-01-28 03:46:13 +0000
commit2cfa999f7baa1b994c9a0e3fef6b05f30d2ec7d9 (patch)
tree6262080bde1c6376c96bdc05d2a6692bd9de6818
parent28651fcd3db70dc779fd2d8d119229d3721de34b (diff)
downloadruby-2cfa999f7baa1b994c9a0e3fef6b05f30d2ec7d9.tar.gz
ruby-2cfa999f7baa1b994c9a0e3fef6b05f30d2ec7d9.tar.xz
ruby-2cfa999f7baa1b994c9a0e3fef6b05f30d2ec7d9.zip
* lib/rss: rss library imported. [ruby-dev:22726]
git-svn-id: http://svn.ruby-lang.org/repos/ruby/trunk@5566 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog4
-rw-r--r--config.sub4
-rw-r--r--lib/rss/0.9.rb438
-rw-r--r--lib/rss/1.0.rb652
-rw-r--r--lib/rss/2.0.rb148
-rw-r--r--lib/rss/content.rb47
-rw-r--r--lib/rss/converter.rb182
-rw-r--r--lib/rss/dublincore.rb56
-rw-r--r--lib/rss/parser.rb330
-rw-r--r--lib/rss/rexmlparser.rb43
-rw-r--r--lib/rss/rss.rb536
-rw-r--r--lib/rss/syndication.rb81
-rw-r--r--lib/rss/taxonomy.rb32
-rw-r--r--lib/rss/trackback.rb235
-rw-r--r--lib/rss/utils.rb19
-rw-r--r--lib/rss/xmlparser.rb69
-rw-r--r--lib/rss/xmlscanner.rb97
-rw-r--r--sample/rss/articles.rss186
-rw-r--r--sample/rss/content.xml28
-rw-r--r--sample/rss/index.rdf.ja186
-rw-r--r--sample/rss/list_description.rb84
-rw-r--r--sample/rss/news.rss170
-rw-r--r--sample/rss/php.rss235
-rw-r--r--sample/rss/raa-rdf10.xml59
-rw-r--r--sample/rss/rnn.rdf44
-rw-r--r--sample/rss/rss.xml87
-rw-r--r--sample/rss/rss2dc.xml203
-rw-r--r--sample/rss/rssMarkPilgrimExample.xml271
-rw-r--r--sample/rss/rssTwoExample.xml66
-rw-r--r--sample/rss/rss_recent.rb84
-rw-r--r--sample/rss/sampleRss.xml50
-rw-r--r--sample/rss/slashdot.rdf176
-rw-r--r--sample/rss/slashdotorg.rdf76
-rw-r--r--sample/rss/tdiary_plugin/rss-recent.rb118
-rw-r--r--sample/rss/w3c.rdf63
-rw-r--r--sample/rss/wiliki.rss88
-rw-r--r--test/rss/common.rb100
-rw-r--r--test/rss/each_parser.rb17
-rw-r--r--test/rss/my-assertions.rb89
-rw-r--r--test/rss/test.rb16
-rw-r--r--test/rss/test_1.0.rb237
-rw-r--r--test/rss/test_accessor.rb24
-rw-r--r--test/rss/test_content.rb94
-rw-r--r--test/rss/test_dublincore.rb123
-rw-r--r--test/rss/test_parser.rb418
-rw-r--r--test/rss/test_syndication.rb122
-rw-r--r--test/rss/test_trackback.rb110
47 files changed, 6595 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 4b1e64437..bfc2d6d73 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Wed Jan 28 12:43:07 2004 Yukihiro Matsumoto <matz@ruby-lang.org>
+
+ * lib/rss: rss library imported. [ruby-dev:22726]
+
Tue Jan 27 15:00:14 2004 Yukihiro Matsumoto <matz@ruby-lang.org>
* misc/ruby-mode.el: better support for general delimited
diff --git a/config.sub b/config.sub
index d2c7af03c..b85986a47 100644
--- a/config.sub
+++ b/config.sub
@@ -3,7 +3,7 @@
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
-timestamp='2003-01-03'
+timestamp='2004-01-28'
# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
@@ -118,7 +118,7 @@ esac
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
- nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
+ nto-qnx* | linux-* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
diff --git a/lib/rss/0.9.rb b/lib/rss/0.9.rb
new file mode 100644
index 000000000..467d57ba2
--- /dev/null
+++ b/lib/rss/0.9.rb
@@ -0,0 +1,438 @@
+require "rss/rss"
+
+module RSS
+
+ module RSS09
+ NSPOOL = {}
+ ELEMENTS = []
+ end
+
+ class Rss < Element
+
+ include RSS09
+
+ [
+ ["channel", nil],
+ ].each do |tag, occurs|
+ install_model(tag, occurs)
+ end
+
+ %w(channel).each do |x|
+ install_have_child_element(x)
+ end
+
+ attr_accessor :rss_version, :version, :encoding, :standalone
+
+ def initialize(rss_version, version=nil, encoding=nil, standalone=nil)
+ super()
+ @rss_version = rss_version
+ @version = version || '1.0'
+ @encoding = encoding
+ @standalone = standalone
+ end
+
+ def output_encoding=(enc)
+ @output_encoding = enc
+ self.converter = Converter.new(@output_encoding, @encoding)
+ end
+
+ def items
+ if @channel
+ @channel.items
+ else
+ []
+ end
+ end
+
+ def image
+ if @channel
+ @channel.image
+ else
+ nil
+ end
+ end
+
+ def to_s(convert=true)
+ rv = <<-EOR
+#{xmldecl}
+<rss version="#{@rss_version}"#{ns_declaration}>
+#{channel_element(false)}
+#{other_element(false, "\t")}
+</rss>
+EOR
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ end
+
+ private
+ def xmldecl
+ rv = "<?xml version='#{@version}'"
+ if @output_encoding or @encoding
+ rv << " encoding='#{@output_encoding or @encoding}'"
+ end
+ rv << " standalone='#{@standalone}'" if @standalone
+ rv << '?>'
+ rv
+ end
+
+ def ns_declaration
+ rv = ''
+ NSPOOL.each do |prefix, uri|
+ prefix = ":#{prefix}" unless prefix.empty?
+ rv << %Q|\n\txmlns#{prefix}="#{uri}"|
+ end
+ rv
+ end
+
+ def children
+ [@channel]
+ end
+
+ class Channel < Element
+
+ include RSS09
+
+ [
+ ["title", nil],
+ ["link", nil],
+ ["description", nil],
+ ["language", nil],
+ ["copyright", "?"],
+ ["managingEditor", "?"],
+ ["webMaster", "?"],
+ ["rating", "?"],
+ ["docs", "?"],
+ ["skipDays", "?"],
+ ["skipHours", "?"],
+ ].each do |x, occurs|
+ install_text_element(x)
+ install_model(x, occurs)
+ end
+
+ [
+ ["pubDate", "?"],
+ ["lastBuildDate", "?"],
+ ].each do |x, occurs|
+ install_date_element(x, 'rfc822')
+ install_model(x, occurs)
+ end
+
+ [
+ ["image", nil],
+ ["textInput", "?"],
+ ["cloud", "?"]
+ ].each do |x, occurs|
+ install_have_child_element(x)
+ install_model(x, occurs)
+ end
+
+ [
+ ["item", "*"]
+ ].each do |x, occurs|
+ install_have_children_element(x)
+ install_model(x, occurs)
+ end
+
+ def initialize()
+ super()
+ end
+
+ def to_s(convert=true)
+ rv = <<-EOT
+ <channel>
+ #{title_element(false)}
+ #{link_element(false)}
+ #{description_element(false)}
+ #{language_element(false)}
+ #{copyright_element(false)}
+ #{managingEditor_element(false)}
+ #{webMaster_element(false)}
+ #{rating_element(false)}
+ #{pubDate_element(false)}
+ #{lastBuildDate_element(false)}
+ #{docs_element(false)}
+ #{skipDays_element(false)}
+ #{skipHours_element(false)}
+ #{image_element(false)}
+#{item_elements(false)}
+ #{textInput_element(false)}
+#{other_element(false, "\t\t")}
+ </channel>
+EOT
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ end
+
+ private
+ def children
+ [@image, @textInput, @cloud, *@item]
+ end
+
+ class Image < Element
+
+ include RSS09
+
+ %w(url title link width height description).each do |x|
+ install_text_element(x)
+ end
+
+ def to_s(convert=true)
+ rv = <<-EOT
+ <image>
+ #{url_element(false)}
+ #{title_element(false)}
+ #{link_element(false)}
+ #{width_element(false)}
+ #{height_element(false)}
+ #{description_element(false)}
+#{other_element(false, "\t\t\t\t")}
+ </image>
+EOT
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ end
+
+ end
+
+ class Cloud < Element
+
+ include RSS09
+
+ [
+ ["domain", nil, false],
+ ["port", nil, false],
+ ["path", nil, false],
+ ["registerProcedure", nil, false],
+ ["protocol", nil ,false],
+ ].each do |name, uri, required|
+ install_get_attribute(name, uri, required)
+ end
+
+ def to_s(convert=true)
+ rv = <<-EOT
+ <cloud
+ domain="#{h @domain}"
+ port="#{h @port}"
+ path="#{h @path}"
+ registerProcedure="#{h @registerProcedure}"
+ protocol="#{h @protocol}"/>
+EOT
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ end
+
+ end
+
+ class Item < Element
+
+ include RSS09
+
+ %w(title link description author comments).each do |x|
+ install_text_element(x)
+ end
+
+ %w(category source enclosure).each do |x|
+ install_have_child_element(x)
+ end
+
+ [
+ ["title", '?'],
+ ["link", '?'],
+ ["description", '?'],
+ ["author", '?'],
+ ["comments", '?'],
+ ["category", '?'],
+ ["source", '?'],
+ ["enclosure", '?'],
+ ].each do |tag, occurs|
+ install_model(tag, occurs)
+ end
+
+ def to_s(convert=true)
+ rv = <<-EOT
+ <item>
+ #{title_element(false)}
+ #{link_element(false)}
+ #{description_element(false)}
+ #{author_element(false)}
+ #{category_element(false)}
+ #{comments_element(false)}
+ #{enclosure_element(false)}
+ #{source_element(false)}
+#{other_element(false, "\t\t\t\t")}
+ </item>
+EOT
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ end
+
+ class Source < Element
+
+ include RSS09
+
+ [
+ ["url", nil, true]
+ ].each do |name, uri, required|
+ install_get_attribute(name, uri, required)
+ end
+
+ content_setup
+
+ def initialize(url=nil, content=nil)
+ super()
+ @url = url
+ @content = content
+ end
+
+ def to_s(convert=true)
+ if @url
+ rv = %Q! <source url="#{@url}">!
+ rv << %Q!#{@content}</source>!
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ else
+ ''
+ end
+ end
+
+ private
+ def _attrs
+ [
+ ["url", true]
+ ]
+ end
+
+ end
+
+ class Enclosure < Element
+
+ include RSS09
+
+ [
+ ["url", nil, true],
+ ["length", nil, true],
+ ["type", nil, true],
+ ].each do |name, uri, required|
+ install_get_attribute(name, uri, required)
+ end
+
+ def initialize(url=nil, length=nil, type=nil)
+ super()
+ @url = url
+ @length = length
+ @type = type
+ end
+
+ def to_s(convert=true)
+ if @url and @length and @type
+ rv = %Q!<enclosure url="#{h @url}" !
+ rv << %Q!length="#{h @length}" type="#{h @type}"/>!
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ else
+ ''
+ end
+ end
+
+ private
+ def _attrs
+ [
+ ["url", true],
+ ["length", true],
+ ["type", true],
+ ]
+ end
+
+ end
+
+ class Category < Element
+
+ include RSS09
+
+ [
+ ["domain", nil, true]
+ ].each do |name, uri, required|
+ install_get_attribute(name, uri, required)
+ end
+
+ content_setup
+
+ def initialize(domain=nil, content=nil)
+ super()
+ @domain = domain
+ @content = content
+ end
+
+ def to_s(convert=true)
+ if @domain
+ rv = %Q!<category domain="#{h @domain}">!
+ rv << %Q!#{h @content}</category>!
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ else
+ ''
+ end
+ end
+
+ private
+ def _attrs
+ [
+ ["domain", true]
+ ]
+ end
+
+ end
+
+ end
+
+ class TextInput < Element
+
+ include RSS09
+
+ %w(title description name link).each do |x|
+ install_text_element(x)
+ end
+
+ def to_s(convert=true)
+ rv = <<-EOT
+ <textInput>
+ #{title_element(false)}
+ #{description_element(false)}
+ #{name_element(false)}
+ #{link_element(false)}
+#{other_element(false, "\t\t\t\t")}
+ </textInput>
+EOT
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ end
+
+ end
+
+ end
+
+ end
+
+ if const_defined?(:BaseListener)
+ RSS09::ELEMENTS.each do |x|
+ BaseListener.install_get_text_element(x, nil, "#{x}=")
+ end
+ end
+
+ if const_defined?(:ListenerMixin)
+ module ListenerMixin
+ private
+ def start_rss(tag_name, prefix, attrs, ns)
+ check_ns(tag_name, prefix, ns, nil)
+
+ @rss = Rss.new(attrs['version'], @version, @encoding, @standalone)
+ @last_element = @rss
+ @proc_stack.push Proc.new { |text, tags|
+ @rss.validate_for_stream(tags) if @do_validate
+ }
+ end
+
+ end
+ end
+
+end
diff --git a/lib/rss/1.0.rb b/lib/rss/1.0.rb
new file mode 100644
index 000000000..72b763712
--- /dev/null
+++ b/lib/rss/1.0.rb
@@ -0,0 +1,652 @@
+require "rss/rss"
+
+module RSS
+
+ module RSS10
+ NSPOOL = {}
+ ELEMENTS = []
+ end
+
+ class RDF < Element
+
+ include RSS10
+
+ class << self
+
+ def required_uri
+ URI
+ end
+
+ end
+
+ TAG_NAME.replace('RDF')
+
+ PREFIX = 'rdf'
+ URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+
+ install_ns('', ::RSS::URI)
+ install_ns(PREFIX, URI)
+
+ [
+ ["channel", nil],
+ ["image", "?"],
+ ["item", "+"],
+ ["textinput", "?"],
+ ].each do |tag, occurs|
+ install_model(tag, occurs)
+ end
+
+ %w(channel image textinput).each do |x|
+ install_have_child_element(x)
+ end
+
+ install_have_children_element("item")
+
+ attr_accessor :rss_version, :version, :encoding, :standalone
+
+ def initialize(version=nil, encoding=nil, standalone=nil)
+ super()
+ @rss_version = '1.0'
+ @version = version || '1.0'
+ @encoding = encoding
+ @standalone = standalone
+ @output_encoding = nil
+ end
+
+ def output_encoding=(enc)
+ @output_encoding = enc
+ self.converter = Converter.new(@output_encoding, @encoding)
+ end
+
+ def to_s(convert=true)
+ rv = <<-EORDF
+#{xmldecl}
+<#{PREFIX}:RDF#{ns_declaration}>
+#{channel_element(false)}
+#{image_element(false)}
+#{item_elements(false)}
+#{textinput_element(false)}
+#{other_element(false, "\t")}
+</#{PREFIX}:RDF>
+EORDF
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ end
+
+ private
+ def xmldecl
+ rv = "<?xml version='#{@version}'"
+ if @output_encoding or @encoding
+ rv << " encoding='#{@output_encoding or @encoding}'"
+ end
+ rv << " standalone='#{@standalone}'" if @standalone
+ rv << '?>'
+ rv
+ end
+
+ def ns_declaration
+ rv = ''
+ self.class::NSPOOL.each do |prefix, uri|
+ prefix = ":#{prefix}" unless prefix.empty?
+ rv << %Q|\n\txmlns#{prefix}="#{html_escape(uri)}"|
+ end
+ rv
+ end
+
+ def rdf_validate(tags)
+ _validate(tags, [])
+ end
+
+ def children
+ [@channel, @image, @textinput, *@item]
+ end
+
+ def _tags
+ rv = [
+ [::RSS::URI, "channel"],
+ [::RSS::URI, "image"],
+ ].delete_if {|x| send(x[1]).nil?}
+ @item.each do |x|
+ rv << [::RSS::URI, "item"]
+ end
+ rv << [::RSS::URI, "textinput"] if @textinput
+ rv
+ end
+
+ class Seq < Element
+
+ include RSS10
+
+ class << self
+
+ def required_uri
+ URI
+ end
+
+ end
+
+ TAG_NAME.replace('Seq')
+
+ install_have_children_element("li")
+
+ install_must_call_validator('rdf', ::RSS::RDF::URI)
+
+ def initialize(li=[])
+ super()
+ @li = li
+ end
+
+ def to_s(convert=true)
+ <<-EOT
+ <#{PREFIX}:Seq>
+#{li_elements(convert, "\t\t\t\t\t")}
+#{other_element(convert, "\t\t\t\t\t")}
+ </#{PREFIX}:Seq>
+EOT
+ end
+
+ private
+ def children
+ @li
+ end
+
+ def rdf_validate(tags)
+ _validate(tags, [["li", '*']])
+ end
+
+ def _tags
+ rv = []
+ @li.each do |x|
+ rv << [URI, "li"]
+ end
+ rv
+ end
+
+ end
+
+ class Li < Element
+
+ include RSS10
+
+ class << self
+
+ def required_uri
+ URI
+ end
+
+ end
+
+ [
+ ["resource", nil, true]
+ ].each do |name, uri, required|
+ install_get_attribute(name, uri, required)
+ end
+
+ def initialize(resource=nil)
+ super()
+ @resource = resource
+ end
+
+ def to_s(convert=true)
+ if @resource
+ rv = %Q!<#{PREFIX}:li resource="#{h @resource}" />!
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ else
+ ''
+ end
+ end
+
+ private
+ def _attrs
+ [
+ ["resource", true]
+ ]
+ end
+
+ end
+
+ class Channel < Element
+
+ include RSS10
+
+ class << self
+
+ def required_uri
+ ::RSS::URI
+ end
+
+ end
+
+ [
+ ["about", URI, true]
+ ].each do |name, uri, required|
+ install_get_attribute(name, uri, required)
+ end
+
+ %w(title link description).each do |x|
+ install_text_element(x)
+ end
+
+ %w(image items textinput).each do |x|
+ install_have_child_element(x)
+ end
+
+ [
+ ['title', nil],
+ ['link', nil],
+ ['description', nil],
+ ['image', '?'],
+ ['items', nil],
+ ['textinput', '?'],
+ ].each do |tag, occurs|
+ install_model(tag, occurs)
+ end
+
+ def initialize(about=nil)
+ super()
+ @about = about
+ end
+
+ def to_s(convert=true)
+ about = ''
+ about << %Q!#{PREFIX}:about="#{h @about}"! if @about
+ rv = <<-EOT
+ <channel #{about}>
+ #{title_element(false)}
+ #{link_element(false)}
+ #{description_element(false)}
+ #{image_element(false)}
+#{items_element(false)}
+ #{textinput_element(false)}
+#{other_element(false, "\t\t")}
+ </channel>
+EOT
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ end
+
+ private
+ def children
+ [@image, @items, @textinput]
+ end
+
+ def _tags
+ [
+ [::RSS::URI, 'title'],
+ [::RSS::URI, 'link'],
+ [::RSS::URI, 'description'],
+ [::RSS::URI, 'image'],
+ [::RSS::URI, 'items'],
+ [::RSS::URI, 'textinput'],
+ ].delete_if do |x|
+ send(x[1]).nil?
+ end
+ end
+
+ def _attrs
+ [
+ ["about", true]
+ ]
+ end
+
+ class Image < Element
+
+ include RSS10
+
+ class << self
+
+ def required_uri
+ ::RSS::URI
+ end
+
+ end
+
+ [
+ ["resource", URI, true]
+ ].each do |name, uri, required|
+ install_get_attribute(name, uri, required)
+ end
+
+ def initialize(resource=nil)
+ super()
+ @resource = resource
+ end
+
+ def to_s(convert=true)
+ if @resource
+ rv = %Q!<image #{PREFIX}:resource="#{h @resource}" />!
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ else
+ ''
+ end
+ end
+
+ private
+ def _attrs
+ [
+ ["resource", true]
+ ]
+ end
+
+ end
+
+ class Textinput < Element
+
+ include RSS10
+
+ class << self
+
+ def required_uri
+ ::RSS::URI
+ end
+
+ end
+
+ [
+ ["resource", URI, true]
+ ].each do |name, uri, required|
+ install_get_attribute(name, uri, required)
+ end
+
+ def initialize(resource=nil)
+ super()
+ @resource = resource
+ end
+
+ def to_s(convert=true)
+ if @resource
+ rv = %Q|<textinput #{PREFIX}:resource="#{h @resource}" />|
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ else
+ ''
+ end
+ end
+
+ private
+ def _attrs
+ [
+ ["resource", true],
+ ]
+ end
+
+ end
+
+ class Items < Element
+
+ include RSS10
+
+ Seq = ::RSS::RDF::Seq
+ class Seq
+ unless const_defined?(:Li)
+ Li = ::RSS::RDF::Li
+ end
+ end
+
+ class << self
+
+ def required_uri
+ ::RSS::URI
+ end
+
+ end
+
+ install_have_child_element("Seq")
+
+ install_must_call_validator('rdf', ::RSS::RDF::URI)
+
+ def initialize(seq=Seq.new)
+ super()
+ @Seq = seq
+ end
+
+ def to_s(convert=true)
+ <<-EOT
+ <items>
+#{Seq_element(convert)}
+#{other_element(convert, "\t\t\t")}
+ </items>
+EOT
+ end
+
+ private
+ def children
+ [@Seq]
+ end
+
+ private
+ def _tags
+ rv = []
+ rv << [URI, 'Seq'] unless @Seq.nil?
+ rv
+ end
+
+ def rdf_validate(tags)
+ _validate(tags, [["Seq", nil]])
+ end
+
+ end
+
+ end
+
+ class Image < Element
+
+ include RSS10
+
+ class << self
+
+ def required_uri
+ ::RSS::URI
+ end
+
+ end
+
+ [
+ ["about", URI, true]
+ ].each do |name, uri, required|
+ install_get_attribute(name, uri, required)
+ end
+
+ %w(title url link).each do |x|
+ install_text_element(x)
+ end
+
+ [
+ ['title', nil],
+ ['url', nil],
+ ['link', nil],
+ ].each do |tag, occurs|
+ install_model(tag, occurs)
+ end
+
+ def initialize(about=nil)
+ super()
+ @about = about
+ end
+
+ def to_s(convert=true)
+ about = ''
+ about << %Q!#{PREFIX}:about="#{h @about}"! if @about
+ rv = <<-EOT
+ <image #{about}>
+ #{title_element(false)}
+ #{url_element(false)}
+ #{link_element(false)}
+#{other_element(false, "\t\t")}
+ </image>
+EOT
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ end
+
+ private
+ def _tags
+ [
+ [::RSS::URI, 'title'],
+ [::RSS::URI, 'url'],
+ [::RSS::URI, 'link'],
+ ].delete_if do |x|
+ send(x[1]).nil?
+ end
+ end
+
+ def _attrs
+ [
+ ["about", true],
+ ]
+ end
+
+ end
+
+ class Item < Element
+
+ include RSS10
+
+ class << self
+
+ def required_uri
+ ::RSS::URI
+ end
+
+ end
+
+ [
+ ["about", URI, true]
+ ].each do |name, uri, required|
+ install_get_attribute(name, uri, required)
+ end
+
+ %w(title link description).each do |x|
+ install_text_element(x)
+ end
+
+ [
+ ["title", nil],
+ ["link", nil],
+ ["description", "?"],
+ ].each do |tag, occurs|
+ install_model(tag, occurs)
+ end
+
+ def initialize(about=nil)
+ super()
+ @about = about
+ end
+
+ def to_s(convert=true)
+ about = ''
+ about << %Q!#{PREFIX}:about="#{h @about}"! if @about
+ rv = <<-EOT
+ <item #{about}>
+ #{title_element(false)}
+ #{link_element(false)}
+ #{description_element(false)}
+#{other_element(false, "\t\t")}
+ </item>
+EOT
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ end
+
+ private
+ def _tags
+ [
+ [::RSS::URI, 'title'],
+ [::RSS::URI, 'link'],
+ [::RSS::URI, 'description'],
+ ].delete_if do |x|
+ send(x[1]).nil?
+ end
+ end
+
+ def _attrs
+ [
+ ["about", true],
+ ]
+ end
+
+ end
+
+ class Textinput < Element
+
+ include RSS10
+
+ class << self
+
+ def required_uri
+ ::RSS::URI
+ end
+
+ end
+
+ [
+ ["about", URI, true]
+ ].each do |name, uri, required|
+ install_get_attribute(name, uri, required)
+ end
+
+ %w(title description name link).each do |x|
+ install_text_element(x)
+ end
+
+ [
+ ["title", nil],
+ ["description", nil],
+ ["name", nil],
+ ["link", nil],
+ ].each do |tag, occurs|
+ install_model(tag, occurs)
+ end
+
+ def initialize(about=nil)
+ super()
+ @about = about
+ end
+
+ def to_s(convert=true)
+ about = ''
+ about << %Q!#{PREFIX}:about="#{h @about}"! if @about
+ rv = <<-EOT
+ <textinput #{about}>
+ #{title_element(false)}
+ #{description_element(false)}
+ #{name_element(false)}
+ #{link_element(false)}
+#{other_element(false, "\t\t")}
+ </textinput>
+EOT
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ end
+
+ private
+ def _tags
+ [
+ [::RSS::URI, 'title'],
+ [::RSS::URI, 'description'],
+ [::RSS::URI, 'name'],
+ [::RSS::URI, 'link'],
+ ].delete_if do |x|
+ send(x[1]).nil?
+ end
+ end
+
+ def _attrs
+ [
+ ["about", true],
+ ]
+ end
+
+ end
+
+ end
+
+ if const_defined?(:BaseListener)
+ RSS10::ELEMENTS.each do |x|
+ BaseListener.install_get_text_element(x, URI, "#{x}=")
+ end
+ end
+
+end
diff --git a/lib/rss/2.0.rb b/lib/rss/2.0.rb
new file mode 100644
index 000000000..e43947e40
--- /dev/null
+++ b/lib/rss/2.0.rb
@@ -0,0 +1,148 @@
+require "rss/0.9"
+
+module RSS
+
+ class Rss
+
+ URI = "http://backend.userland.com/rss2"
+
+ install_ns('', URI)
+
+ def self.required_uri
+ URI
+ end
+
+ class Channel
+
+ def self.required_uri
+ URI
+ end
+
+ %w(generator ttl).each do |x|
+ install_text_element(x)
+ end
+
+ %w(category).each do |x|
+ install_have_child_element(x)
+ end
+
+ [
+ ["image", "?"],
+ ].each do |x, occurs|
+ install_model(x, occurs)
+ end
+
+ def other_element(convert, indent='')
+ rv = <<-EOT
+#{indent}#{category_element(convert)}
+#{indent}#{generator_element(convert)}
+#{indent}#{ttl_element(convert)}
+EOT
+ rv << super
+ end
+
+ Category = Item::Category
+ def Category.required_uri
+ URI
+ end
+
+ class Item
+
+ def self.required_uri
+ URI
+ end
+
+ [
+ ["pubDate", '?'],
+ ].each do |x, occurs|
+ install_date_element(x, 'rfc822')
+ install_model(x, occurs)
+ end
+
+ [
+ ["guid", '?'],
+ ].each do |x, occurs|
+ install_have_child_element(x)
+ install_model(x, occurs)
+ end
+
+ def other_element(convert, indent='')
+ rv = <<-EOT
+#{indent}#{pubDate_element(false)}
+#{indent}#{guid_element(false)}
+EOT
+ rv << super
+ end
+
+ class Guid < Element
+
+ include RSS09
+
+ def self.required_uri
+ URI
+ end
+
+ [
+ ["isPermaLink", nil, false]
+ ].each do |name, uri, required|
+ install_get_attribute(name, uri, required)
+ end
+
+ content_setup
+
+ def initialize(isPermaLink=nil, content=nil)
+ super()
+ @isPermaLink = isPermaLink
+ @content = content
+ end
+
+ def to_s(convert=true)
+ if @content
+ rv = %Q!<guid!
+ rv << %Q! isPermaLink="#{h @isPermaLink}"! if @isPermaLink
+ rv << %Q!>#{h @content}</guid>!
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ else
+ ''
+ end
+ end
+
+ private
+ def _attrs
+ [
+ ["isPermaLink", false]
+ ]
+ end
+
+ end
+
+ end
+
+ end
+
+ end
+
+ if const_defined?(:BaseListener)
+ RSS09::ELEMENTS.each do |x|
+ BaseListener.install_get_text_element(x, Rss::URI, "#{x}=")
+ end
+ end
+
+ if const_defined?(:ListenerMixin)
+ module ListenerMixin
+ private
+ def start_rss(tag_name, prefix, attrs, ns)
+ check_ns(tag_name, prefix, ns, Rss::URI)
+
+ @rss = Rss.new(attrs['version'], @version, @encoding, @standalone)
+ @last_element = @rss
+ @proc_stack.push Proc.new { |text, tags|
+ @rss.validate_for_stream(tags) if @do_validate
+ }
+ end
+
+ end
+ end
+
+end
diff --git a/lib/rss/content.rb b/lib/rss/content.rb
new file mode 100644
index 000000000..64f87d4d5
--- /dev/null
+++ b/lib/rss/content.rb
@@ -0,0 +1,47 @@
+require "rss/1.0"
+
+module RSS
+
+ CONTENT_PREFIX = 'content'
+ CONTENT_URI = "http://purl.org/rss/1.0/modules/content/"
+
+ RDF.install_ns(CONTENT_PREFIX, CONTENT_URI)
+
+ module ContentModel
+
+ extend BaseModel
+
+ ELEMENTS = []
+
+ %w(encoded).each do |x|
+ install_text_element("#{CONTENT_PREFIX}_#{x}")
+ end
+
+ def content_validate(tags)
+ counter = {}
+ ELEMENTS.each do |x|
+ counter[x] = 0
+ end
+
+ tags.each do |tag|
+ key = "#{CONTENT_PREFIX}_#{tag}"
+ raise UnknownTagError.new(tag, CONTENT_URI) unless counter.has_key?(key)
+ counter[key] += 1
+ raise TooMuchTagError.new(tag, tag_name) if counter[key] > 1
+ end
+ end
+
+ end
+
+ class RDF
+ class Item; include ContentModel; end
+ end
+
+ if const_defined? :BaseListener
+ prefix_size = CONTENT_PREFIX.size + 1
+ ContentModel::ELEMENTS.each do |x|
+ BaseListener.install_get_text_element(x[prefix_size..-1], CONTENT_URI, "#{x}=")
+ end
+ end
+
+end
diff --git a/lib/rss/converter.rb b/lib/rss/converter.rb
new file mode 100644
index 000000000..144daab56
--- /dev/null
+++ b/lib/rss/converter.rb
@@ -0,0 +1,182 @@
+require "rss/utils"
+
+module RSS
+
+ class Converter
+
+ include Utils
+
+ def initialize(to_enc, from_enc=nil)
+ to_enc = to_enc.downcase.gsub(/-/, '_')
+ from_enc ||= 'utf-8'
+ from_enc = from_enc.downcase.gsub(/-/, '_')
+ if to_enc == from_enc
+ def_same_enc()
+ else
+ if respond_to?("def_to_#{to_enc}_from_#{from_enc}")
+ send("def_to_#{to_enc}_from_#{from_enc}")
+ else
+ def_else_enc(to_enc, from_enc)
+ end
+ end
+ end
+
+ def convert(value)
+ value
+ end
+
+ def def_convert()
+ instance_eval(<<-EOC, *get_file_and_line_from_caller(0))
+ def convert(value)
+ if value.kind_of?(String)
+ #{yield('value')}
+ else
+ value
+ end
+ end
+ EOC
+ end
+
+ def def_iconv_convert(to_enc, from_enc)
+ begin
+ require "iconv"
+ def_convert do |value|
+ <<-EOC
+ @iconv ||= Iconv.new("#{to_enc}", "#{from_enc}")
+ begin
+ @iconv.iconv(#{value})
+ rescue Iconv::Failure
+ raise ConversionError.new(#{value}, "#{to_enc}", "#{from_enc}")
+ #{value}
+ end
+EOC
+ end
+ rescue LoadError, ArgumentError, SystemCallError
+ raise UnknownConversionMethodError.new(to_enc, from_enc)
+ end
+ end
+
+ def def_else_enc(to_enc, from_enc)
+ raise UnknownConversionMethodError.new(to_enc, from_enc)
+ end
+
+ def def_same_enc()
+ def_convert do |value|
+ value
+ end
+ end
+
+ def def_to_euc_jp_from_utf_8
+ begin
+ require "uconv"
+ def_convert do |value|
+ "Uconv.u8toeuc(#{value})"
+ end
+ rescue LoadError
+ def_iconv_convert('EUC-JP', 'UTF-8')
+ end
+ end
+
+ def def_to_utf_8_from_euc_jp
+ begin
+ require "uconv"
+ def_convert do |value|
+ "Uconv.euctou8(#{value})"
+ end
+ rescue LoadError
+ def_iconv_convert('UTF-8', 'EUC-JP')
+ end
+ end
+
+ def def_to_shift_jis_from_utf_8
+ begin
+ require "uconv"
+ def_convert do |value|
+ "Uconv.u8tosjis(#{value})"
+ end
+ rescue LoadError
+ def_iconv_convert('Shift_JIS', 'UTF-8')
+ end
+ end
+
+ def def_to_utf_8_from_shift_jis
+ begin
+ require "uconv"
+ def_convert do |value|
+ "Uconv.sjistou8(#{value})"
+ end
+ rescue LoadError
+ def_iconv_convert('UTF-8', 'Shift_JIS')
+ end
+ end
+
+ def def_to_euc_jp_from_shift_jis
+ begin
+ require "nkf"
+ rescue LoadError
+ raise UnknownConversionMethodError.new('EUC-JP', 'Shift_JIS')
+ end
+ def_convert do |value|
+ "NKF.nkf('-Se', #{value})"
+ end
+ end
+
+ def def_to_shift_jis_from_euc_jp
+ begin
+ require "nkf"
+ rescue LoadError
+ raise UnknownConversionMethodError.new('Shift_JIS', 'EUC-JP')
+ end
+ def_convert do |value|
+ "NKF.nkf('-Es', #{value})"
+ end
+ end
+
+ def def_to_euc_jp_from_iso_2022_jp
+ begin
+ require "nkf"
+ rescue LoadError
+ raise UnknownConversionMethodError.new('EUC-JP', 'ISO-2022-JP')
+ end
+ def_convert do |value|
+ "NKF.nkf('-Je', #{value})"
+ end
+ end
+
+ def def_to_iso_2022_jp_from_euc_jp
+ begin
+ require "nkf"
+ rescue LoadError
+ raise UnknownConversionMethodError.new('ISO-2022-JP', 'EUC-JP')
+ end
+ def_convert do |value|
+ "NKF.nkf('-Ej', #{value})"
+ end
+ end
+
+ def def_to_utf_8_from_iso_8859_1
+ def_convert do |value|
+ "#{value}.unpack('C*').pack('U*')"
+ end
+ end
+
+ def def_to_iso_8859_1_from_utf_8
+ def_convert do |value|
+ <<-EOC
+ array_utf8 = #{value}.unpack('U*')
+ array_enc = []
+ array_utf8.each do |num|
+ if num <= 0xFF
+ array_enc << num
+ else
+ array_enc.concat "&\#\#{num};".unpack('C*')
+ end
+ end
+ array_enc.pack('C*')
+EOC
+ end
+ end
+
+ end
+
+end
diff --git a/lib/rss/dublincore.rb b/lib/rss/dublincore.rb
new file mode 100644
index 000000000..e9c3fcac2
--- /dev/null
+++ b/lib/rss/dublincore.rb
@@ -0,0 +1,56 @@
+require "rss/1.0"
+
+module RSS
+
+ DC_PREFIX = 'dc'
+ DC_URI = "http://purl.org/dc/elements/1.1/"
+
+ RDF.install_ns(DC_PREFIX, DC_URI)
+
+ module DublincoreModel
+
+ extend BaseModel
+
+ ELEMENTS = []
+
+ %w(title description creator subject publisher
+ contributor type format identifier source
+ language relation coverage rights).each do |x|
+ install_text_element("#{DC_PREFIX}_#{x}")
+ end
+
+ %w(date).each do |x|
+ install_date_element("#{DC_PREFIX}_#{x}", 'iso8601', x)
+ end
+
+ def dc_validate(tags)
+ counter = {}
+ ELEMENTS.each do |x|
+ counter[x] = 0
+ end
+
+ tags.each do |tag|
+ key = "#{DC_PREFIX}_#{tag}"
+ raise UnknownTagError.new(tag, DC_URI) unless counter.has_key?(key)
+ counter[key] += 1
+ raise TooMuchTagError.new(tag, tag_name) if counter[key] > 1
+ end
+ end
+
+ end
+
+ class RDF
+ class Channel; include DublincoreModel; end
+ class Image; include DublincoreModel; end
+ class Item; include DublincoreModel; end
+ class Textinput; include DublincoreModel; end
+ end
+
+ if const_defined? :BaseListener
+ prefix_size = DC_PREFIX.size + 1
+ DublincoreModel::ELEMENTS.each do |x|
+ BaseListener.install_get_text_element(x[prefix_size..-1], DC_URI, "#{x}=")
+ end
+ end
+
+end
diff --git a/lib/rss/parser.rb b/lib/rss/parser.rb
new file mode 100644
index 000000000..39ccdfbc3
--- /dev/null
+++ b/lib/rss/parser.rb
@@ -0,0 +1,330 @@
+require "rss/rss"
+
+module RSS
+
+ class NotWellFormedError < Error
+ attr_reader :line, :element
+ def initialize(line=nil, element=nil)
+ message = "This is not well formed XML"
+ if element or line
+ message << "\nerror occurred"
+ message << " in #{element}" if element
+ message << " at about #{line} line" if line
+ end
+ message << "\n#{yield}" if block_given?
+ super(message)
+ end
+ end
+
+ class XMLParserNotFound < Error
+ def initialize
+ super("available XML parser does not found in " <<
+ "#{AVAILABLE_PARSERS.inspect}.")
+ end
+ end
+
+ class NSError < InvalidRSSError
+ attr_reader :tag, :prefix, :uri
+ def initialize(tag, prefix, require_uri)
+ @tag, @prefix, @uri = tag, prefix, require_uri
+ super("prefix <#{prefix}> doesn't associate uri " <<
+ "<#{require_uri}> in tag <#{tag}>")
+ end
+ end
+
+ class BaseParser
+
+ def initialize(rss)
+ @listener = Listener.new
+ @rss = rss
+ end
+
+ def rss
+ @listener.rss
+ end
+
+ def ignore_unknown_element
+ @listener.ignore_unknown_element
+ end
+
+ def ignore_unknown_element=(new_value)
+ @listener.ignore_unknown_element = new_value
+ end
+
+ def do_validate
+ @listener.do_validate
+ end
+
+ def do_validate=(new_value)
+ @listener.do_validate = new_value
+ end
+
+ def parse
+ if @listener.rss.nil?
+ _parse
+ end
+ @listener.rss
+ end
+
+ class << self
+ def parse(rss, do_validate=true, ignore_unknown_element=true)
+ parser = new(rss)
+ parser.do_validate = do_validate
+ parser.ignore_unknown_element = ignore_unknown_element
+ parser.parse
+ end
+ end
+
+ end
+
+ class BaseListener
+
+ extend Utils
+
+ class << self
+
+ @@setter = {}
+ def install_setter(uri, tag_name, setter)
+ @@setter[uri] = {} unless @@setter.has_key?(uri)
+ @@setter[uri][tag_name] = setter
+ end
+
+ def setter(uri, tag_name)
+ begin
+ @@setter[uri][tag_name]
+ rescue NameError
+ nil
+ end
+ end
+
+ def available_tags(uri)
+ begin
+ @@setter[uri].keys
+ rescue NameError
+ []
+ end
+ end
+
+ def install_get_text_element(name, uri, setter)
+ install_setter(uri, name, setter)
+ def_get_text_element(name, *get_file_and_line_from_caller(1))
+ end
+
+ private
+
+ def def_get_text_element(name, file, line)
+ unless private_instance_methods(false).include?("start_#{name}")
+ module_eval(<<-EOT, file, line)
+ def start_#{name}(name, prefix, attrs, ns)
+ uri = ns[prefix]
+ if @do_validate
+ tags = self.class.available_tags(uri)
+ unless tags.include?(name)
+ raise UnknownTagError.new(name, uri)
+ end
+ end
+ start_get_text_element(name, prefix, ns, uri)
+ end
+ EOT
+ end
+ send("private", "start_#{name}")
+ end
+
+ end
+
+ end
+
+ module ListenerMixin
+
+ attr_reader :rss
+
+ attr_accessor :ignore_unknown_element
+ attr_accessor :do_validate
+
+ def initialize
+ @rss = nil
+ @ignore_unknown_element = true
+ @do_validate = true
+ @ns_stack = [{}]
+ @tag_stack = [[]]
+ @text_stack = ['']
+ @proc_stack = []
+ @last_element = nil
+ @version = @encoding = @standalone = nil
+ end
+
+ def xmldecl(version, encoding, standalone)
+ @version, @encoding, @standalone = version, encoding, standalone
+ end
+
+ def tag_start(name, attributes)
+ @text_stack.push('')
+
+ ns = @ns_stack.last.dup
+ attrs = {}
+ attributes.each do |n, v|
+ if n =~ /\Axmlns:?/
+ ns[$'] = v # $' is post match
+ else
+ attrs[n] = v
+ end
+ end
+ @ns_stack.push(ns)
+
+ prefix, local = split_name(name)
+ @tag_stack.last.push([ns[prefix], local])
+ @tag_stack.push([])
+ if respond_to?("start_#{local}", true)
+ send("start_#{local}", local, prefix, attrs, ns.dup)
+ else
+ start_else_element(local, prefix, attrs, ns.dup)
+ end
+ end
+
+ def tag_end(name)
+ if $DEBUG
+ p "end tag #{name}"
+ p @tag_stack
+ end
+ text = @text_stack.pop
+ tags = @tag_stack.pop
+ pr = @proc_stack.pop
+ pr.call(text, tags) unless pr.nil?
+ end
+
+ def text(data)
+ @text_stack.last << data
+ end
+
+ private
+
+ def start_RDF(tag_name, prefix, attrs, ns)
+ check_ns(tag_name, prefix, ns, RDF::URI)
+
+ @rss = RDF.new(@version, @encoding, @standalone)
+ @rss.do_validate = @do_validate
+ @last_element = @rss
+ @proc_stack.push Proc.new { |text, tags|
+ @rss.validate_for_stream(tags) if @do_validate
+ }
+ end
+
+ def start_else_element(local, prefix, attrs, ns)
+ class_name = local[0,1].upcase << local[1..-1]
+ current_class = @last_element.class
+ begin
+# if current_class.const_defined?(class_name)
+ next_class = current_class.const_get(class_name)
+ start_have_something_element(local, prefix, attrs, ns, next_class)
+ rescue NameError
+# else
+ if @ignore_unknown_element
+ @proc_stack.push(nil)
+ else
+ parent = "ROOT ELEMENT???"
+ begin
+ parent = current_class::TAG_NAME
+ rescue NameError
+ end
+ raise NotExceptedTagError.new(local, parent)
+ end
+ end
+ end
+
+ NAMESPLIT = /^(?:([\w:][-\w\d.]*):)?([\w:][-\w\d.]*)/
+ def split_name(name)
+ name =~ NAMESPLIT
+ [$1 || '', $2]
+ end
+
+ def check_ns(tag_name, prefix, ns, require_uri)
+ if @do_validate
+ if ns[prefix] == require_uri
+ #ns.delete(prefix)
+ else
+ raise NSError.new(tag_name, prefix, require_uri)
+ end
+ end
+ end
+
+ def start_get_text_element(tag_name, prefix, ns, required_uri)
+ @proc_stack.push Proc.new {|text, tags|
+ setter = self.class.setter(required_uri, tag_name)
+ setter ||= "#{tag_name}="
+ if @last_element.respond_to?(setter)
+ @last_element.send(setter, text.to_s)
+ else
+ if @do_validate and not @ignore_unknown_element
+ raise NotExceptedTagError.new(tag_name, @last_element.tag_name)
+ end
+ end
+ }
+ end
+
+ def start_have_something_element(tag_name, prefix, attrs, ns, klass)
+
+ check_ns(tag_name, prefix, ns, klass.required_uri)
+
+ args = []
+
+ klass.get_attributes.each do |a_name, a_uri, required|
+
+ if a_uri
+ for prefix, uri in ns
+ if uri == a_uri
+ val = attrs["#{prefix}:#{a_name}"]
+ break if val
+ end
+ end
+ else
+ val = attrs[a_name]
+ end
+
+ if @do_validate and required and val.nil?
+ raise MissingAttributeError.new(tag_name, a_name)
+ end
+
+ args << val
+ end
+
+ previous = @last_element
+ next_element = klass.send(:new, *args)
+ next_element.do_validate = @do_validate
+ setter = ""
+ setter << "#{klass.required_prefix}_" if klass.required_prefix
+ setter << "#{tag_name}="
+ @last_element.send(setter, next_element)
+ @last_element = next_element
+ @proc_stack.push Proc.new { |text, tags|
+ p @last_element.class if $DEBUG
+ @last_element.content = text if klass.have_content?
+ @last_element.validate_for_stream(tags) if @do_validate
+ @last_element = previous
+ }
+ end
+
+ end
+
+ unless const_defined? :AVAILABLE_PARSERS
+ AVAILABLE_PARSERS = [
+ "rss/xmlparser",
+ "rss/xmlscanner",
+ "rss/rexmlparser",
+ ]
+ end
+
+ loaded = false
+ AVAILABLE_PARSERS.each do |parser|
+ begin
+ require parser
+ loaded = true
+ break
+ rescue LoadError
+ end
+ end
+
+ unless loaded
+ raise XMLParserNotFound
+ end
+end
+
diff --git a/lib/rss/rexmlparser.rb b/lib/rss/rexmlparser.rb
new file mode 100644
index 000000000..b3d801597
--- /dev/null
+++ b/lib/rss/rexmlparser.rb
@@ -0,0 +1,43 @@
+require "rexml/document"
+require "rexml/streamlistener"
+
+/\A(\d+)\.(\d+).\d+\z/ =~ REXML::Version
+if $1.to_i < 2 or ($1.to_i == 2 and $2.to_i < 5)
+ raise LoadError
+end
+
+module RSS
+
+ class Parser < BaseParser
+
+ private
+ def _parse
+ begin
+ REXML::Document.parse_stream(@rss, @listener)
+ rescue RuntimeError => e
+ raise NotWellFormedError.new{e.message}
+ rescue REXML::ParseException => e
+ context = e.context
+ line = context[0] if context
+ raise NotWellFormedError.new(line){e.message}
+ end
+ end
+
+ end
+
+ class Listener < BaseListener
+
+ include REXML::StreamListener
+ include ListenerMixin
+
+
+ def xmldecl(version, encoding, standalone)
+ super
+ # Encoding is converted to UTF-8 when REXML parse XML.
+ @encoding = 'UTF-8'
+ end
+
+ alias_method(:cdata, :text)
+ end
+
+end
diff --git a/lib/rss/rss.rb b/lib/rss/rss.rb
new file mode 100644
index 000000000..0acf7803e
--- /dev/null
+++ b/lib/rss/rss.rb
@@ -0,0 +1,536 @@
+require "time"
+
+require "rss/utils"
+require "rss/converter"
+
+module RSS
+
+ VERSION = "0.0.7"
+
+ class Error < StandardError; end
+
+ class OverlappedPrefixError < Error
+ attr_reader :prefix
+ def initialize(prefix)
+ @prefix = prefix
+ end
+ end
+
+ class InvalidRSSError < Error; end
+
+ class MissingTagError < InvalidRSSError
+ attr_reader :tag, :parent
+ def initialize(tag, parent)
+ @tag, @parent = tag, parent
+ super("tag <#{tag}> is missing in tag <#{parent}>")
+ end
+ end
+
+ class TooMuchTagError < InvalidRSSError
+ attr_reader :tag, :parent
+ def initialize(tag, parent)
+ @tag, @parent = tag, parent
+ super("tag <#{tag}> is too much in tag <#{parent}>")
+ end
+ end
+
+ class MissingAttributeError < InvalidRSSError
+ attr_reader :tag, :attribute
+ def initialize(tag, attribute)
+ @tag, @attribute = tag, attribute
+ super("attribute <#{attribute}> is missing in tag <#{tag}>")
+ end
+ end
+
+ class UnknownTagError < InvalidRSSError
+ attr_reader :tag, :uri
+ def initialize(tag, uri)
+ @tag, @uri = tag, uri
+ super("tag <#{tag}> is unknown in namespace specified by uri <#{uri}>")
+ end
+ end
+
+ class NotExceptedTagError < InvalidRSSError
+ attr_reader :tag, :parent
+ def initialize(tag, parent)
+ @tag, @parent = tag, parent
+ super("tag <#{tag}> is not expected in tag <#{parent}>")
+ end
+ end
+
+ class NotAvailableValueError < InvalidRSSError
+ attr_reader :tag, :value
+ def initialize(tag, value)
+ @tag, @value = tag, value
+ super("value <#{value}> of tag <#{tag}> is not available.")
+ end
+ end
+
+ class UnknownConversionMethodError < Error
+ attr_reader :to, :from
+ def initialize(to, from)
+ @to = from
+ @from = from
+ super("can't convert to #{to} from #{from}.")
+ end
+ end
+ # for backward compatibility
+ UnknownConvertMethod = UnknownConversionMethodError
+
+ class ConversionError < Error
+ attr_reader :string, :to, :from
+ def initialize(string, to, from)
+ @string = string
+ @to = from
+ @from = from
+ super("can't convert #{@string} to #{to} from #{from}.")
+ end
+ end
+
+ module BaseModel
+
+ include Utils
+
+ def install_have_child_element(name)
+ attr_accessor name
+ install_element(name) do |n, elem_name|
+ <<-EOC
+ if @#{n}
+ "\#{indent}\#{@#{n}.to_s(convert)}"
+ else
+ ''
+ end
+EOC
+ end
+ end
+ alias_method(:install_have_attribute_element, :install_have_child_element)
+
+ def install_have_children_element(name, postfix="s")
+ def_children_accessor(name, postfix)
+ add_have_children_element(name)
+ install_element(name, postfix) do |n, elem_name|
+ <<-EOC
+ rv = ''
+ @#{n}.each do |x|
+ rv << "\#{indent}\#{x.to_s(convert)}"
+ end
+ rv
+EOC
+ end
+ end
+
+ def install_text_element(name)
+ self::ELEMENTS << name
+ attr_writer name
+ convert_attr_reader name
+ install_element(name) do |n, elem_name|
+ <<-EOC
+ if @#{n}
+ rv = "\#{indent}<#{elem_name}>"
+ value = html_escape(@#{n})
+ if convert and @converter
+ rv << @converter.convert(value)
+ else
+ rv << value
+ end
+ rv << "</#{elem_name}>"
+ rv
+ else
+ ''
+ end
+EOC
+ end
+ end
+
+ def install_date_element(name, type, disp_name=name)
+ self::ELEMENTS << name
+
+ # accessor
+ convert_attr_reader name
+ module_eval(<<-EOC, *get_file_and_line_from_caller(2))
+ def #{name}=(new_value)
+ if new_value.kind_of?(Time)
+ @#{name} = new_value
+ else
+ if @do_validate
+ begin
+ @#{name} = Time.send('#{type}', new_value)
+ rescue ArgumentError
+ raise NotAvailableValueError.new('#{disp_name}', new_value)
+ end
+ elsif /\\A\\s*\\z/ !~ new_value.to_s
+ @#{name} = Time.parse(new_value)
+ else
+ @#{name} = nil
+ end
+ end
+
+ # Is it need?
+ if @#{name}
+ class << @#{name}
+ alias_method(:_to_s, :to_s) unless respond_to?(:_to_s)
+ alias_method(:to_s, :#{type})
+ end
+ end
+
+ end
+EOC
+
+ install_element(name) do |n, elem_name|
+ <<-EOC
+ if @#{n}
+ rv = "\#{indent}<#{elem_name}>"
+ value = html_escape(@#{n}.#{type})
+ if convert and @converter
+ rv << @converter.convert(value)
+ else
+ rv << value
+ end
+ rv << "</#{elem_name}>"
+ rv
+ else
+ ''
+ end
+EOC
+ end
+
+ end
+
+ private
+ def install_element(name, postfix="")
+ elem_name = name.sub('_', ':')
+ module_eval(<<-EOC, *get_file_and_line_from_caller(2))
+ def #{name}_element#{postfix}(convert=true, indent='')
+ #{yield(name, elem_name)}
+ end
+ private :#{name}_element#{postfix}
+EOC
+ end
+
+ def convert_attr_reader(*attrs)
+ attrs.each do |attr|
+ attr = attr.id2name if attr.kind_of?(Integer)
+ module_eval(<<-EOC, *get_file_and_line_from_caller(2))
+ def #{attr}
+ if @converter
+ @converter.convert(@#{attr})
+ else
+ @#{attr}
+ end
+ end
+EOC
+ end
+ end
+
+ def def_children_accessor(accessor_name, postfix="s")
+ module_eval(<<-EOC, *get_file_and_line_from_caller(2))
+ def #{accessor_name}#{postfix}
+ @#{accessor_name}
+ end
+
+ def #{accessor_name}(*args)
+ if args.empty?
+ @#{accessor_name}.first
+ else
+ @#{accessor_name}.send("[]", *args)
+ end
+ end
+
+ def #{accessor_name}=(*args)
+ if args.size == 1
+ @#{accessor_name}.push(args[0])
+ else
+ @#{accessor_name}.send("[]=", *args)
+ end
+ end
+ alias_method(:set_#{accessor_name}, :#{accessor_name}=)
+EOC
+ end
+
+ end
+
+ URI = "http://purl.org/rss/1.0/"
+
+ class Element
+
+ extend BaseModel
+ include Utils
+
+ class << self
+
+ def inherited(klass)
+ klass.module_eval(<<-EOC)
+ public
+
+ TAG_NAME = name.split('::').last.downcase
+
+
+ @@must_call_validators = {::RSS::URI => ''}
+
+ def self.must_call_validators
+ @@must_call_validators
+ end
+
+ def self.install_must_call_validator(prefix, uri)
+ @@must_call_validators[uri] = prefix
+ end
+
+ @@model = []
+
+ def self.model
+ @@model
+ end
+
+ def self.install_model(tag, occurs=nil)
+ if m = @@model.find {|t, o| t == tag}
+ m[1] = occurs
+ else
+ @@model << [tag, occurs]
+ end
+ end
+
+ @@get_attributes = []
+
+ def self.get_attributes()
+ @@get_attributes
+ end
+
+ def self.install_get_attribute(name, uri, required=true)
+ attr_writer name
+ convert_attr_reader name
+ @@get_attributes << [name, uri, required]
+ end
+
+ @@have_content = false
+
+ def self.content_setup
+ attr_writer :content
+ convert_attr_reader :content
+ @@have_content = true
+ end
+
+ def self.have_content?
+ @@have_content
+ end
+
+ @@have_children_elements = []
+
+ def self.have_children_elements
+ @@have_children_elements
+ end
+
+ def self.add_have_children_element(variable_name)
+ @@have_children_elements << variable_name
+ end
+
+ EOC
+ end
+
+ def required_prefix
+ nil
+ end
+
+ def required_uri
+ nil
+ end
+
+ def install_ns(prefix, uri)
+ if self::NSPOOL.has_key?(prefix)
+ raise OverlappedPrefixError.new(prefix)
+ end
+ self::NSPOOL[prefix] = uri
+ end
+
+ end
+
+ attr_accessor :do_validate
+
+ def initialize(do_validate=true)
+ @do_validate = do_validate
+ initialize_have_children_elements
+ end
+
+ def tag_name
+ self.class::TAG_NAME
+ end
+
+ def converter=(converter)
+ @converter = converter
+ children.each do |child|
+ child.converter = converter unless child.nil?
+ end
+ end
+
+ def validate
+ validate_attribute
+ __validate
+ end
+
+ def validate_for_stream(tags)
+ __validate(tags, false)
+ end
+
+ private
+ def initialize_have_children_elements
+ self.class.have_children_elements.each do |variable_name|
+ instance_eval("@#{variable_name} = []")
+ end
+ end
+
+ # not String class children.
+ def children
+ []
+ end
+
+ # default #validate() argument.
+ def _tags
+ []
+ end
+
+ def _attrs
+ []
+ end
+
+ def __validate(tags=_tags, recursive=true)
+ if recursive
+ children.compact.each do |child|
+ child.validate
+ end
+ end
+ must_call_validators = self.class::must_call_validators
+ tags = tag_filter(tags.dup)
+ p tags if $DEBUG
+ self.class::NSPOOL.each do |prefix, uri|
+ if tags.has_key?(uri) and !must_call_validators.has_key?(uri)
+ meth = "#{prefix}_validate"
+ send(meth, tags[uri]) if respond_to?(meth, true)
+ end
+ end
+ must_call_validators.each do |uri, prefix|
+ send("#{prefix}_validate", tags[uri])
+ end
+ end
+
+ def validate_attribute
+ _attrs.each do |a_name, required|
+ if required and send(a_name).nil?
+ raise MissingAttributeError.new(self.class::TAG_NAME, a_name)
+ end
+ end
+ end
+
+ def other_element(convert, indent='')
+ rv = ''
+ private_methods.each do |meth|
+ if /\A([^_]+)_[^_]+_elements?\z/ =~ meth and
+ self.class::NSPOOL.has_key?($1)
+ res = send(meth, convert)
+ rv << "#{indent}#{res}\n" if /\A\s*\z/ !~ res
+ end
+ end
+ rv
+ end
+
+ def _validate(tags, model=self.class.model)
+ count = 1
+ do_redo = false
+ not_shift = false
+ tag = nil
+
+ model.each_with_index do |elem, i|
+
+ if $DEBUG
+ p "before"
+ p tags
+ p elem
+ end
+
+ if not_shift
+ not_shift = false
+ else
+ begin
+ tag = tags.shift
+ rescue NameError
+ end
+ end
+
+ if $DEBUG
+ p "mid"
+ p count
+ end
+
+ case elem[1]
+ when '?'
+ if count > 2
+ raise TooMuchTagError.new(elem[0], tag_name)
+ else
+ if elem[0] == tag
+ do_redo = true
+ else
+ not_shift = true
+ end
+ end
+ when '*'
+ if elem[0] == tag
+ do_redo = true
+ else
+ not_shift = true
+ end
+ when '+'
+ if elem[0] == tag
+ do_redo = true
+ else
+ if count > 1
+ not_shift = true
+ else
+ raise MissingTagError.new(elem[0], tag_name)
+ end
+ end
+ else
+ if elem[0] == tag
+ begin
+ if model[i+1][0] != elem[0] and tags.first == elem[0]
+ raise TooMuchTagError.new(elem[0], tag_name)
+ end
+ rescue NameError # for model[i+1][0] and tags.first
+ end
+ else
+ raise MissingTagError.new(elem[0], tag_name)
+ end
+ end
+
+ if $DEBUG
+ p "after"
+ p not_shift
+ p do_redo
+ p tag
+ end
+
+ if do_redo
+ do_redo = false
+ count += 1
+ redo
+ else
+ count = 1
+ end
+
+ end
+
+ if !tags.nil? and !tags.empty?
+ raise NotExceptedTagError.new(tag, tag_name)
+ end
+
+ end
+
+ def tag_filter(tags)
+ rv = {}
+ tags.each do |tag|
+ rv[tag[0]] = [] unless rv.has_key?(tag[0])
+ rv[tag[0]].push(tag[1])
+ end
+ rv
+ end
+
+ end
+
+end
diff --git a/lib/rss/syndication.rb b/lib/rss/syndication.rb
new file mode 100644
index 000000000..74bfbac8e
--- /dev/null
+++ b/lib/rss/syndication.rb
@@ -0,0 +1,81 @@
+require "rss/1.0"
+
+module RSS
+
+ SY_PREFIX = 'sy'
+ SY_URI = "http://purl.org/rss/1.0/modules/syndication/"
+
+ RDF.install_ns(SY_PREFIX, SY_URI)
+
+ module SyndicationModel
+
+ extend BaseModel
+
+ ELEMENTS = []
+
+ %w(updatePeriod updateFrequency).each do |x|
+ install_text_element("#{SY_PREFIX}_#{x}")
+ end
+
+ %w(updateBase).each do |x|
+ install_date_element("#{SY_PREFIX}_#{x}", 'iso8601', x)
+ end
+
+ def sy_validate(tags)
+ counter = {}
+ ELEMENTS.each do |x|
+ counter[x] = 0
+ end
+
+ tags.each do |tag|
+ key = "#{SY_PREFIX}_#{tag}"
+ raise UnknownTagError.new(tag, SY_URI) unless counter.has_key?(key)
+ counter[key] += 1
+ raise TooMuchTagError.new(tag, tag_name) if counter[key] > 1
+ end
+ end
+
+
+ alias_method(:_sy_updatePeriod=, :sy_updatePeriod=)
+ def sy_updatePeriod=(new_value)
+ new_value = new_value.strip
+ validate_sy_updatePeriod(new_value) if @do_validate
+ self._sy_updatePeriod = new_value
+ end
+
+ alias_method(:_sy_updateFrequency=, :sy_updateFrequency=)
+ def sy_updateFrequency=(new_value)
+ new_value = new_value.strip
+ validate_sy_updateFrequency(new_value) if @do_validate
+ self._sy_updateFrequency = new_value.to_i
+ end
+
+ private
+ SY_UPDATEPERIOD_AVAILABLE_VALUES = %w(hourly daily weekly monthly yearly)
+ def validate_sy_updatePeriod(value)
+ unless SY_UPDATEPERIOD_AVAILABLE_VALUES.include?(value)
+ raise NotAvailableValueError.new("updatePeriod", value)
+ end
+ end
+
+ SY_UPDATEFREQUENCY_AVAILABLE_RE = /\A\s*\+?\d+\s*\z/
+ def validate_sy_updateFrequency(value)
+ if SY_UPDATEFREQUENCY_AVAILABLE_RE !~ value
+ raise NotAvailableValueError.new("updateFrequency", value)
+ end
+ end
+
+ end
+
+ class RDF
+ class Channel; include SyndicationModel; end
+ end
+
+ if const_defined? :BaseListener
+ prefix_size = SY_PREFIX.size + 1
+ SyndicationModel::ELEMENTS.each do |x|
+ BaseListener.install_get_text_element(x[prefix_size..-1], SY_URI, "#{x}=")
+ end
+ end
+
+end
diff --git a/lib/rss/taxonomy.rb b/lib/rss/taxonomy.rb
new file mode 100644
index 000000000..5d3dd5bf8
--- /dev/null
+++ b/lib/rss/taxonomy.rb
@@ -0,0 +1,32 @@
+# Experimental
+
+require "rss/1.0"
+
+module RSS
+
+ TAXO_PREFIX = "taxo"
+ TAXO_NS = "http://purl.org/rss/1.0/modules/taxonomy/"
+
+ Element.install_ns(TAXO_PREFIX, TAXO_NS)
+
+ TAXO_ELEMENTS = []
+
+ %w(link).each do |x|
+ if const_defined? :Listener
+ Listener.install_get_text_element(x, TAXO_NS, "#{TAXO_PREFIX}_#{x}=")
+ end
+ TAXO_ELEMENTS << "#{TAXO_PREFIX}_#{x}"
+ end
+
+ module TaxonomyModel
+ attr_writer *%w(title description creator subject publisher
+ contributor date format identifier source
+ language relation coverage rights).collect{|x| "#{TAXO_PREFIX}_#{x}"}
+ end
+
+ class Channel; extend TaxonomyModel; end
+ class Item; extend TaxonomyModel; end
+ class Image; extend TaxonomyModel; end
+ class TextInput; extend TaxonomyModel; end
+
+end
diff --git a/lib/rss/trackback.rb b/lib/rss/trackback.rb
new file mode 100644
index 000000000..5c7ca777b
--- /dev/null
+++ b/lib/rss/trackback.rb
@@ -0,0 +1,235 @@
+# ATTENSION:
+# TrackBack handling API MUST be CHANGED!!!!
+
+require 'rss/1.0'
+require 'rss/2.0'
+
+module RSS
+
+ TRACKBACK_PREFIX = 'trackback'
+ TRACKBACK_URI = 'http://madskills.com/public/xml/rss/module/trackback/'
+
+ RDF.install_ns(TRACKBACK_PREFIX, TRACKBACK_URI)
+ Rss.install_ns(TRACKBACK_PREFIX, TRACKBACK_URI)
+
+ module BaseTrackBackModel
+ def trackback_validate(tags)
+ raise unless @do_validate
+ counter = {}
+ %w(ping about).each do |x|
+ counter["#{TRACKBACK_PREFIX}_#{x}"] = 0
+ end
+
+ tags.each do |tag|
+ key = "#{TRACKBACK_PREFIX}_#{tag}"
+ raise UnknownTagError.new(tag, TRACKBACK_URI) unless counter.has_key?(key)
+ counter[key] += 1
+ if tag != "about" and counter[key] > 1
+ raise TooMuchTagError.new(tag, tag_name)
+ end
+ end
+
+ if counter["#{TRACKBACK_PREFIX}_ping"].zero? and
+ counter["#{TRACKBACK_PREFIX}_about"].nonzero?
+ raise MissingTagError.new("#{TRACKBACK_PREFIX}:ping", tag_name)
+ end
+ end
+ end
+
+ module TrackBackModel10
+ extend BaseModel
+ include BaseTrackBackModel
+
+ def self.append_features(klass)
+ super
+
+ unless klass.class == Module
+ %w(ping).each do |x|
+ klass.install_have_child_element("#{TRACKBACK_PREFIX}_#{x}")
+ end
+
+ %w(about).each do |x|
+ klass.install_have_children_element("#{TRACKBACK_PREFIX}_#{x}")
+ end
+ end
+ end
+
+ class Ping < Element
+ include RSS10
+
+ class << self
+
+ def required_prefix
+ TRACKBACK_PREFIX
+ end
+
+ def required_uri
+ TRACKBACK_URI
+ end
+
+ end
+
+ [
+ ["resource", ::RSS::RDF::URI, true]
+ ].each do |name, uri, required|
+ install_get_attribute(name, uri, required)
+ end
+
+ def initialize(resource=nil)
+ super()
+ @resource = resource
+ end
+
+ def to_s(convert=true)
+ if @resource
+ rv = %Q!<#{TRACKBACK_PREFIX}:ping #{::RSS::RDF::PREFIX}:resource="#{h @resource}"/>!
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ else
+ ''
+ end
+ end
+
+ private
+ def _attrs
+ [
+ ["resource", true],
+ ]
+ end
+
+ end
+
+ class About < Element
+ include RSS10
+
+ class << self
+
+ def required_prefix
+ TRACKBACK_PREFIX
+ end
+
+ def required_uri
+ TRACKBACK_URI
+ end
+
+ end
+
+ [
+ ["resource", ::RSS::RDF::URI, true]
+ ].each do |name, uri, required|
+ install_get_attribute(name, uri, required)
+ end
+
+ def initialize(resource=nil)
+ super()
+ @resource = resource
+ end
+
+ def to_s(convert=true)
+ if @resource
+ rv = %Q!<#{TRACKBACK_PREFIX}:about #{::RSS::RDF::PREFIX}:resource="#{h @resource}"/>!
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ else
+ ''
+ end
+ end
+
+ private
+ def _attrs
+ [
+ ["resource", true],
+ ]
+ end
+
+ end
+ end
+
+ module TrackBackModel20
+ include BaseTrackBackModel
+ extend BaseModel
+
+ def self.append_features(klass)
+ super
+
+ unless klass.class == Module
+ %w(ping).each do |x|
+ klass.install_have_child_element("#{TRACKBACK_PREFIX}_#{x}")
+ end
+
+ %w(about).each do |x|
+ klass.install_have_children_element("#{TRACKBACK_PREFIX}_#{x}")
+ end
+ end
+ end
+
+ class Ping < Element
+ include RSS09
+
+ content_setup
+
+ class << self
+
+ def required_prefix
+ TRACKBACK_PREFIX
+ end
+
+ def required_uri
+ TRACKBACK_URI
+ end
+
+ end
+
+ def to_s(convert=true)
+ if @content
+ rv = %Q!<#{TRACKBACK_PREFIX}:ping>#{h @content}</#{TRACKBACK_PREFIX}:ping>!
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ else
+ ''
+ end
+ end
+
+ end
+
+ class About < Element
+ include RSS09
+
+ content_setup
+
+ class << self
+
+ def required_prefix
+ TRACKBACK_PREFIX
+ end
+
+ def required_uri
+ TRACKBACK_URI
+ end
+
+ end
+
+ def to_s(convert=true)
+ if @content
+ rv = %Q!<#{TRACKBACK_PREFIX}:about>#{h @content}</#{TRACKBACK_PREFIX}:about>!
+ rv = @converter.convert(rv) if convert and @converter
+ rv
+ else
+ ''
+ end
+ end
+
+ end
+ end
+
+ class RDF
+ class Item; include TrackBackModel10; end
+ end
+
+ class Rss
+ class Channel
+ class Item; include TrackBackModel20; end
+ end
+ end
+
+end
diff --git a/lib/rss/utils.rb b/lib/rss/utils.rb
new file mode 100644
index 000000000..32940cf2a
--- /dev/null
+++ b/lib/rss/utils.rb
@@ -0,0 +1,19 @@
+module RSS
+
+ module Utils
+
+ def get_file_and_line_from_caller(i=0)
+ tmp = caller[i].split(':')
+ line = tmp.pop.to_i
+ file = tmp.join(':')
+ [file, line]
+ end
+
+ def html_escape(s)
+ s.to_s.gsub(/&/, "&amp;").gsub(/\"/, "&quot;").gsub(/>/, "&gt;").gsub(/</, "&lt;")
+ end
+ alias h html_escape
+
+ end
+
+end
diff --git a/lib/rss/xmlparser.rb b/lib/rss/xmlparser.rb
new file mode 100644
index 000000000..32061805a
--- /dev/null
+++ b/lib/rss/xmlparser.rb
@@ -0,0 +1,69 @@
+begin
+ require "xml/encoding-ja"
+rescue LoadError
+ require "xmlencoding-ja"
+ if defined?(Kconv)
+ module XMLEncoding_ja
+ class SJISHandler
+ include Kconv
+ end
+ end
+ end
+end
+
+module RSS
+
+ class XMLParser < ::XML::Parser
+
+ include XML::Encoding_ja
+
+ def listener=(listener)
+ @listener = listener
+ end
+
+ def startElement(name, attrs)
+ @listener.tag_start(name, attrs)
+ end
+
+ def endElement(name)
+ @listener.tag_end(name)
+ end
+
+ def character(data)
+ @listener.text(data)
+ end
+
+ def xmlDecl(version, encoding, standalone)
+ @listener.xmldecl(version, encoding, standalone == 1)
+ end
+
+ end
+
+ class Parser < BaseParser
+
+ private
+ def _parse
+ begin
+ parser = XMLParser.new
+ parser.listener = @listener
+ parser.parse(@rss)
+ rescue XMLParserError => e
+ raise NotWellFormedError.new(parser.line){e.message}
+ end
+ end
+
+ end
+
+ class Listener < BaseListener
+
+ include ListenerMixin
+
+ def xmldecl(version, encoding, standalone)
+ super
+ # Encoding is converted to UTF-8 when XMLParser parses XML.
+ @encoding = 'UTF-8'
+ end
+
+ end
+
+end
diff --git a/lib/rss/xmlscanner.rb b/lib/rss/xmlscanner.rb
new file mode 100644
index 000000000..81dae96df
--- /dev/null
+++ b/lib/rss/xmlscanner.rb
@@ -0,0 +1,97 @@
+require 'xmlscan/scanner'
+
+module RSS
+
+ class Parser < BaseParser
+
+ private
+ def _parse
+ begin
+ XMLScan::XMLScanner.new(@listener).parse(@rss)
+ rescue XMLScan::Error => e
+ raise NotWellFormedError.new(e.lineno){e.message}
+ end
+ end
+
+ end
+
+ class Listener < BaseListener
+
+ include XMLScan::Visitor
+ include ListenerMixin
+
+ ENTITIES = {
+ 'lt' => '<',
+ 'gt' => '>',
+ 'amp' => '&',
+ 'quot' => '"',
+ 'apos' => '\''
+ }
+
+ def on_xmldecl_version(str)
+ @version = str
+ end
+
+ def on_xmldecl_encoding(str)
+ @encoding = str
+ end
+
+ def on_xmldecl_standalone(str)
+ @standalone = str
+ end
+
+ def on_xmldecl_end
+ xmldecl(@version, @encoding, @standalone)
+ end
+
+ alias_method(:on_chardata, :text)
+ alias_method(:on_cdata, :text)
+
+ def on_etag(name)
+ tag_end(name)
+ end
+
+ def on_entityref(ref)
+ text(ENTITIES[ref])
+ end
+
+ def on_charref(code)
+ text([code].pack('U'))
+ end
+
+ alias_method(:on_charref_hex, :on_charref)
+
+ def on_stag(name)
+ @attrs = {}
+ end
+
+ def on_attribute(name)
+ @attrs[name] = @current_attr = ''
+ end
+
+ def on_attr_value(str)
+ @current_attr << str
+ end
+
+ def on_attr_entityref(ref)
+ @current_attr << ENTITIES[ref]
+ end
+
+ def on_attr_charref(code)
+ @current_attr << [code].pack('U')
+ end
+
+ alias_method(:on_attr_charref_hex, :on_attr_charref)
+
+ def on_stag_end(name)
+ tag_start(name, @attrs)
+ end
+
+ def on_stag_end_empty(name)
+ tag_start(name, @attrs)
+ tag_end(name)
+ end
+
+ end
+
+end
diff --git a/sample/rss/articles.rss b/sample/rss/articles.rss
new file mode 100644
index 000000000..ac40ce3a6
--- /dev/null
+++ b/sample/rss/articles.rss
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<rdf:RDF
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns="http://purl.org/rss/1.0/"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
+ xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/"
+ xmlns:syn="http://purl.org/rss/1.0/modules/syndication/"
+>
+
+<channel rdf:about="http://slashdot.org/">
+<title>Slashdot: Articles</title>
+<link>http://slashdot.org/</link>
+<description>News for nerds, stuff that matters</description>
+<dc:language>en-us</dc:language>
+<dc:rights>Copyright &amp;copy; 1997-2001, OSDN</dc:rights>
+<dc:date>2003-03-16T06:13:51+00:00</dc:date>
+<dc:publisher>OSDN</dc:publisher>
+<dc:creator>pater@slashdot.org</dc:creator>
+<dc:subject>Technology</dc:subject>
+<syn:updatePeriod>hourly</syn:updatePeriod>
+<syn:updateFrequency>1</syn:updateFrequency>
+<syn:updateBase>1970-01-01T00:00+00:00</syn:updateBase>
+<items>
+ <rdf:Seq>
+ <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/03/16/0414225" />
+ <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/03/16/0131253" />
+ <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/03/15/2233217" />
+ <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/03/15/2059226" />
+ <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/03/15/1734207" />
+ <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/03/15/1711213" />
+ <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/03/15/162202" />
+ <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/03/15/147223" />
+ <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/03/15/0237232" />
+ <rdf:li rdf:resource="http://slashdot.org/article.pl?sid=03/03/15/1328203" />
+ </rdf:Seq>
+</items>
+<image rdf:resource="http://images.slashdot.org/topics/topicslashdot.gif" />
+<textinput rdf:resource="http://slashdot.org/search.pl" />
+</channel>
+
+<image rdf:about="http://images.slashdot.org/topics/topicslashdot.gif">
+<title>Slashdot: Articles</title>
+<url>http://images.slashdot.org/topics/topicslashdot.gif</url>
+<link>http://slashdot.org/</link>
+</image>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/03/16/0414225">
+<title>Live Vorbis Streams Over 802.11b From SXSW.com</title>
+<link>http://slashdot.org/article.pl?sid=03/03/16/0414225</link>
+<description>chupacabra writes "SXSW.com in Austin, Texas has a group of computers in various music venues around town. The ices/icecast stream is sent over 802.11 to a ...</description>
+<dc:creator>timothy</dc:creator>
+<dc:subject>wireless</dc:subject>
+<dc:date>2003-03-16T04:19:46+00:00</dc:date>
+<slash:department>decent-exposure</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>50</slash:comments>
+<slash:hitparade>50,43,33,18,10,4,1</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/03/16/0131253">
+<title>Music Companies Bemoan New High-Cap Portables</title>
+<link>http://slashdot.org/article.pl?sid=03/03/16/0131253</link>
+<description>An anonymous reader writes "New Scientist reports: 'The music industry this week condemned the launch of two recording systems that will let people copy ...</description>
+<dc:creator>timothy</dc:creator>
+<dc:subject>hardware</dc:subject>
+<dc:date>2003-03-16T02:09:34+00:00</dc:date>
+<slash:department>that's-a-lot-of-lake-woebegone-days</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>184</slash:comments>
+<slash:hitparade>184,170,134,89,41,27,23</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/03/15/2233217">
+<title>New Social-Network Mapping Tools Compared</title>
+<link>http://slashdot.org/article.pl?sid=03/03/15/2233217</link>
+<description>Roland Piquepaille writes "There are many new visualization tools around us which try to map our social networks. In this column, I examined Inflow, a ...</description>
+<dc:creator>timothy</dc:creator>
+<dc:subject>software</dc:subject>
+<dc:date>2003-03-15T23:16:26+00:00</dc:date>
+<slash:department>useful-in-high-school-sex-ed-class</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>65</slash:comments>
+<slash:hitparade>65,62,48,32,14,11,8</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/03/15/2059226">
+<title>AMD Opteron Due In April</title>
+<link>http://slashdot.org/article.pl?sid=03/03/15/2059226</link>
+<description>updog writes "Here's an article from Infoworld claiming that the new 64-bit AMD Opteron is ready to launch on April 22. Some of the notable features of the new ...</description>
+<dc:creator>timothy</dc:creator>
+<dc:subject>amd</dc:subject>
+<dc:date>2003-03-15T21:07:45+00:00</dc:date>
+<slash:department>grain-of-salt-please</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>244</slash:comments>
+<slash:hitparade>244,227,174,119,38,22,18</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/03/15/1734207">
+<title>Clear Case Roundup</title>
+<link>http://slashdot.org/article.pl?sid=03/03/15/1734207</link>
+<description>The Cheat writes "Interested in making your computer the envy of all the other computers on the block? What visitors to oooh and ahhh when they enter your ...</description>
+<dc:creator>CowboyNeal</dc:creator>
+<dc:subject>hardware</dc:subject>
+<dc:date>2003-03-15T19:48:26+00:00</dc:date>
+<slash:department>classy-chassis</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>169</slash:comments>
+<slash:hitparade>169,163,115,68,29,18,14</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/03/15/1711213">
+<title>Forbes on Lessig and Eldred</title>
+<link>http://slashdot.org/article.pl?sid=03/03/15/1711213</link>
+<description>scubacuda writes "In the Forbes editorial, Fact and Comment , Steve Forbes voices his support for Lessig and the Eldred case: 'Maybe Congress should just be ...</description>
+<dc:creator>timothy</dc:creator>
+<dc:subject>money</dc:subject>
+<dc:date>2003-03-15T18:40:21+00:00</dc:date>
+<slash:department>capitalist-tool</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>189</slash:comments>
+<slash:hitparade>189,183,158,115,44,30,19</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/03/15/162202">
+<title>Modular Home Network PVR at CeBIT</title>
+<link>http://slashdot.org/article.pl?sid=03/03/15/162202</link>
+<description>Mackus Daddius writes "This ought to give the MPAA a conniption: 'The Lancaster system is modular, consisting of a TV tuner (analogue or digital), a hard disk ...</description>
+<dc:creator>CowboyNeal</dc:creator>
+<dc:subject>tv</dc:subject>
+<dc:date>2003-03-15T17:37:55+00:00</dc:date>
+<slash:department>different-kinds-of-tv-networks</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>75</slash:comments>
+<slash:hitparade>75,63,49,34,12,9,8</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/03/15/147223">
+<title>EA, Eidos Have No Plans for Xbox Live</title>
+<link>http://slashdot.org/article.pl?sid=03/03/15/147223</link>
+<description>News for nerds writes "Eidos, maker of Tomb Raider, said it doesn't plan to make games for Xbox Live because Microsoft controls the system and manages ...</description>
+<dc:creator>CowboyNeal</dc:creator>
+<dc:subject>games</dc:subject>
+<dc:date>2003-03-15T15:24:48+00:00</dc:date>
+<slash:department>getting-connected</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>275</slash:comments>
+<slash:hitparade>275,266,192,109,45,26,17</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/03/15/0237232">
+<title>Build Your Own Sherman Tank</title>
+<link>http://slashdot.org/article.pl?sid=03/03/15/0237232</link>
+<description>absolut.evil writes "OK, so admittedly it is only 1/5th scale, but still pretty cool.. especially if you're a kid. The thing comes complete with working ...</description>
+<dc:creator>Hemos</dc:creator>
+<dc:subject>toys</dc:subject>
+<dc:date>2003-03-15T14:36:49+00:00</dc:date>
+<slash:department>constructing-the-universe</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>216</slash:comments>
+<slash:hitparade>216,206,122,70,36,21,16</slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.org/article.pl?sid=03/03/15/1328203">
+<title>Sony's Cashless Smart Card Catching on in Japan</title>
+<link>http://slashdot.org/article.pl?sid=03/03/15/1328203</link>
+<description>Spasemunki writes "The New York Times reports here on the success in Japan of an RF-based, cash replacement smart card developed by Sony. Used primarily by ...</description>
+<dc:creator>timothy</dc:creator>
+<dc:subject>money</dc:subject>
+<dc:date>2003-03-15T13:36:32+00:00</dc:date>
+<slash:department>are-they-tradeable</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>196</slash:comments>
+<slash:hitparade>196,192,152,77,27,15,10</slash:hitparade>
+</item>
+
+<textinput rdf:about="http://slashdot.org/search.pl">
+<title>Search Slashdot</title>
+<description>Search Slashdot stories</description>
+<name>query</name>
+<link>http://slashdot.org/search.pl</link>
+</textinput>
+
+</rdf:RDF> \ No newline at end of file
diff --git a/sample/rss/content.xml b/sample/rss/content.xml
new file mode 100644
index 000000000..5eb192ec7
--- /dev/null
+++ b/sample/rss/content.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<rdf:RDF
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:content="http://purl.org/rss/1.0/modules/content/"
+ xmlns="http://purl.org/rss/1.0/"
+>
+
+ <channel rdf:about="http://example.org/rss.rdf">
+ <title>Example Feed</title>
+ <link>http://www.example.org</link>
+ <description>Simply for the purpose of demonstration.</description>
+
+ <items>
+ <rdf:Seq>
+ <rdf:li resource="http://example.org/item/" />
+ </rdf:Seq>
+ </items>
+
+ </channel>
+
+ <item rdf:about="http://example.org/item/">
+ <title>The Example Item</title>
+ <link>http://example.org/item/</link>
+ <content:encoded><![CDATA[<p>What a <em>beautiful</em> day!</p>]]></content:encoded>
+ </item>
+</rdf:RDF>
+
diff --git a/sample/rss/index.rdf.ja b/sample/rss/index.rdf.ja
new file mode 100644
index 000000000..6657abf8d
--- /dev/null
+++ b/sample/rss/index.rdf.ja
@@ -0,0 +1,186 @@
+<?xml version='1.0' encoding='EUC-JP'?>
+<rdf:RDF
+ xmlns="http://purl.org/rss/1.0/"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <channel rdf:about='http://bat/~gallery'>
+ <title>¥È¥Ã¥×</title>
+
+ <link>http://bat/~gallery</link>
+
+ <description>¥®¥ã¥é¥ê¡¼¥È¥Ã¥×</description>
+
+
+ <items>
+ <rdf:Seq>
+ <rdf:li resource="http://bat/~gallery/./momi/paris/%A5%D5%A5%E9%A5%F3%A5%B9%20%20%A5%D1%A5%EA.jpg" />
+
+ <rdf:li resource="http://bat/~gallery/./momi/paris/invalides.jpg" />
+
+ <rdf:li resource="http://bat/~gallery/./momi/paris/tour%2Deffel2.jpg" />
+
+ <rdf:li resource="http://bat/~gallery/./momi/paris/tour%2Deffel3.jpg" />
+
+ <rdf:li resource="http://bat/~gallery/./momi/paris/france_photo2_055.jpg" />
+
+ <rdf:li resource="http://bat/~gallery/./momi/paris/france_photo2_054.jpg" />
+
+ <rdf:li resource="http://bat/~gallery/./momi/paris/tour%2Deffel.jpg" />
+
+ <rdf:li resource="http://bat/~gallery/./wrudgef/SPANGLETRASH/101%2D0133_IMG.JPG" />
+
+ <rdf:li resource="http://bat/~gallery/./wrudgef/SPANGLETRASH/101%2D0137_IMG.JPG" />
+
+ <rdf:li resource="http://bat/~gallery/./wrudgef/SPANGLETRASH/101%2D0136_IMG.JPG" />
+
+ <rdf:li resource="http://bat/~gallery/./wrudgef/SPANGLETRASH/101%2D0134_IMG.JPG" />
+
+ <rdf:li resource="http://bat/~gallery/./wrudgef/BARROWGANG/100%2D0099_IMG.JPG" />
+
+
+
+ </rdf:Seq>
+
+
+ </items>
+
+
+
+ </channel>
+
+
+ <item rdf:about='http://bat/~gallery/./momi/paris/%A5%D5%A5%E9%A5%F3%A5%B9%20%20%A5%D1%A5%EA.jpg'>
+ <title>¥Õ¥é¥ó¥¹ ¥Ñ¥ê</title>
+
+
+ <description></description>
+
+ <dc:date>2003-06-11T00:13:33+09:00</dc:date>
+
+ </item>
+
+ <item rdf:about='http://bat/~gallery/./momi/paris/invalides.jpg'>
+ <title>¶â¤Ô¤«¥É¡¼¥à</title>
+
+
+ <description>¥¢¥ó¥ô¥¡¥ê¥Ã¥É¤È¤¤¤¤¤Þ¤¹¡£·³»öÇîʪ´Û¡¦²òÊü·®¾ÏÇîʪ´Û¡¦¥µ¥ó¡á¥ë¥¤¶µ²ñ¡¢¤½¤·¤Æ¡¢¤¢¤Î¥Ê¥Ý¥ì¥ª¥ó£±À¤¤ÎÊè¤È¤·¤Æ¤Î´é¤â»ý¤Ã¤Æ¤¤¤Þ¤¹¡£</description>
+
+ <dc:date>2003-06-11T00:13:33+09:00</dc:date>
+
+ </item>
+
+ <item rdf:about='http://bat/~gallery/./momi/paris/tour%2Deffel2.jpg'>
+ <title>²¼¤«¤é·ã¼Ì</title>
+
+
+ <description>¥¨¥Ã¥Õ¥§¥ë¤ò²¼¤«¤é¸«¤ë¤È¤³¤ó¤Ê´¶¤¸¤Ç¤¹¡£</description>
+
+ <dc:date>2003-06-11T00:13:33+09:00</dc:date>
+
+ </item>
+
+ <item rdf:about='http://bat/~gallery/./momi/paris/tour%2Deffel3.jpg'>
+ <title>º£Å٤Ͼ夫¤é</title>
+
+
+ <description>¥¨¥Ã¥Õ¥§¥ëÅã¤Ï¡¢£±³¬¡¦£²³¬¤ËÅФ뤳¤È¤¬¤Ç¤­¤Þ¤¹¡£¤³¤ì¤Ï£±³¬¤«¤é¤Î¥·¥ç¥Ã¥È¡£ÃϾ壳£°£í°Ì¤Ç¤·¤ç¤¦¤«¡£¥Ñ¥ê¤¬°ì˾¤Ç¤­¤Þ¤¹¡£</description>
+
+ <dc:date>2003-06-11T00:13:33+09:00</dc:date>
+
+ </item>
+
+ <item rdf:about='http://bat/~gallery/./momi/paris/france_photo2_055.jpg'>
+ <title>¤É¤³¤À¤«¤ï¤«¤ê¤Þ¤¹¤«¡©</title>
+
+
+ <description>¥·¥ã¥ó¥¼¥ê¥¼¤È¸À¤¨¤Ð¤ï¤«¤ê¤Þ¤¹¤è¤Í¡£
+¤³¤Î²èÁü¤¸¤ã¤¿¤À¤ÎÆ»¤Ç¤¹¤¬¡¦¡¦¡¦</description>
+
+ <dc:date>2003-06-11T00:13:33+09:00</dc:date>
+
+ </item>
+
+ <item rdf:about='http://bat/~gallery/./momi/paris/france_photo2_054.jpg'>
+ <title>³®ÀûÌç¤Î¤è¤¦¤Ç¤¹</title>
+
+
+ <description>¥á¥Ã¥«¤Ç¤¹¤«¤é¤Í¤§¡£Â­²¼¤Ï¥í¡¼¥¿¥ê¡¼¤Ç¤¹¡£¤è¤¯¤Ö¤Ä¤«¤é¤Ê¤¤¤â¤Î¤À¤È´¶¿´¤·¤Æ¤·¤Þ¤¤¤Þ¤¹¡£</description>
+
+ <dc:date>2003-06-11T00:13:33+09:00</dc:date>
+
+ </item>
+
+ <item rdf:about='http://bat/~gallery/./momi/paris/tour%2Deffel.jpg'>
+ <title>¥¨¥Ã¥Õ¥§¥ëÅã¤È¤¤¤¦¤ä¤Ä¤Ç¤¹</title>
+
+
+ <description>Å·µ¤°­¤¯¤ÆåºÎ露¤ã¤Ê¤¤¤Ç¤¹¤Í¡£¤Ç¤­¤¿Åö»þ¤Ï¡¢Å´¤Î²ô¤Ë¤«¤Ê¤êÈãȽŪ¤ÊÀ¼¤¬Â¿¤«¤Ã¤¿¤é¤·¤¤¤Ç¤¹¤è¡£º£¤Ï´Ñ¸÷̾½ê¤Ç¤¹¤±¤É¤Í¡£</description>
+
+ <dc:date>2003-06-11T00:13:33+09:00</dc:date>
+
+ </item>
+
+ <item rdf:about='http://bat/~gallery/./wrudgef/SPANGLETRASH/101%2D0133_IMG.JPG'>
+ <title>¥×¥ê¥ó¥ÈȾ¤½¤Ç¥·¥ã¥Ä</title>
+
+
+ <description>¡ï9.800¡¡£Í¡¡¡ã¥Ô¥ó¥¯¡¡¥Ö¥ë¡¼¡¡¥¯¥í¡ä
+ÇØÃæ¤Ë¥È²»µ­¹æ¥×¥ê¥ó¥È¤ÎÆþ¤Ã¤¿¥·¥ã¥Ä¡£
+£Ô¥·¥ã¥Ä¤ä¥¿¥ó¥¯¥È¥Ã¥×¤Î¾å¤Ë±©¿¥¤Ã¤Æ¥í¥Ã¥¯¤Ë·è¤á¤è¤¦¡ª</description>
+
+ <dc:date>2003-06-11T00:12:36+09:00</dc:date>
+
+ </item>
+
+ <item rdf:about='http://bat/~gallery/./wrudgef/SPANGLETRASH/101%2D0137_IMG.JPG'>
+ <title>ñññð¥×¥ê¥ó¥ÈȾ¤½¤Ç¥·¥ã¥Ä</title>
+
+
+ <description>¡ï9.800¡¡£Í¡¡¡ã¥Ü¥ë¥É¡¼¡¡¥°¥ì¥¤¡¡¥¯¥í¡ä
+¥¹¥Ñ¥ó¥°¥ë¤ªÆÀ°Õ¤Î¥Ï¡¼¥É¤Êñññð¥×¥ê¥ó¥È¤Î¥·¥ã¥Ä¡£
+ÇØÃ椬¼çÄ¥¤·¤Þ¤¯¤ê¤Þ¤¹¡£</description>
+
+ <dc:date>2003-06-11T00:12:36+09:00</dc:date>
+
+ </item>
+
+ <item rdf:about='http://bat/~gallery/./wrudgef/SPANGLETRASH/101%2D0136_IMG.JPG'>
+ <title>ñññð¥×¥ê¥ó¥ÈȾ¤½¤Ç¥·¥ã¥Ä</title>
+
+
+ <description>¡ï9.800¡¡£Í¡¡¡ã¥Ü¥ë¥É¡¼¡¡¥°¥ì¥¤¡¡¥¯¥í¡ä
+¥¹¥Ñ¥ó¥°¥ë¤ªÆÀ°Õ¤Î¥Ï¡¼¥É¤Êñññð¥×¥ê¥ó¥È¤Î¥·¥ã¥Ä¡£
+ÇØÃ椬¼çÄ¥¤·¤Þ¤¯¤ê¤Þ¤¹¡£</description>
+
+ <dc:date>2003-06-11T00:12:36+09:00</dc:date>
+
+ </item>
+
+ <item rdf:about='http://bat/~gallery/./wrudgef/SPANGLETRASH/101%2D0134_IMG.JPG'>
+ <title>¥×¥ê¥ó¥ÈȾ¤½¤Ç¥·¥ã¥Ä</title>
+
+
+ <description>¡ï9.800¡¡£Í¡¡¡ã¥Ô¥ó¥¯¡¡¥Ö¥ë¡¼¡¡¥¯¥í¡ä
+ÇØÃæ¤Ë¥È²»µ­¹æ¥×¥ê¥ó¥È¤ÎÆþ¤Ã¤¿¥·¥ã¥Ä¡£
+£Ô¥·¥ã¥Ä¤ä¥¿¥ó¥¯¥È¥Ã¥×¤Î¾å¤Ë±©¿¥¤Ã¤Æ¥í¥Ã¥¯¤Ë·è¤á¤è¤¦¡ª</description>
+
+ <dc:date>2003-06-11T00:12:36+09:00</dc:date>
+
+ </item>
+
+ <item rdf:about='http://bat/~gallery/./wrudgef/BARROWGANG/100%2D0099_IMG.JPG'>
+ <title>¤¢¤ß¤¢¤ß¥¹¥«¡¼¥È</title>
+
+
+ <description>¡ï8.900¡¡¥Õ¥ê¡¼¥µ¥¤¥º¡¡¡ã¥Ù¡¼¥¸¥å¡ä
+ÌʤǤ¢¤ó¤À¥Ë¥Ã¥È¤Ê¤Î¤Ç·Ú¤¤°õ¾Ý¤Ç¤¹¡£
+¤Á¤ç¤¦¤É¤Ò¤¶¾å¾æ¤Ê¤Î¤Ç¡¢¥Ñ¥ó¥Ä¤È½Å¤Í¤¿¤ê¤â¤Ç¤­¤Þ¤¹¡£</description>
+
+ <dc:date>2003-06-11T00:09:25+09:00</dc:date>
+
+ </item>
+
+
+
+
+</rdf:RDF>
diff --git a/sample/rss/list_description.rb b/sample/rss/list_description.rb
new file mode 100644
index 000000000..edb9ba07a
--- /dev/null
+++ b/sample/rss/list_description.rb
@@ -0,0 +1,84 @@
+#!/usr/bin/env ruby
+
+require "nkf"
+class String
+ # From tdiary.rb
+ def shorten( len = 120 )
+ lines = NKF::nkf( "-e -m0 -f#{len}", self.gsub( /\n/, ' ' ) ).split( /\n/ )
+ lines[0].concat( '...' ) if lines[0] and lines[1]
+ lines[0]
+ end
+end
+
+require "rss/parser"
+require "rss/1.0"
+require "rss/2.0"
+require "rss/dublincore"
+
+channels = {}
+verbose = false
+
+def error(exception)
+ mark = "=" * 20
+ mark = "#{mark} error #{mark}"
+ puts mark
+ puts exception.class
+ puts exception.message
+ puts exception.backtrace
+ puts mark
+end
+
+before_time = Time.now
+ARGV.each do |fname|
+ if fname == '-v'
+ verbose = true
+ next
+ end
+ rss = nil
+ f = File.new(fname).read
+ begin
+ ## do validate parse
+ rss = RSS::Parser.parse(f)
+ rescue RSS::InvalidRSSError
+ error($!) if verbose
+ ## do non validate parse for invalid RSS 1.0
+ begin
+ rss = RSS::Parser.parse(f, false)
+ rescue RSS::Error
+ ## invalid RSS.
+ error($!) if verbose
+ end
+ rescue RSS::Error
+ error($!) if verbose
+ end
+ if rss.nil?
+ puts "#{fname} does not include RSS 1.0 or 0.9x/2.0"
+ else
+ begin
+ rss.output_encoding = "euc-jp"
+ rescue RSS::UnknownConversionMethodError
+ error($!) if verbose
+ end
+ rss.channel.title ||= "Unknown"
+ rss.items.each do |item|
+ item.title ||= "Unknown"
+ channels[rss.channel.title] ||= []
+ channels[rss.channel.title] << item if item.description
+ end
+ end
+end
+processing_time = Time.now - before_time
+
+channels.sort do |x, y|
+ x[0] <=> y[0]
+end[0..20].each do |title, items|
+ puts "Channel : #{title}" unless items.empty?
+ items.sort do |x, y|
+ x.title <=> y.title
+ end[0..10].each do |item|
+ puts " Item : #{item.title.shorten(50)}"
+ puts " Description : #{item.description.shorten(50)}"
+ end
+end
+
+puts "Processing Time : #{processing_time}s"
diff --git a/sample/rss/news.rss b/sample/rss/news.rss
new file mode 100644
index 000000000..c1bb5af6a
--- /dev/null
+++ b/sample/rss/news.rss
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<rdf:RDF
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns="http://purl.org/rss/1.0/"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+>
+<channel rdf:about="http://www.php.net/">
+ <title>PHP: Hypertext Preprocessor</title>
+ <link>http://www.php.net/</link>
+ <description>The PHP scripting language web site</description>
+ <items>
+ <rdf:Seq>
+ <rdf:li rdf:resource="http://www.phparch.com" />
+ <rdf:li rdf:resource="http://www.php.net/echo" />
+ <rdf:li rdf:resource="http://phpconf.hu/" />
+ <rdf:li rdf:resource="http://www.php.net/release_4_3_1.php" />
+ <rdf:li rdf:resource="http://www.php-con.com/return.php?i=ph2" />
+ <rdf:li rdf:resource="http://www.linuxtag.org/2003/en/conferences/cfp.html" />
+ <rdf:li rdf:resource="http://phpconf.phpquebec.org/index.php" />
+ <rdf:li rdf:resource="http://www.phpconference.com/" />
+ <rdf:li rdf:resource="http://pear.php.net/" />
+ <rdf:li rdf:resource="http://www.derickrethans.nl/20021230.php" />
+ <rdf:li rdf:resource="http://www.php.net/downloads.php" />
+ <rdf:li rdf:resource="http://weblabor.hu/php-doc-chm" />
+ <rdf:li rdf:resource="http://www.mysql.com/events/uc2003/" />
+ <rdf:li rdf:resource="http://www.php.net/news.rss" />
+ <rdf:li rdf:resource="http://www.afup.org/" />
+ <rdf:li rdf:resource="http://www.phpmag.de/" />
+ <rdf:li rdf:resource="http://www.phparch.com/" />
+ <rdf:li rdf:resource="http://www.php.net/urlhowto.php" />
+ <rdf:li rdf:resource="http://www.linuxworldexpo.de" />
+ </rdf:Seq>
+ </items>
+</channel>
+<!-- RSS-Items -->
+
+<item rdf:about="http://www.phparch.com">
+ <title>Grant Program</title>
+ <link>http://www.phparch.com</link>
+ <description> php|architect, is proud to announce the creation of the php|architect Grant Program, whose goal is to provide financial support to best-of-breed PHP-related projects. Participation in the program is open to all open-source projects that are related to PHP (but not necessarily written in PHP). The program is accepting submissions now and will start distributing grants in June of 2003. For more information, visit the program's website. </description>
+ <dc:date>2003-03-06</dc:date>
+</item>
+
+<item rdf:about="http://www.php.net/echo">
+ <title>Set your own language preference</title>
+ <link>http://www.php.net/echo</link>
+ <description> Starting from today, your browser's &quot;Accept Language&quot; setting is also honored on language sensitive pages on the php.net site. If you would like to get to the documentation page of echo for example, you can use the /echo shortcut on all mirror sites, if your browser is set to provide your language preference information to the server. This also makes the PHP error message links point to the documentation in your preferred language. You can set your preferences under Edit/Preferences/Navigator/Languages in Mozilla, and under Tools/Internet Options/Languages in Internet Explorer. This will probably also enhance your web experience on sites providing translated content. </description>
+ <dc:date>2003-03-01</dc:date>
+</item>
+
+<item rdf:about="http://phpconf.hu/">
+ <title>First Hungarian PHP Conference</title>
+ <link>http://phpconf.hu/</link>
+ <description> The members of the Hungarian PHP community announce the first Hungarian PHP Conference which will take place in Budapest, on Saturday March 29th, sponsored by several international and local companies. The conference offers an entirely free one day activity with several presentations addressing basic and advanced topics, as well, exclusively in Hungarian. Moreover, a five kilobyte-limited PHP contest has been started to discover the most talented PHP programmers in our country. The programme includes the first session of the so-called PHP Division which will be established with the set purpose of representing the community itself and promoting their interests in any national business and official phorums. </description>
+ <dc:date>2003-02-25</dc:date>
+</item>
+
+<item rdf:about="http://www.php.net/release_4_3_1.php">
+ <title>PHP 4.3.1 released in response to CGI vulnerability</title>
+ <link>http://www.php.net/release_4_3_1.php</link>
+ <description> The PHP Group today announced the details of a serious CGI vulnerability in PHP version 4.3.0. A security update, PHP 4.3.1, fixes the issue. Everyone running affected version of PHP (as CGI) are encouraged to upgrade immediately. The new 4.3.1 release does not include any other changes, so upgrading from 4.3.0 is safe and painless. </description>
+ <dc:date>2003-02-17</dc:date>
+</item>
+
+<item rdf:about="http://www.php-con.com/return.php?i=ph2">
+ <title>PHPCon East 2003 - (April 23-25, 2003)</title>
+ <link>http://www.php-con.com/return.php?i=ph2</link>
+ <description> PHPCon announces PHPCon East 2003 in New York City. This conference features two days of technical learning with speakers such as Rasmus Lerdorf, Zeev Suraski, Michael Radwin, George Schlossnagle and Jeremy Zawodny. PHPCon East also adds a third, full day of tutorials offering practical, cogent PHP solutions and ideas including: MySQL and PHP; Building and Consuming Web Services with SOAP; Getting Started with PHP; High Performance PHP: Profiling and Benchmarking; and more PHPCon East has discounts for early registration, students, non-profits, and Tutorial/Conference packages. Early Bird Deadline is March 31st. For more program information, visit the PHPCon website. </description>
+ <dc:date>2003-02-01</dc:date>
+</item>
+
+<item rdf:about="http://www.linuxtag.org/2003/en/conferences/cfp.html">
+ <title>LinuxTag, Karlsruhe, July 10th - 13th</title>
+ <link>http://www.linuxtag.org/2003/en/conferences/cfp.html</link>
+ <description> LinuxTag e.V has once again put out a call for papers for this years conference event. Submit your ideas and proposals here. This year's theme looks at discussions that promote new ideas, delivers a broad overview, introduces new users to linux, or discusses the legal, moral and other implications of linux and free software. </description>
+ <dc:date>2002-12-30</dc:date>
+</item>
+
+<item rdf:about="http://phpconf.phpquebec.org/index.php">
+ <title>Conf&amp;eacute;rence PHP Qu&amp;eacute;bec 2003 - (Montr&amp;eacute;al, March 20&amp;amp;21rst, 2003)</title>
+ <link>http://phpconf.phpquebec.org/index.php</link>
+ <description> The PHP Qu&amp;eacute;bec association announces the Conf&amp;eacute;rence PHP Qu&amp;eacute;bec 2003. The conference will take place in the &amp;Eacute;cole Polytechnique de Montr&amp;eacute;al, Qu&amp;eacute;bec, Canada. The Conf&amp;eacute;rence PHP Qu&amp;eacute;bec features two days of conferences, with outstanding customer cases from Canada, and cutting edge technical sessions, hosted by international experts. An exhibitor room will showroom professional solutions. Learn more about those exciting days at phpconf.phpquebec.com. </description>
+ <dc:date>2003-01-28</dc:date>
+</item>
+
+<item rdf:about="http://www.phpconference.com/">
+ <title>International PHP Conference 2003 - Spring Edition (Amsterdam, May 8-9)</title>
+ <link>http://www.phpconference.com/</link>
+ <description> Software &amp;amp; Support Verlag announced the International PHP Conference 2003 - Spring Edition - in Amsterdam. The dates for this event for PHP enthusiasts from all over the world will be May 8 and 9, 2003. The conference venue is the RAI conference center in Amsterdam. Like the International PHP Conferences in Frankfurt this conference will offer a first class program to an international audience of PHP enthusiasts. We are happy to ask you to submit your proposals for the session program. The topics are General PHP, PHP &amp;amp; Business, PHP &amp;amp; Databases, PHP Design, PHP Extensions, PHP &amp;amp; XML and PHP-GTK. </description>
+ <dc:date>2003-01-13</dc:date>
+</item>
+
+<item rdf:about="http://pear.php.net/">
+ <title>PEAR Out of Beta!</title>
+ <link>http://pear.php.net/</link>
+ <description> The PEAR development team is proud to announce that PEAR is finally out of its long beta period. As of PHP 4.3, the PEAR installer is installed by default. Unix support is considered stable, while Windows and Darwin are still of beta-quality. </description>
+ <dc:date>2003-01-11</dc:date>
+</item>
+
+<item rdf:about="http://www.derickrethans.nl/20021230.php">
+ <title>PHP Look Back 2002</title>
+ <link>http://www.derickrethans.nl/20021230.php</link>
+ <description> We are at the end of 2002, and it seemed appropriate to look back on the development issues of the past year. So starts the first PHP Look Back You can find it in on the non-official personal website of one of the PHP Developers here. Happy New Year </description>
+ <dc:date>2002-12-31</dc:date>
+</item>
+
+<item rdf:about="http://www.php.net/downloads.php">
+ <title>PHP 4.3.0 Released!</title>
+ <link>http://www.php.net/downloads.php</link>
+ <description> The PHP developers are pleased to announce the immediate availability of PHP 4.3.0, the latest and greatest version of this extremely popular and widely used scripting language. This release contains a multitude of changes, bug fixes and improvements over the previous one, PHP 4.2.3. It further elevates PHP's standing as a serious contender in the general purpose scripting language arena. Please see the full release announcement. </description>
+ <dc:date>2002-12-27</dc:date>
+</item>
+
+<item rdf:about="http://weblabor.hu/php-doc-chm">
+ <title>New Release of the PHP Manual CHM Edition - Please Help Us</title>
+ <link>http://weblabor.hu/php-doc-chm</link>
+ <description> The 11th sample of the CHM edition is available for download from today. The sample hopefully fixed the missing page bugs forever, introduces a new integration method (see documentation inside) and contains actual manual text, mirrors list and user notes. See the edition's page for download. We also would like to ask you to help out in testing our new on-the-fly syntax highlighter, which would make the CHM significantly smaller, and would give you more options in displaying the pages. See the edition's page for more information. </description>
+ <dc:date>2002-12-27</dc:date>
+</item>
+
+<item rdf:about="http://www.mysql.com/events/uc2003/">
+ <title>MySQL Users Conference and Expo 2003 in San Jose</title>
+ <link>http://www.mysql.com/events/uc2003/</link>
+ <description> MySQL AB is proud to host the world's First Annual MySQL User Conference, to be held in the heart of Silicon Valley, April 10-12, 2003. This event promises to be the biggest gathering of MySQL database users ever in one location. Designed for both the MySQL developer and the corporate decision maker, this is the place to learn about the latest in MySQL technology, discover new business opportunities, take a pulse on industry direction and commune with like minds. More information on the event's website. </description>
+ <dc:date>2002-12-16</dc:date>
+</item>
+
+<item rdf:about="http://www.php.net/news.rss">
+ <title>PHP news feed available</title>
+ <link>http://www.php.net/news.rss</link>
+ <description> The news of PHP.net is available now in RSS 1.0 format via our new news.rss file. You can add this file to any news reader or portal site to get the latest official PHP news. We strongly recommend you to cache the contents locally on your side, as the newsfeed is updated daily. The RSS file is available on every mirror site. </description>
+ <dc:date>2002-12-01</dc:date>
+</item>
+
+<item rdf:about="http://www.afup.org/">
+ <title>Forum PHP 2002 in Paris, France</title>
+ <link>http://www.afup.org/</link>
+ <description> The French PHP User Group AFUP invites you to the &quot;Forum PHP 2002&quot; in Paris, on December 9th and 10th. Designed to meet the needs of PHP aware companies and all the French PHP developper's community alike, this event will provided you with valuable and up-to-date information. For more information (in French) see the PHP Forum website. </description>
+ <dc:date>2002-11-21</dc:date>
+</item>
+
+<item rdf:about="http://www.phpmag.de/">
+ <title>PHP Magazine - International Edition</title>
+ <link>http://www.phpmag.de/</link>
+ <description> Software &amp;amp; Support Verlag GmbH is going to publish an International version of the PHP Magazin. This magazine was initiated after growing interest for an English magazine after the German version has been around for a few months. PHP Magazine not only informs about the scripting language itself, but also about related technologies such as the Apache Web Server, database technologies, XML and other innovative internet technologies. Different sections within the magazine are oriented towards the specific question areas with which a web developer is confronted in daily practice. The first issue will be published in December and the frequency of issues is two months. You will be able to subscribe on the website which will open shortly. </description>
+ <dc:date>2002-11-17</dc:date>
+</item>
+
+<item rdf:about="http://www.phparch.com/">
+ <title>New Monthly PHP Magazine Launched</title>
+ <link>http://www.phparch.com/</link>
+ <description> php|architect, a new monthly magazine dedicated exclusively to PHP, has launched its website. php|a is published in PDF format and is available worldwide. It covers a variety of advanced topics ranging from day-to-day programming to the internals of PHP. A sample article on the creation of a web-based PDF converter is also available on the magazine website </description>
+ <dc:date>2002-11-15</dc:date>
+</item>
+
+<item rdf:about="http://www.php.net/urlhowto.php">
+ <title>PHP Search Bars available for major browsers</title>
+ <link>http://www.php.net/urlhowto.php</link>
+ <description> We added a new option to access our site's content quickly. In addition to URL shortcuts, keyboard shortcuts and browser specific magic you can now use our Search Bar from the major browsers. Please help us to test this new service, and provide feedback via the bug system (categorize your bug as a PHP.net website bug please). </description>
+ <dc:date>2002-10-29</dc:date>
+</item>
+
+<item rdf:about="http://www.linuxworldexpo.de">
+ <title>PHP at the LinuxWorld Expo Oct. 29-31th in Frankfurt, Germany</title>
+ <link>http://www.linuxworldexpo.de</link>
+ <description> For the first time the Open Source projects comprising the popular LAMP platform (Linux, Apache, MySQL and PHP) will be present at the LinuxWorld Expo with its own booth. At the booth, which is organized by the German PHP Association and the PHP Usergroup Frankfurt, fair visitors can experience and learn about Apache, MySQL, PHP and related projects. Visitors can take LAMP home, too, since there will be a CD with the necessary software available at the booth. </description>
+ <dc:date>2002-10-28</dc:date>
+</item>
+<!-- / RSS-Items PHP/RSS -->
+</rdf:RDF>
diff --git a/sample/rss/php.rss b/sample/rss/php.rss
new file mode 100644
index 000000000..e9508b9d0
--- /dev/null
+++ b/sample/rss/php.rss
@@ -0,0 +1,235 @@
+<?xml version="1.0" encoding="utf-8"?>
+<rdf:RDF
+ xmlns="http://purl.org/rss/1.0/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"
+ xml:lang="ja">
+
+ <channel rdf:about="http://ishinao.net/WikiLike/?sort=modified_desc">
+ <title>ishinao's personal WikiLike</title>
+ <link>http://ishinao.net/WikiLike/?sort=modified_desc</link>
+ <description>WikiLike Modified List</description>
+ <items>
+ <rdf:Seq>
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=276" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=275" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=274" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=273" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=271" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=272" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=270" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=243" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=269" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=268" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=267" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=266" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=265" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=264" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=263" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=262" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=261" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=260" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=258" />
+ <rdf:li rdf:resource="http://ishinao.net/WikiLike/?sid=1" />
+ </rdf:Seq>
+ </items>
+ </channel>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=276">
+ <title>プログラミング言語ã®åˆ¶å¾¡æ§‹é€ ç³»å‘½ä»¤ä¸€è¦§</title>
+ <link>http://ishinao.net/WikiLike/?sid=276</link>
+ <description>ã™ãã«æ··ä¹±ã—ã¦åˆ†ã‹ã‚‰ãªããªã‚‹ã„ã‚ã„ã‚ãª[[プログラミング言語]]ã®[[制御構造]]ç³»[[命令]]ã®ä¸€è¦§ã€‚ãŸã¶ã‚“第1稿ã«ã¯ã„ã‚ã„ã‚é–“é•ã„ãŒã‚ã‚Šãã†ï¼†è¨€èªžã®é¸æŠžã‚‚é©å½“ã ãªã€‚ã‚ã¨ã§ç´°ã‹ãç›´ãã†ã€‚変ãªã¨ã“ã‚を見ã¤ã‘ãŸã‚‰æ•™ãˆã¦ãã ã•ã„。
+
+!![[Perl]]
+!!!for
+ for ($i=0; $i&lt;10; $i++) {
+ }
+!!!while
+ while ($i&lt;10) {
+ break; //脱出
+ next; //次ループ
+ }
+!!!foreach array
+ </description>
+ <dc:date>2003-03-03T08:51:55+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/276</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=275">
+ <title>IMを次ã®ãƒ¬ãƒ™ãƒ«ã«â€•â€•MSã®ã€Œ3°ã€ãŒç›®æŒ‡ã™ä¸–ç•Œ from ZDNet</title>
+ <link>http://ishinao.net/WikiLike/?sid=275</link>
+ <description>*[[IM]]を次ã®ãƒ¬ãƒ™ãƒ«ã«â€•â€•[[MS]]ã®ã€Œ[[3°]]ã€ãŒç›®æŒ‡ã™ä¸–ç•Œ - http://www.zdnet.co.jp/news/0303/03/xert_msim.html
+
+[[マイクロソフト]]ã¯ã€ä¼æ¥­å‘ã‘ã®[[P2P]]アプリã¯[[Groove]]ã§ã€ä¸€èˆ¬å‘ã‘ã®P2Pアプリã¯ThreeDegreeã§ã€ã£ã¦æ„Ÿã˜ã®æˆ¦ç•¥ãªã®ã‹ãªã€‚ã‚ã¾ã‚Šã«ã‚‚リッãƒãªã‚¢ãƒ—リã«ãªã‚Šã™ãŽã¦å‹•ä½œãŒé‡ããªã‚Šã™ãŽãªã‘ã‚Œã°ã€çµæ§‹äººæ°—ãŒå‡ºãã†ã ã€‚ãŸã ã€ã‚°ãƒ«ãƒ¼ãƒ—内ã§ã®ã‚¤ãƒ³ã‚¿ãƒ¼ãƒãƒƒãƒˆè¶Šã—ã®[[音楽共有]]ã£ã¦ã®ãŒæœ¬å½“ã«OKãªã‚‰ã°ã€</description>
+ <dc:date>2003-03-03T08:11:56+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/275</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=274">
+ <title>音楽業界ã«å–を入れる「DVDミュージックã€ã®æ­£ä½“ from ZDNet</title>
+ <link>http://ishinao.net/WikiLike/?sid=274</link>
+ <description>*[[音楽]]業界ã«å–を入れる「[[DVDミュージック]]ã€ã®æ­£ä½“ - http://www.zdnet.co.jp/news/0303/03/cjad_kodera3.html
+
+「[[DVD-R]]ã¨ã‹ã«é©å½“ã«[[オーディオ]]ã¨ã‹[[é™æ­¢ç”»]]ã¨ã‹ã®ãƒ‡ãƒ¼ã‚¿ã‚’入れã¦ã€DVDãŒå†ç”Ÿã§ãる装置ã§ãã‚Œãªã‚Šã«å†ç”Ÿã§ãるよã†ã«ã™ã‚‹ã€ã“ã¨ã«ã€ŒDVDミュージックã€ã¨ã„ã†[[è¦æ ¼]]åを付ã‘ã¦å£²ã‚Šå‡ºã—ã¦ã¿ã‚ˆã†ã€ã£ã¦ã“ã¨ã‹ã€‚
+
+ã¯ã£ãã‚Šã„ã£ã¦ã€[[DVD-Audio]]ã¿ãŸã„ãª[[次世代]]高級音楽メディアè¦æ ¼</description>
+ <dc:date>2003-03-03T08:07:09+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/274</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=273">
+ <title>ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯æ”»æ’ƒã¸ã®åæ’ƒã¯åˆæ³•ã‹ from ZDNet</title>
+ <link>http://ishinao.net/WikiLike/?sid=273</link>
+ <description>*[[ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯]][[攻撃]]ã¸ã®[[åæ’ƒ]]ã¯[[åˆæ³•]]ã‹ - http://www.zdnet.co.jp/news/0303/01/nebt_09.html
+
+&gt;ã“ã®æ¡é …ã®ä¸‹ã§è¢«å®³è€…ã¯ã€æ”»æ’ƒã‚’加ãˆã¦ã„ã‚‹[[サーãƒ]]ãŒãŸã¨ãˆä»–人ã®ã‚‚ã®ã§ã‚ã£ã¦ã‚‚ã€ãã®ã‚µãƒ¼ãƒå†…ã®æ”»æ’ƒç”¨ãƒ—ログラムをåœæ­¢ã•ã›ã‚‹ã“ã¨ãŒè¨±ã•ã‚Œã‚‹ã¨è§£é‡ˆã§ãã‚‹ã¨ã„ã†ã€‚
+
+確ã‹ã«é™å®šã•ã‚ŒãŸåæ’ƒãªã‚‰ã°è‰¯ã•ãã†ãªæ°—ãŒã™ã‚‹ã‘ã‚Œã©ã‚‚ã€[[éŽå‰°é˜²è¡›]]ã¨ã®å¢ƒç›®ãŒé›£ã—ãã†ãªæ°—ã‚‚ã™ã‚‹ã€‚ã‚‚ã—ã‚‚ã“ã‚ŒãŒèªã‚られるãªã‚‰ã°ã€[[ウイルス駆除]]ソフトメーカ</description>
+ <dc:date>2003-03-03T03:54:43+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/273</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=271">
+ <title>言葉交差点</title>
+ <link>http://ishinao.net/WikiLike/?sid=271</link>
+ <description>*言葉交差点 - http://ishinao.net/wordslinks/
+
+[[キーワード]]ã§è¤‡æ•°ã®[[Webサイト]]ã‚’çµã³ã¤ã‘ã‚‹[[リンク集]]。[[プロジェクトå]]を「[[言葉交差点]]ã€ã¨ã¤ã‘ã¦[[テスト]]中。ã„ã‚ã„ã‚ãªã‚„ã‚Šæ–¹ãŒã‚ã‚Šã™ãŽã¦ã€ã©ã‚ŒãŒä¸€ç•ªã„ã„ã®ã‹ã‚ã‹ã‚‰ãªããªã£ãŸã®ã§ã€ã¨ã¦ã‚‚[[プリミティブ]]ãªã‚‚ã®ã§é›°å›²æ°—を見定ã‚ã¦ã¿ã‚ˆã†ã€‚特ã«[[インターフェース]]周りã®æ‰±ã„ãŒé›£ã—ã„。ã²ã¨ã¾ãšWikiLikeã‹ã‚‰ã¯[[自動登録]]ãŒã§ãるよã†ã«TrackBackçš„ãªã‚„り方を実装ã—ã¦ã¿</description>
+ <dc:date>2003-03-03T02:53:20+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/271</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=272">
+ <title>複製症候群</title>
+ <link>http://ishinao.net/WikiLike/?sid=272</link>
+ <description>[[講談社文庫]] [[西澤ä¿å½¦]]è‘— 「[[複製症候群:http://www.amazon.co.jp/exec/obidos/ASIN/4062734575/ishinao-22]]ã€
+
+ã‚ã‚‹æ—¥çªç„¶ç©ºã‹ã‚‰ä¸æ€è­°ãªå·¨å¤§[[ãƒãƒ¥ãƒ¼ãƒ–]]ãŒç¾ã‚ŒãŸã€‚ãã‚Œã«è§¦ã£ãŸç”Ÿã物ã¯ã™ã¹ã¦å®Œå…¨ãª[[複製]]([[コピー]])ãŒä½œã‚‰ã‚Œã¦ã—ã¾ã†ã€‚家æ—ã‚„å‹äººã€æ•™å¸«ã€ãã—ã¦å…„ã«å¯¾ã—ã¦å¼·ã„コンプレックスをもã¤â€œåƒ•â€ã¯ã€å‹äººé”ã¨ã¨ã‚‚ã«ãƒãƒ¥ãƒ¼ãƒ–ã®ä¸­ã«é–‰ã˜ã“ã‚られã¦ã—ã¾ã£ãŸâ€¦â€¦ã€‚
+
+ã¨ã„ã†[[SF]]çš„ã‚·ãƒãƒ¥ã‚¨ãƒ¼ã‚·ãƒ§ãƒ³ã«ãŠã‘ã‚‹[[</description>
+ <dc:date>2003-03-02T14:36:12+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/272</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=270">
+ <title>ãƒãƒ©ã®ãƒ„ボミ</title>
+ <link>http://ishinao.net/WikiLike/?sid=270</link>
+ <description>[[20030302131001.jpg:http://ishinao.net/image/20030302131001.jpg]]
+ã¾ã ã“ã®æ™‚期ã®ãƒ„ボミã¯åˆ‡ã‚‰ãªãゃダメらã—ã„ã­ã€‚ã§ã‚‚切るã«å¿ã³ãªã„。</description>
+ <dc:date>2003-03-02T04:10:02+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/270</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=243">
+ <title>Apacheã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒå¤‰ã‚ã£ãŸ</title>
+ <link>http://ishinao.net/WikiLike/?sid=243</link>
+ <description>昨日[[特ã«ä½¿ã†ã‚ã¦ã®ãªã„Wiki]]ã®æ›´æ–°ãŒã§ããªããªã£ã¦ã„ã‚‹ã¨ã‚³ãƒ¡ãƒ³ãƒˆã§æ•™ãˆã‚‰ã‚Œã¦è¦‹ã«è¡Œã£ãŸã‚‰ã€ãªãœã‹PukiWikiã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ãƒ•ã‚¡ã‚¤ãƒ«ã‚’æ›´æ–°ã§ããªããªã£ã¦ã„ãŸã€‚ãªãœã ã‚ã†ã¨èª¿ã¹ã¦ã¿ãŸã‚‰ã€[[Apache]]ã®[[動作ユーザー]](ID)ãŒå¤‰ã‚ã£ã¦ã„る。ãã®ã›ã„ã§ã€æ—§ãƒ¦ãƒ¼ã‚¶ãƒ¼æ¨©é™ã§ä½œæˆã•ã‚ŒãŸãƒ•ã‚¡ã‚¤ãƒ«ã¸ã®WriteアクセスãŒã§ããªããªã£ã¦ã„ãŸã€‚
+
+Read権é™ã¯ã‚ã£ãŸã‚“ã§ã€ã„ã£ãŸã‚“FTPã§ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã‚’å–ã‚Šã€ãƒ‡ãƒ¼ã‚¿ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’別ã«å·®ã—替ãˆã¦606ã§æ”¾ã‚Šè¾¼ã‚“ã ã‚‰å‹•ãよã†ã«ãªã£ãŸã‘ã‚Œã©ã‚‚ã€æ—§ãƒ‡ãƒ¼ã‚¿ãƒ‡ã‚£</description>
+ <dc:date>2003-03-01T19:06:25+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/243</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=269">
+ <title>椎å林檎CCCD</title>
+ <link>http://ishinao.net/WikiLike/?sid=269</link>
+ <description>ã‚らã€æ–°ã—ã„[[椎å林檎]]ã®[[アルãƒãƒ ]]ã£ã¦[[CCCD]]ã ã£ãŸã®ã­ã€‚å±ãªãè²·ã†ã¨ã“ã‚ã ã£ãŸã‚ˆã€‚ã£ã¦ã®ã¯åˆ¥ã«CCCDã«çµ¶å¯¾å対原ç†ä¸»ç¾©è€…ã ã‹ã‚‰ã§ã¯ãªã(ãŠãŠã‚€ã­å対+ã‚ã‚“ãªã—ょã¼ã„技術使ã†ãªã‚“ã¦ãƒã‚«ã˜ã‚ƒã­ãƒ¼ã®ã¨ã¯æ€ã£ã¦ã„ã‚‹ã‘ã©ï¼‰ã€ä¿ºã¯åŸºæœ¬çš„ã«[[PC]]+[[シリコンオーディオプレイヤー]]ã§[[音楽]]ã‚’è´ã人間ãªã‚“ã§ã€CCCDã˜ã‚ƒã‚è²·ã†æ„味ãŒãªã„ã‹ã‚‰ã€‚ã‚‚ã¡ã‚ã‚“CCCDã«ã—ãŸã£ã¦ã®ã¯ã€ãã†ã„ã†äººã¯ç§ã®éŸ³æ¥½ã‚’è´ããªã£ã¦æ„味ãªã‚“ã ã‚ˆã­ã€‚</description>
+ <dc:date>2003-03-01T07:28:43+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/269</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=268">
+ <title>◆「ルパン三世ã€ãŒãƒãƒªã‚¦ãƒƒãƒ‰ã§å®Ÿå†™æ˜ ç”»åŒ– from ZAKZAK</title>
+ <link>http://ishinao.net/WikiLike/?sid=268</link>
+ <description>*◆「[[ルパン三世]]ã€ãŒãƒãƒªã‚¦ãƒƒãƒ‰ã§å®Ÿå†™æ˜ ç”»åŒ– - http://www.zakzak.co.jp/midnight/hollywood/backnumber/L/030228-L.html
+
+[[アメリカン]]ãª[[ãƒãƒªã‚¦ãƒƒãƒ‰]]加工ã•ã‚ŒãŸ[[ルパン]]三世。見ãŸã„よã†ãªè¦‹ãŸããªã„よã†ãªã€‚見ã¦ã„ãªã„ã‘ã©é§„作ã¨è©•åˆ¤ã ã£ãŸ[[ãƒãƒ‰ã‚½ãƒ³ãƒ»ãƒ›ãƒ¼ã‚¯]]ã¨ã‹æ€ã„æµ®ã‹ã¹ã¡ã‚ƒã†ã—ãªã€‚ã§ãã®æ‚ªã„[[007]]シリーズã¿ãŸã„ãªã‚‚ã®ã«ãªã‚Šãã†ãªæ°—ã‚‚ã™ã‚‹ã—。</description>
+ <dc:date>2003-03-01T06:49:20+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/268</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=267">
+ <title>パフォーマンスã¯è‰¯å¥½ã‚‚ã€ä¾ç„¶ã¬ããˆã¬ä¸å®‰â€•â€•ã€ŒCentrinoテクノロジã€ãƒ—レスå‘ã‘事å‰ã‚»ãƒŸãƒŠãƒ¼é–‹å‚¬ from ZDNet</title>
+ <link>http://ishinao.net/WikiLike/?sid=267</link>
+ <description>*パフォーマンスã¯è‰¯å¥½ã‚‚ã€ä¾ç„¶ã¬ããˆã¬ä¸å®‰â€•â€•ã€Œ[[Centrino]]テクノロジã€ãƒ—レスå‘ã‘事å‰ã‚»ãƒŸãƒŠãƒ¼é–‹å‚¬ - http://www.zdnet.co.jp/news/0302/28/nj00_centrino.html
+
+技術・性能的ã«ã¯å„ªã‚Œã¦ã„ã‚‹ã‘ã‚Œã©ã‚‚ã€å–¶æ¥­ãƒ»åºƒå‘Šãƒ»ã‚¿ã‚¤ãƒŸãƒ³ã‚°çš„ã«ã¯å•é¡ŒãŒãŸãã•ã‚“ã‚ã‚Šã¾ã™ã£ã¦ã“ã¨ã‹ã€‚ãã‚Œã«ã—ã¦ã‚‚[[インテル]]ã£ã¦ã€ã“ã‚“ãªã«ã‚ã‹ã‚Šã‚„ã™ã„例示(タクシーを使ã£ãŸãƒ¢ãƒ‡ãƒ«ï¼‰æº€è¼‰ã®[[プレス]]å‘ã‘ã®[[セミナー]]ãªã‚“ã¦ã‚„るタイプã ã£ã‘? もã†ã¡ã‚‡ã£ã¨æ™®é€šã«æŠ€è¡“説明ã£</description>
+ <dc:date>2003-03-01T06:46:37+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/267</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=266">
+ <title>◆「中å·å®¶ã€å¼Ÿã€ã‚­ãƒ¬ã¦è·¯ä¸ŠãƒŠãƒ³ãƒ‘女性殴る from ZAKZAK</title>
+ <link>http://ishinao.net/WikiLike/?sid=266</link>
+ <description>*◆「[[中å·å®¶]]ã€å¼Ÿã€ã‚­ãƒ¬ã¦è·¯ä¸ŠãƒŠãƒ³ãƒ‘女性殴る - http://www.zakzak.co.jp/top/top0301_1_08.html
+
+[[漫æ‰å¸«]]ã«[[ツッコミ]]を入れられãŸãらã„ã§è¨´ãˆã‚‹ãªã‚“ã¦å†—談ã®åˆ†ã‹ã‚‰ãªã„ã‚„ã¤ã ãªãƒ¼ã€‚ã¨ã„ã†è«–調ã«ã¯ãªã‚‰ãªã„ã‚“ã§ã™ã­ã€‚「女性ã®é ­ã‚’1回殴ã£ãŸã€ã£ã¦ã®ãŒå…·ä½“çš„ã«ã©ã®ãƒ¬ãƒ™ãƒ«ãªã®ã‹ã‚ˆã分ã‹ã‚‰ãªã„ã‘ã©ã€‚</description>
+ <dc:date>2003-03-01T06:33:53+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/266</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=265">
+ <title>工学部・水柿助教授ã®æ—¥å¸¸</title>
+ <link>http://ishinao.net/WikiLike/?sid=265</link>
+ <description>[[GENTOSHA NOVELS]] [[森åšå—£]]è‘— 「[[工学部・水柿助教授ã®æ—¥å¸¸:http://www.amazon.co.jp/exec/obidos/ASIN/4344009088/ishinao-22]]ã€
+
+ã—ã¾ã£ãŸã€ã ã¾ã•ã‚ŒãŸã€‚æ–°ã—ã„[[ミステリー]]å°èª¬ã‹ã¨æ€ã£ãŸã‚‰ã€ãã†ã„ã†ä½“è£ã‚’å–ã£ãŸ[[エッセイ]]ã˜ã‚ƒã­ãƒ¼ã‹ã€‚ãã‚Œãªã‚Šã«é¢ç™½ã‹ã£ãŸã—ã€ãã†ã ã¨çŸ¥ã£ã¦ã„ã¦ã‚‚ãŸã¶ã‚“è²·ã£ãŸã¨ã¯æ€ã†ã‘ã‚Œã©ã‚‚(ã§ã‚‚今ã¾ã§åŸºæœ¬çš„ã«æ£®åšå—£ã®ã‚¨ãƒƒã‚»ã‚¤ç³»ã¯ã‚ã‚“ã¾ã‚Šè²·ã£ã¦ã„ãªã„)ã€æœŸå¾…ã—ãŸã‚‚ã®ãŒå¾—られãªã‹ã£ãŸã¨ã„ã†</description>
+ <dc:date>2003-03-01T05:20:40+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/265</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=264">
+ <title>瞬間移動死体</title>
+ <link>http://ishinao.net/WikiLike/?sid=264</link>
+ <description>[[講談社文庫]] [[西澤ä¿å½¦]]è‘— 「[[瞬間移動死体:http://www.amazon.co.jp/exec/obidos/ASIN/4062732262/ishinao-22]]ã€
+
+ã¨ã¦ã‚‚é™å®šã•ã‚ŒãŸ[[テレãƒãƒ¼ãƒ†ãƒ¼ã‚·ãƒ§ãƒ³]]能力をæŒã¤ç”·ãŒã€ãれを利用ã—ãŸ[[殺人]]を計画ã™ã‚‹ã€‚ã¨ã„ã†è¥¿æ¾¤ä¿å½¦å¾—æ„ã®[[SF]]ãƒã‚¿ã‚’使ã£ãŸ[[ミステリー]]。é¢ç™½ããªã‹ã£ãŸã‚ã‘ã§ã¯ãªã„ã‘ã‚Œã©ã‚‚ã€ãªã‚“ã‹ã¡ã‚‡ã£ã¨ã„ã¾ã„ã¡ãªå°è±¡ã€‚ã‚ã‚ã„ã†æž ã®è¨­å®šã ã£ãŸã‚‰ã€ã»ã‹ã«ã‚‚ã„ã‚ã„ã‚ãªé¸æŠžè‚¢ï¼ˆãã‚Œãªã‚Šã«ç†å±ˆãŒé€šã‚‹ã‚¹ãƒˆãƒ¼ãƒªãƒ¼ï¼‰ãŒ</description>
+ <dc:date>2003-03-01T05:12:07+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/264</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=263">
+ <title>犯罪系ファンタジー</title>
+ <link>http://ishinao.net/WikiLike/?sid=263</link>
+ <description>*[[性犯罪]] - http://www.ag.wakwak.com/~mai_u/umui/200302c.html#200302281232
+*[[フェティシズム]](ã¨ã„ã†ã®ã‚‚変ãªæ„Ÿã˜ãŒã—ã¾ã™ã‘ã‚Œã©ã‚‚) - http://darkares.tdiary.net/20030228.html#p02
+*Re:性犯罪 - http://www.ag.wakwak.com/~mai_u/umui/200302c.html#200302281858
+*ã—ã¦ã¯ã„ã‘ãªã„ã‹ã‚‰ã“ã - http://dark</description>
+ <dc:date>2003-03-01T03:06:59+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/263</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=262">
+ <title>æºå¸¯ã‹ã‚‰ã®ãƒ¡ãƒ¼ãƒ«æŠ•ç¨¿ã«å¯¾å¿œ</title>
+ <link>http://ishinao.net/WikiLike/?sid=262</link>
+ <description>ã¨ã„ã†ã‚ã‘ã§ã€[[æºå¸¯]]ã‹ã‚‰ã®[[メール]][[投稿]]ã«å¯¾å¿œã—ã¦ã¿ãŸã‚ã‘ã§ã™ã€‚一応[[添付ファイル]]ã«ã‚‚対応。ãŸã ã—今ã®ã¨ã“ã‚[[JPEG]]ã®ã¿å±•é–‹ã€‚
+
+ç§ã¯[[au]]ユーザーãªã‚“ã§[[å‹•ç”»]]ã¯[[ezmovie]]ã¨ã„ã†å¦™ãª[[フォーマット]]ãªã‚“ã§ã™ã‚ˆã­ã€‚[[CODEC]]自体ã¯[[mpeg4]]ãªã‚“ã ã‘ã©ã€[[コンテナフォーマット]]ãŒau独自ã®å¤‰ãªå½¢å¼ãªã‚“ã§ã€æ™®é€šã®PCã˜ã‚ƒã‚[[å†ç”Ÿ]]ã§ããªã„。一応[[Windows]]用ã®[[プレイヤー]]ソフトã¯é…布ã•ã‚Œã¦ã„ã‚‹ã‘ã©ã€ã‚ã‚“ãªã®a</description>
+ <dc:date>2003-02-28T13:11:07+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/262</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=261">
+ <title>カエルã®ãƒžã‚¦ã‚¹ãƒ‘ッド</title>
+ <link>http://ishinao.net/WikiLike/?sid=261</link>
+ <description>[[20030228215401:http://ishinao.net/image/20030228215401.jpg]]
+ãºã‚‰ãºã‚‰ã®å¸ƒè£½ãƒžã‚¦ã‚¹ãƒ‘ッドã¯æŒã¡é‹ã³ã«ä¾¿åˆ©ã€‚</description>
+ <dc:date>2003-02-28T12:54:01+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/261</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=260">
+ <title>æºå¸¯ã‹ã‚‰ã®æŠ•ç¨¿ãƒ†ã‚¹ãƒˆ</title>
+ <link>http://ishinao.net/WikiLike/?sid=260</link>
+ <description>[[20030228212001:http://ishinao.net/image/20030228212001.jpg]]
+テストメールã ã‚ˆã€‚写ã£ã¦ã„ã‚‹ã®ã¯FOMAã®è‰²ã‚‚ã®ç«¯æœ«ã€‚ãã‚Œã«ã—ã¦ã‚‚æºå¸¯ã§é•·æ–‡ã¯æ‰“ã¡ãŸããªã„よã­ã€‚</description>
+ <dc:date>2003-02-28T12:32:06+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/260</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=258">
+ <title>ç§ã¯ã€ã‚µã‚¤ãƒœãƒ¼ã‚° from ZDNet</title>
+ <link>http://ishinao.net/WikiLike/?sid=258</link>
+ <description>*ç§ã¯ã€[[サイボーグ]] - http://www.zdnet.co.jp/news/0302/28/nj00_interaction.html
+
+&gt;神経ã¨æŽ¥ç¶šã•ã‚ŒãŸ[[義手]]。ãã®ã‚¤ãƒ¡ãƒ¼ã‚¸ã¯ã€[[平井和正]]ã®ã€Ž[[死霊狩り]]ã€ã«å‡ºã¦ããŸã€‚宇宙生命体[[ゾンビー]]ã¨æˆ¦ã†ãŸã‚ã«æˆ¦é—˜è¨“ç·´ã‚’å—ã‘ãŸä¸»äººå…¬ã®ç”°æ‘俊夫ãŒã€è¨“ç·´ã®æœ€ä¸­ã«å·¦æ‰‹ã‚’失ã†ã®ã§ã‚る。
+
+ãˆãƒ¼ã£ã¨ã€ã»ã‹ã«é©å½“ãªä¾‹ã¯ãªã‹ã£ãŸã‚“ã ã£ã‘? コブラã¯ã¡ã‚‡ã£ã¨é•ã†ã‹ã€‚ãªã‚“ã‹ãŸãã•ã‚“ã‚ã‚Šãã†ãªã®ã«æ€ã„ã¤ã‹ãªã„ãªãƒ¼ã€‚ã£ã¤ãƒ¼ã‹ã€ã€Œæ­»éœŠç‹©ã‚Šã€ã‚’ナ</description>
+ <dc:date>2003-02-28T11:57:19+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/258</trackback:ping>
+</item>
+<item rdf:about="http://ishinao.net/WikiLike/?sid=1">
+ <title>FrontPage</title>
+ <link>http://ishinao.net/WikiLike/?sid=1</link>
+ <description>ã“ã“ã¯ã€[[ishinao]]専用ã®WikiLikeã§ã™ã€‚ページã®æŠ•ç¨¿ãƒ»ç·¨é›†ã¯ishinaoã—ã‹å‡ºæ¥ã¾ã›ã‚“。コメントã®æŠ•ç¨¿ã¯èª°ã§ã‚‚å¯èƒ½ã§ã™ã€‚
+
+*[[ã™ã¹ã¦:http://ishinao.net/WikiLike/view.php]]
+*[[日常:http://ishinao.net/WikiLike/view.php?query=%C6%FC%BE%EF]]
+*[[WebWatch:http://ishinao.net/WikiLike/view.php?query=WebWatch]]
+*[</description>
+ <dc:date>2003-02-28T09:35:59+00:00</dc:date>
+ <trackback:ping>http://ishinao.net/WikiLike/tb.php/1</trackback:ping>
+</item>
+</rdf:RDF>
diff --git a/sample/rss/raa-rdf10.xml b/sample/rss/raa-rdf10.xml
new file mode 100644
index 000000000..a7d3115ef
--- /dev/null
+++ b/sample/rss/raa-rdf10.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns="http://my.netscape.com/rdf/simple/0.9/">
+
+ <channel>
+ <title>Ruby App. Archive</title>
+ <link>http://raa.ruby-lang.org/</link>
+ <description>New 10 files in the Ruby Application Archive</description>
+ </channel>
+ <item>
+ <title>library: classes to manage versioned libraries</title>
+ <link>http://raa.ruby-lang.org/list.rhtml?name=library</link>
+ </item>
+
+ <item>
+ <title>sys-host: hostname and ip address info via Ruby - C extension</title>
+ <link>http://raa.ruby-lang.org/list.rhtml?name=sys-host</link>
+ </item>
+
+ <item>
+ <title>sys-uptime: 'uptime' information via Ruby - C extension</title>
+ <link>http://raa.ruby-lang.org/list.rhtml?name=sys-uptime</link>
+ </item>
+
+ <item>
+ <title>hail_ruby: most of the ruby stuff from Hail packaged as an extension</title>
+ <link>http://raa.ruby-lang.org/list.rhtml?name=hail_ruby</link>
+ </item>
+
+ <item>
+ <title>tiki: Tiki - WikiEngine</title>
+ <link>http://raa.ruby-lang.org/list.rhtml?name=tiki</link>
+ </item>
+
+ <item>
+ <title>sys-cpu: Interface for cpu information</title>
+ <link>http://raa.ruby-lang.org/list.rhtml?name=sys-cpu</link>
+ </item>
+
+ <item>
+ <title>btpgsql: Bi-Temporal PostgreSQL - manage data which changes over time</title>
+ <link>http://raa.ruby-lang.org/list.rhtml?name=btpgsql</link>
+ </item>
+
+ <item>
+ <title>ynot2day_server: YNot2Day Server Templator</title>
+ <link>http://raa.ruby-lang.org/list.rhtml?name=ynot2day_server</link>
+ </item>
+
+ <item>
+ <title>kwarts: kwa's Ruby Template System - a very fast template system</title>
+ <link>http://raa.ruby-lang.org/list.rhtml?name=kwarts</link>
+ </item>
+
+ <item>
+ <title>exerb-win32: Exerb for Windows</title>
+ <link>http://raa.ruby-lang.org/list.rhtml?name=exerb-win32</link>
+ </item>
+</rdf:RDF>
diff --git a/sample/rss/rnn.rdf b/sample/rss/rnn.rdf
new file mode 100644
index 000000000..41c5dda08
--- /dev/null
+++ b/sample/rss/rnn.rdf
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/">
+<channel>
+<title>RNN</title><link>http://rnn.sourceforge.jp</link><description>Ruby no News</description>
+<items><rdf:Seq>
+<rdf:li rdf:resource="http://rnn.sourceforge.jp/modules/news/article.php?storyid=140"/>
+<rdf:li rdf:resource="http://rnn.sourceforge.jp/modules/news/article.php?storyid=139"/>
+<rdf:li rdf:resource="http://rnn.sourceforge.jp/modules/news/article.php?storyid=138"/>
+<rdf:li rdf:resource="http://rnn.sourceforge.jp/modules/news/article.php?storyid=137"/>
+<rdf:li rdf:resource="http://rnn.sourceforge.jp/modules/news/article.php?storyid=136"/>
+</rdf:Seq></items>
+</channel>
+
+
+<item rdf:about="http://rnn.sourceforge.jp/modules/news/article.php?storyid=140">
+<title>ã¾ã¤ã‚‚ã¨ã•ã‚“ã¸ã®ã‚¤ãƒ³ã‚¿ãƒ“ュー</title>
+<link>http://rnn.sourceforge.jp/modules/news/article.php?storyid=140</link>
+<description>ã¾ã¤ã‚‚ã¨ã•ã‚“ã¸ã®ã‚¤ãƒ³ã‚¿ãƒ“ュー (Fri Mar 14 16:40:43 JST 2003)</description>
+</item>
+
+<item rdf:about="http://rnn.sourceforge.jp/modules/news/article.php?storyid=139">
+<title>kwarts -- HTMLテンプレートライブラリ</title>
+<link>http://rnn.sourceforge.jp/modules/news/article.php?storyid=139</link>
+<description>kwarts -- HTMLテンプレートライブラリ (Wed Mar 12 22:14:54 JST 2003)</description>
+</item>
+
+<item rdf:about="http://rnn.sourceforge.jp/modules/news/article.php?storyid=138">
+<title>Linux Jurnal: Ruby</title>
+<link>http://rnn.sourceforge.jp/modules/news/article.php?storyid=138</link>
+<description>Linux Jurnal: Ruby (Wed Mar 12 04:02:01 JST 2003)</description>
+</item>
+
+<item rdf:about="http://rnn.sourceforge.jp/modules/news/article.php?storyid=137">
+<title>電脳 Ruby セミナー</title>
+<link>http://rnn.sourceforge.jp/modules/news/article.php?storyid=137</link>
+<description>電脳 Ruby セミナー (Tue Mar 11 20:20:37 JST 2003)</description>
+</item>
+
+<item rdf:about="http://rnn.sourceforge.jp/modules/news/article.php?storyid=136">
+<title>KWICツールtea</title>
+<link>http://rnn.sourceforge.jp/modules/news/article.php?storyid=136</link>
+<description>KWICツールtea (Tue Mar 11 01:01:19 JST 2003)</description>
+</item>
+</rdf:RDF>
diff --git a/sample/rss/rss.xml b/sample/rss/rss.xml
new file mode 100644
index 000000000..767b605be
--- /dev/null
+++ b/sample/rss/rss.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<rss version="2.0">
+<channel>
+<title>@IT Insider.NETフォーラム</title>
+<link>http://www.atmarkit.co.jp/fdotnet/</link>
+<description>ITエンジニアå‘ã‘Webサイト@IT内ã®ã€Microsoft .NET ソリューションã®ãŸã‚ã®æŠ€è¡“情報サイトフォーラム</description>
+<language>ja-jp</language>
+<copyright>Copyright (c) 2000-2003, atmarkIT Corporation</copyright>
+<pubDate>Mon, 26 May 2003 03:00:01 +0900</pubDate>
+<image>
+<url>http://www.atmarkit.co.jp/aboutus/copyright/atit_links.gif</url>
+<link>http://www.atmarkit.co.jp/fdotnet/</link>
+</image>
+<item>
+<title>.NET TIPS - .NET開発ã®ãƒ†ã‚¯ãƒ‹ãƒƒã‚¯ã¨ãƒ’ント集 -</title>
+<link>http://www.atmarkit.co.jp/fdotnet/dotnettips/index/index.html</link>
+<description>確実ãªçµ‚了処ç†ã‚’è¡Œã†ã«ã¯ï¼Ÿãƒ”クセルã®è‰²ã‚’HTMLカラーã¸å¤‰æ›ã™ã‚‹ã«ã¯ï¼Ÿæ–‡å­—列を連çµã™ã‚‹ã«ã¯ï¼Ÿ</description>
+<category>Insider.NET</category>
+<pubDate>Sat, 30 Nov 2002 00:00:00 +0900</pubDate>
+</item>
+<item>
+<title>プログラマを.NETã«èª˜ã†VS.NET 2003ã®ãƒ©ã‚¤ãƒ³ã‚¢ãƒƒãƒ—</title>
+<link>http://www.atmarkit.co.jp/fdotnet/insiderseye/20030522vs2003/vs2003.html</link>
+<description> .NET Frameworkã‚’æ­è¼‰ã—ãŸWindowsサーãƒã¨ã¨ã‚‚ã«ã€Visual Studio .NETã®æ–°ç‰ˆãŒã„よã„よ発売ã¨ãªã‚‹ã€‚.NETソリューションã®æ™®åŠã¯åŠ é€Ÿã•ã‚Œã‚‹ã®ã‹ï¼Ÿ</description>
+<category>Insider.NET</category>
+<pubDate>Sat, 30 Nov 2002 00:00:00 +0900</pubDate>
+</item>
+<item>
+<title>èªè¨¼ã«ã‚ˆã‚‹Webサービス・クライアントã®è­˜åˆ¥</title>
+<link>http://www.atmarkit.co.jp/fdotnet/hybooks/vbnet01/vbnet01_01.html</link>
+<description>XML WebサービスをASP.NET+VB.NETã§æ§‹ç¯‰ã™ã‚‹éš›ã«åˆ©ç”¨å¯èƒ½ãªã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£åˆ¶å¾¡ã«ã¤ã„ã¦è©³ç´°ã«è§£èª¬ã—ã¦ã„ã</description>
+<category>Insider.NET</category>
+<pubDate>Sat, 30 Nov 2002 00:00:00 +0900</pubDate>
+</item>
+<item>
+<title>Visual Studio .NET 2003ã¯â€œè²·ã„â€ã‹ï¼Ÿ</title>
+<link>http://www.atmarkit.co.jp/fdotnet/questionnaire/2003-04/2003_04.html</link>
+<description>VS.NET 2003ãŒé–“ã‚‚ãªã発売ã¨ãªã‚‹ãŒã€ã“ã‚Œã«å…ˆç«‹ã¡ã‚¢ãƒ³ã‚±ãƒ¼ãƒˆèª¿æŸ»ã‚’è¡Œã£ãŸã€‚ç¾åœ¨ã®é–‹ç™ºç’°å¢ƒã¨2003ã®å°Žå…¥äºˆå®šã¯ï¼Ÿ 魅力ã¨ãªã‚‹æ–°æ©Ÿèƒ½ã¯ï¼Ÿ</description>
+<category>Insider.NET</category>
+<pubDate>Sat, 30 Nov 2002 00:00:00 +0900</pubDate>
+</item>
+<item>
+<title>ASP.NETã«ãŠã‘ã‚‹èªè¨¼ã¨èªå®š</title>
+<link>http://www.atmarkit.co.jp/fdotnet/aspnet/aspnet17/aspnet17_01.html</link>
+<description>Webアプリã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ç¢ºä¿ã¯éžå¸¸ã«é¢å€’ãªå•é¡Œã ãŒã€ASP.NETã«ã¯æ•°å°‘ãªã„手順ã§ã“れを実ç¾ã™ã‚‹ãŸã‚ã®ä»•çµ„ã¿ãŒç”¨æ„ã•ã‚Œã¦ã„ã‚‹</description>
+<category>Insider.NET</category>
+<pubDate>Sat, 30 Nov 2002 00:00:00 +0900</pubDate>
+</item>
+<item>
+<title>.NETデータ・プロãƒã‚¤ãƒ€ã«ã‚ˆã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®ã‚¢ã‚¯ã‚»ã‚¹</title>
+<link>http://www.atmarkit.co.jp/fdotnet/basics/adonet02/adonet02_01.html</link>
+<description>ADO.NETã«ã‚ˆã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ãƒ»ãƒ—ログラミングをマスターã™ã‚‹ãŸã‚ã«ã¯ã€ã¾ãšã€Œ.NETデータ・プロãƒã‚¤ãƒ€ã€ã‚’よãç†è§£ã—ã¦ãŠãã“ã¨ãŒé‡è¦ã </description>
+<category>Insider.NET</category>
+<pubDate>Sat, 30 Nov 2002 00:00:00 +0900</pubDate>
+</item>
+<item>
+<title>VS.NETã§ãƒ—ログラム・レス開発を学ã¶ï¼ˆå‰ç·¨ï¼‰</title>
+<link>http://www.atmarkit.co.jp/fdotnet/aspandvs/aspandvs02/aspandvs02_01.html</link>
+<description> VS.NETã®çµ±åˆé–‹ç™ºç’°å¢ƒãŒå¯èƒ½ã«ã™ã‚‹ã€ãƒ—ログラム・レスãªASP.NETアプリケーション開発を簡å˜ãªã‚µãƒ³ãƒ—ルã§å®Ÿä½“験</description>
+<category>Insider.NET</category>
+<pubDate>Sat, 30 Nov 2002 00:00:00 +0900</pubDate>
+</item>
+<item>
+<title>ã‚ãªãŸã®ã‚³ãƒ¼ãƒ‰ã¯ï¼ˆå†ã³ï¼‰ç”Ÿã残れるã‹</title>
+<link>http://www.atmarkit.co.jp/fdotnet/terrarium2/terrarium01/terrarium01_01.html</link>
+<description> プログラマã®æ³¨ç›®ã‚’集ã‚ãŸãƒ†ãƒ©ãƒªã‚¦ãƒ ãƒ»ã‚³ãƒ³ãƒ†ã‚¹ãƒˆãŒä»Šå¹´ã‚‚開催ã•ã‚Œã‚‹ã€‚システムã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚¢ãƒƒãƒ—ã«ã¨ã‚‚ãªã„ã€å‰å›žã®è¨˜äº‹ã‚’加筆・修正</description>
+<category>Insider.NET</category>
+<pubDate>Sat, 30 Nov 2002 00:00:00 +0900</pubDate>
+</item>
+<item>
+<title>.NET TIPS - .NET開発ã®ãƒ†ã‚¯ãƒ‹ãƒƒã‚¯ã¨ãƒ’ント集 -</title>
+<link>http://www.atmarkit.co.jp/fdotnet/dotnettips/index/index.html</link>
+<description>Win32 APIã‚„DLL関数を呼ã³å‡ºã™ã«ã¯ï¼Ÿ
+Win32 APIã‚„DLL関数ã«æ–‡å­—列ãƒãƒƒãƒ•ã‚¡ã‚’渡ã™ã«ã¯ï¼Ÿ
+Win32 APIã‚„DLL関数ã«æ§‹é€ ä½“を渡ã™ã«ã¯ï¼Ÿ</description>
+<category>Insider.NET</category>
+<pubDate>Sat, 30 Nov 2002 00:00:00 +0900</pubDate>
+</item>
+<item>
+<title>DOM(Document Object Model)ã§XML文書を扱ã†</title>
+<link>http://www.atmarkit.co.jp/fdotnet/easyxml/easyxml04/easyxml04_01.html</link>
+<description> XML文書ã«å«ã¾ã‚Œã‚‹æƒ…報をツリー構造ã«å±•é–‹ã—ã€ãƒ‡ãƒ¼ã‚¿ã¸ã®ãƒ©ãƒ³ãƒ€ãƒ ãƒ»ã‚¢ã‚¯ã‚»ã‚¹ã‚„編集をå¯èƒ½ã«ã™ã‚‹DOMを用ã„ã¦ã€.NETã§XML文書をæ“作ã™ã‚‹</description>
+<category>Insider.NET</category>
+<pubDate>Sat, 30 Nov 2002 00:00:00 +0900</pubDate>
+</item>
+</channel>
+</rss>
diff --git a/sample/rss/rss2dc.xml b/sample/rss/rss2dc.xml
new file mode 100644
index 000000000..bd107cbc4
--- /dev/null
+++ b/sample/rss/rss2dc.xml
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<rdf:RDF
+xmlns="http://purl.org/rss/1.0/"
+xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+xmlns:dc="http://purl.org/dc/elements/1.1/"
+xmlns:sy="http://purl.org/rss/modules/syndication/"
+xml:lang="ja">
+<channel rdf:about="http://www.atmarkit.co.jp">
+<title>ï¼ IT</title>
+<link>http://www.atmarkit.co.jp</link>
+<description>ITエンジニア対象ã®æŠ€è¡“解説情報&コミュニティサイト</description>
+<language>ja</language>
+<items>
+<rdf:Seq>
+<rdf:li rdf:resource="http://www.atmarkit.co.jp/fdotnet/dotnettips/index/index.html" />
+<rdf:li rdf:resource="http://www.atmarkit.co.jp/fxml/survey/survey09/xml09.html" />
+<rdf:li rdf:resource="http://www.atmarkit.co.jp/fjava/rensai2/jspservlet05/jspsevlet05_1.html" />
+<rdf:li rdf:resource="http://www.atmarkit.co.jp/fbiz/column/fl/reg117/01.html" />
+<rdf:li rdf:resource="http://www.atmarkit.co.jp/fsys/zunouhoudan/036zunou/emb_security.html" />
+<rdf:li rdf:resource="http://www.atmarkit.co.jp/fjava/devs/dstylefaq/uml/index/dstylefaquml_index.html" />
+<rdf:li rdf:resource="http://www.atmarkit.co.jp/fwin2k/verification/vpn03/vpn03_01.html" />
+<rdf:li rdf:resource="http://www.atmarkit.co.jp/fdotnet/insiderseye/20030522vs2003/vs2003.html" />
+<rdf:li rdf:resource="http://www.atmarkit.co.jp/fbiz/data/index.html" />
+<rdf:li rdf:resource="http://www.atmarkit.co.jp/fsecurity/rensai/unix_sec01/unix_sec01.html" />
+<rdf:li rdf:resource="http://www.atmarkit.co.jp/flinux/rensai/linuxtips/tipsindex.html" />
+<rdf:li rdf:resource="http://www.atmarkit.co.jp/fwin2k/insiderseye/20030519ws2003an/ws2003an.html" />
+<rdf:li rdf:resource="http://www.atmarkit.co.jp/fdotnet/hybooks/vbnet01/vbnet01_01.html" />
+<rdf:li rdf:resource="http://www.atmarkit.co.jp/fnetwork/trend/20030405/sip.html" />
+<rdf:li rdf:resource="http://www.atmarkit.co.jp/fbiz/bookreview/itroi/index.html" />
+</rdf:Seq>
+</items>
+</channel>
+<item rdf:about="http://www.atmarkit.co.jp/fdotnet/dotnettips/index/index.html">
+<title>.NET TIPS - .NET開発ã®ãƒ†ã‚¯ãƒ‹ãƒƒã‚¯ã¨ãƒ’ント集 -</title>
+<link>http://www.atmarkit.co.jp/fdotnet/dotnettips/index/index.html</link>
+<description>確実ãªçµ‚了処ç†ã‚’è¡Œã†ã«ã¯ï¼Ÿ
+ピクセルã®è‰²ã‚’HTMLカラーã¸å¤‰æ›ã™ã‚‹ã«ã¯ï¼Ÿ
+文字列を連çµã™ã‚‹ã«ã¯ï¼Ÿ</description>
+<category>Insider.NET</category>
+<dc:subject></dc:subject>
+<dc:creator>
+
+</dc:creator>
+<dc:date>2003-05-23T00:00:00+09:00</dc:date>
+</item>
+<item rdf:about="http://www.atmarkit.co.jp/fxml/survey/survey09/xml09.html">
+<title>読者ã®XMLã¨Webサービスã®æ´»ç”¨çŠ¶æ³ã¯ï¼Ÿ</title>
+<link>http://www.atmarkit.co.jp/fxml/survey/survey09/xml09.html</link>
+<description>2å¹´åŠå‰ã®èª¿æŸ»ã¨æ¯”ã¹ã¦XMLã®åˆ©ç”¨çŽ‡ã¯å€ä»¥ä¸Šã«ã€‚一方ã§ç¾çŠ¶ã¯Webサービスを利用ã™ã‚‹äºˆå®šãŒãªã„ã€ã¨ã„ã†èª­è€…ã®ç†ç”±ã‚‚明らã‹ã«</description>
+<category>XML &amp; Web Services</category>
+<dc:subject></dc:subject>
+<dc:creator>
+
+</dc:creator>
+<dc:date>2003-05-23T00:00:00+09:00</dc:date>
+</item>
+<item rdf:about="http://www.atmarkit.co.jp/fjava/rensai2/jspservlet05/jspsevlet05_1.html">
+<title>JSPã®åŸºæœ¬ã€Œæš—黙オブジェクトã€ã‚’使ã†</title>
+<link>http://www.atmarkit.co.jp/fjava/rensai2/jspservlet05/jspsevlet05_1.html</link>
+<description>暗黙オブジェクトã¯Webプログラミングã«ãªãã¦ãªã‚‰ãªã„機能を集約ã—ã¦ã„ã¾ã™ã€‚今回ã‹ã‚‰2回ã«åˆ†ã‘ã¦ãã®ä½¿ã„方をç†è§£ã—ã¾ã™</description>
+<category>Java Solution</category>
+<dc:subject></dc:subject>
+<dc:creator>
+山田祥寛
+</dc:creator>
+<dc:date>2003-05-23T00:00:00+09:00</dc:date>
+</item>
+<item rdf:about="http://www.atmarkit.co.jp/fbiz/column/fl/reg117/01.html">
+<title>æ–°ã—ã„ãƒãƒƒãƒˆåºƒå‘Šãƒ¢ãƒ‡ãƒ«ã€ŒPPCSEã€ãŒé–‹ã未æ¥</title>
+<link>http://www.atmarkit.co.jp/fbiz/column/fl/reg117/01.html</link>
+<description> ã²ã‚“æ­»ã®ã‚¤ãƒ³ã‚¿ãƒ¼ãƒãƒƒãƒˆåºƒå‘Šæ¥­ç•Œã«ç¾ã‚ŒãŸæ•‘世主「PPC検索エンジンã€ã€‚“広告â€ã¨â€œã‚¤ãƒ³ã‚¿ãƒ¼ãƒãƒƒãƒˆâ€ã¯ã©ã®ã‚ˆã†ã«â€œä¸¡ç«‹â€ã™ã‚‹ã®ã‹</description>
+<category>Business Computing</category>
+<dc:subject></dc:subject>
+<dc:creator>
+
+</dc:creator>
+<dc:date>2003-05-23T00:00:00+09:00</dc:date>
+</item>
+<item rdf:about="http://www.atmarkit.co.jp/fsys/zunouhoudan/036zunou/emb_security.html">
+<title>組ã¿è¾¼ã¿ç”¨é€”ã§ã‚‚セキュリティãŒå¤§æ³¨ç›®ï¼Ÿ</title>
+<link>http://www.atmarkit.co.jp/fsys/zunouhoudan/036zunou/emb_security.html</link>
+<description> Suicaã‚„ETCã«ä»£è¡¨ã•ã‚Œã‚‹ã‚ˆã†ãªçµ„ã¿è¾¼ã¿åˆ†é‡Žã§ã¯èªè¨¼ãŒå¿…須。ã“ã†ã—ãŸç”¨é€”ã§ã¯ã€ã©ã®ã‚ˆã†ã«ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚’確ä¿ã—ã¦ã„ã‚‹ã®ã ã‚ã†ã‹ï¼Ÿ</description>
+<category>System Insider</category>
+<dc:subject></dc:subject>
+<dc:creator>
+Massa POP Izumida
+</dc:creator>
+<dc:date>2003-05-22T00:00:00+09:00</dc:date>
+</item>
+<item rdf:about="http://www.atmarkit.co.jp/fjava/devs/dstylefaq/uml/index/dstylefaquml_index.html">
+<title>Q)UMLã®9種類ã®ãƒ€ã‚¤ã‚¢ã‚°ãƒ©ãƒ ã¨ã¯ï¼Ÿ</title>
+<link>http://www.atmarkit.co.jp/fjava/devs/dstylefaq/uml/index/dstylefaquml_index.html</link>
+<description>9種類ã®UMLダイアグラムãŒã‚ªãƒ–ジェクト指å‘開発ã®å„工程ã§ã©ã®ã‚ˆã†ãªå½¹å‰²ã‚’æžœãŸã™ã®ã‹ã€‚ダイアグラムã®åŸºæœ¬ã‚’詳細ã«è§£èª¬ã™ã‚‹</description>
+<category>Java Solution</category>
+<dc:subject></dc:subject>
+<dc:creator>
+羽生田栄一
+</dc:creator>
+<dc:date>2003-05-22T00:00:00+09:00</dc:date>
+</item>
+<item rdf:about="http://www.atmarkit.co.jp/fwin2k/verification/vpn03/vpn03_01.html">
+<title>PPTPサーãƒã®æ§‹ç¯‰</title>
+<link>http://www.atmarkit.co.jp/fwin2k/verification/vpn03/vpn03_01.html</link>
+<description> 今回ã‹ã‚‰ã¯å®Ÿéš›ã«VPN環境を構築ã—ã¦ã¿ã‚‹ã€‚ã¾ãšã¯Active Directoryドメインã®å°Žå…¥ã¨PPTPã«ã‚ˆã‚‹VPNサーãƒã®å°Žå…¥æ–¹æ³•ã«ã¤ã„ã¦è§£èª¬ã™ã‚‹</description>
+<category>Windows Server Insider</category>
+<dc:subject></dc:subject>
+<dc:creator>
+デジタルアドãƒãƒ³ãƒ†ãƒ¼ã‚¸
+</dc:creator>
+<dc:date>2003-05-22T00:00:00+09:00</dc:date>
+</item>
+<item rdf:about="http://www.atmarkit.co.jp/fdotnet/insiderseye/20030522vs2003/vs2003.html">
+<title>プログラマを.NETã«èª˜ã†VS.NET 2003ã®ãƒ©ã‚¤ãƒ³ã‚¢ãƒƒãƒ—</title>
+<link>http://www.atmarkit.co.jp/fdotnet/insiderseye/20030522vs2003/vs2003.html</link>
+<description> .NET Frameworkã‚’æ­è¼‰ã—ãŸWindowsサーãƒã¨ã¨ã‚‚ã«ã€Visual Studio .NETã®æ–°ç‰ˆãŒã„よã„よ発売ã¨ãªã‚‹ã€‚.NETソリューションã®æ™®åŠã¯åŠ é€Ÿã•ã‚Œã‚‹ã®ã‹ï¼Ÿ</description>
+<category>Insider.NET</category>
+<dc:subject></dc:subject>
+<dc:creator>
+デジタルアドãƒãƒ³ãƒ†ãƒ¼ã‚¸
+</dc:creator>
+<dc:date>2003-05-22T00:00:00+09:00</dc:date>
+</item>
+<item rdf:about="http://www.atmarkit.co.jp/fbiz/data/index.html">
+<title>Business &amp; IT DataLinks(IT業界データ集)</title>
+<link>http://www.atmarkit.co.jp/fbiz/data/index.html</link>
+<description>−「ソリューション・サービス市場動å‘調査ã€&lt;br&gt;−「ä¸æ­£ã‚¢ã‚¯ã‚»ã‚¹è¡Œç‚ºå¯¾ç­–ã®å®Ÿæ…‹èª¿æŸ»ã€&lt;br&gt;ãªã©ã€5月10æ—¥ã¾ã§ã®ãƒ‡ãƒ¼ã‚¿ã‚’12件追加</description>
+<category>Business Computing</category>
+<dc:subject></dc:subject>
+<dc:creator>
+
+</dc:creator>
+<dc:date>2003-05-22T00:00:00+09:00</dc:date>
+</item>
+<item rdf:about="http://www.atmarkit.co.jp/fsecurity/rensai/unix_sec01/unix_sec01.html">
+<title>ä¸è¦ãªã‚µãƒ¼ãƒ“スã®åœæ­¢ã“ã管ç†ã®ç¬¬ä¸€æ­©</title>
+<link>http://www.atmarkit.co.jp/fsecurity/rensai/unix_sec01/unix_sec01.html</link>
+<description> 悩ã¾ã—ã„ã®ã¯åœæ­¢ã§ããªã„サーãƒã®ç®¡ç†ã€‚稼åƒã‚µãƒ¼ãƒ“スã®åœæ­¢ã‚’最å°é™ã«æŠ‘ãˆãŸã€ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£å‘上ã®è¨­å®šã‚„ツールを紹介</description>
+<category>Security&amp;Trust</category>
+<dc:subject></dc:subject>
+<dc:creator>
+
+</dc:creator>
+<dc:date>2003-05-22T00:00:00+09:00</dc:date>
+</item>
+<item rdf:about="http://www.atmarkit.co.jp/flinux/rensai/linuxtips/tipsindex.html">
+<title>Linux Tips</title>
+<link>http://www.atmarkit.co.jp/flinux/rensai/linuxtips/tipsindex.html</link>
+<description>Red Hat Linuxã§APTを使ã†ã«ã¯
+sshã§ãƒ‘スワードãªã—ã«ãƒ­ã‚°ã‚¤ãƒ³ã™ã‚‹ã«ã¯
+Unicodeã®ãƒ†ã‚­ã‚¹ãƒˆãƒ•ã‚¡ã‚¤ãƒ«ã‚’ã»ã‹ã®æ–‡å­—コードã«å¤‰æ›</description>
+<category>Linux Square</category>
+<dc:subject></dc:subject>
+<dc:creator>
+
+</dc:creator>
+<dc:date>2003-05-22T00:00:00+09:00</dc:date>
+</item>
+<item rdf:about="http://www.atmarkit.co.jp/fwin2k/insiderseye/20030519ws2003an/ws2003an.html">
+<title>Windows Server 2003日本語版ãŒã„よã„よ登場</title>
+<link>http://www.atmarkit.co.jp/fwin2k/insiderseye/20030519ws2003an/ws2003an.html</link>
+<description> 次世代サーãƒã€ŒWindows Server 2003ã€ã€æœ€æ–°é–‹ç™ºç’°å¢ƒã€64bit対応ã®SQL
+ServerãŒåŒæ—¥ç™ºè¡¨ã€‚.NET戦略ã¯åŠ é€Ÿã•ã‚Œã‚‹ã®ã‹ï¼Ÿ</description>
+<category>Windows Server Insider</category>
+<dc:subject></dc:subject>
+<dc:creator>
+デジタルアドãƒãƒ³ãƒ†ãƒ¼ã‚¸
+</dc:creator>
+<dc:date>2003-05-21T00:00:00+09:00</dc:date>
+</item>
+<item rdf:about="http://www.atmarkit.co.jp/fdotnet/hybooks/vbnet01/vbnet01_01.html">
+<title>èªè¨¼ã«ã‚ˆã‚‹Webサービス・クライアントã®è­˜åˆ¥</title>
+<link>http://www.atmarkit.co.jp/fdotnet/hybooks/vbnet01/vbnet01_01.html</link>
+<description>XML WebサービスをASP.NET+VB.NETã§æ§‹ç¯‰ã™ã‚‹éš›ã«åˆ©ç”¨å¯èƒ½ãªã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£åˆ¶å¾¡ã«ã¤ã„ã¦è©³ç´°ã«è§£èª¬ã—ã¦ã„ã</description>
+<category>Insider.NET</category>
+<dc:subject></dc:subject>
+<dc:creator>
+
+</dc:creator>
+<dc:date>2003-05-21T00:00:00+09:00</dc:date>
+</item>
+<item rdf:about="http://www.atmarkit.co.jp/fnetwork/trend/20030405/sip.html">
+<title>SIP:マイクロソフトãŒIP電話をé¢ç™½ãã™ã‚‹!?</title>
+<link>http://www.atmarkit.co.jp/fnetwork/trend/20030405/sip.html</link>
+<description> IP網ã¨é›»è©±ç¶²ã‚’çµ±åˆã•ã›ã‚‹VoIPã®ã€åŸºç›¤æŠ€è¡“ã®1ã¤ã€ŒSIPã€ã€‚ MSã®æ–°ã‚µãƒ¼ãƒã§ã‚‚対応ãŒå§‹ã¾ã£ãŸã€ã“ã®éŸ³å£°ã‚„ç”»åƒãªã©ã‚’扱ã†ãƒ—ロトコルã¯ãªãœé‡è¦ãªã®ã‹</description>
+<category>Master of IP Network</category>
+<dc:subject></dc:subject>
+<dc:creator>
+鈴木淳也
+</dc:creator>
+<dc:date>2003-05-21T00:00:00+09:00</dc:date>
+</item>
+<item rdf:about="http://www.atmarkit.co.jp/fbiz/bookreview/itroi/index.html">
+<title>æ­£ã—ã„IT投資を目指ã™ãŸã‚ã®5冊</title>
+<link>http://www.atmarkit.co.jp/fbiz/bookreview/itroi/index.html</link>
+<description> 特集「ã„ã¾ã‹ã‚‰å§‹ã‚ã‚‹IT投資効果測定ã€é€£å‹•ä¼ç”»ã€‚ã„ã¾ã¾ã•ã«ITã®ROI測定ã¸å–り組もã†ã¨ã„ã†æ–¹ã€å…·ä½“ç­–ãŒã‚ã‹ã‚‰ãšæ‚©ã‚“ã§ã„ã‚‹æ–¹ã«ã‚ªã‚¹ã‚¹ãƒ¡ã®5冊を紹介</description>
+<category>Business Computing</category>
+<dc:subject></dc:subject>
+<dc:creator>
+
+</dc:creator>
+<dc:date>2003-05-21T00:00:00+09:00</dc:date>
+</item>
+</rdf:RDF> \ No newline at end of file
diff --git a/sample/rss/rssMarkPilgrimExample.xml b/sample/rss/rssMarkPilgrimExample.xml
new file mode 100644
index 000000000..d6600d461
--- /dev/null
+++ b/sample/rss/rssMarkPilgrimExample.xml
@@ -0,0 +1,271 @@
+<?xml version="1.0" encoding="utf-8"?>
+<rss version="2.0"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
+ xmlns:admin="http://webns.net/mvcb/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:content="http://purl.org/rss/1.0/modules/content/">
+
+ <channel>
+ <title>dive into mark</title>
+ <link>http://diveintomark.org/</link>
+ <description>A lot of effort went into making this effortless.</description>
+ <dc:language>en-us</dc:language>
+ <dc:creator>f8dy@diveintomark.org</dc:creator>
+ <dc:rights>Copyright 2002</dc:rights>
+ <dc:date>2002-09-29T23:40:06-05:00</dc:date>
+ <admin:generatorAgent rdf:resource="http://www.movabletype.org/?v=2.21" />
+ <admin:errorReportsTo rdf:resource="mailto:f8dy@diveintomark.org"/>
+ <sy:updatePeriod>hourly</sy:updatePeriod>
+ <sy:updateFrequency>1</sy:updateFrequency>
+ <sy:updateBase>2000-01-01T12:00+00:00</sy:updateBase>
+
+
+ <item>
+ <title>Dooce</title>
+ <link>http://diveintomark.org/archives/2002/09/29.html#dooce</link>
+ <description>Reborn.</description>
+ <guid isPermaLink="false">1856@http://diveintomark.org/</guid>
+ <content:encoded><![CDATA[<p><a href="http://www.dooce.com/">Reborn</a>.</p>]]></content:encoded>
+ <dc:subject></dc:subject>
+ <dc:date>2002-09-29T23:40:06-05:00</dc:date>
+ </item>
+
+ <item>
+ <title>Advanced CSS lists</title>
+ <link>http://diveintomark.org/archives/2002/09/27.html#advanced_css_lists</link>
+ <description>Mark Newhouse: CSS Design: Taming Lists. &quot;I'll demonstrate how to use CSS to bring unwieldy lists under control. It's time for you to tell lists how to behave, instead of letting them run wild on your web page.&quot;</description>
+ <guid isPermaLink="false">1855@http://diveintomark.org/</guid>
+ <content:encoded><![CDATA[<p><cite title="A List Apart">Mark Newhouse</cite>: <a href="http://www.alistapart.com/stories/taminglists/">CSS Design: Taming Lists</a>. <q>I'll demonstrate how to use CSS to bring unwieldy lists under control. It's time for you to tell lists how to behave, instead of letting them run wild on your web page.</q></p>]]></content:encoded>
+ <dc:subject>CSS</dc:subject>
+ <dc:date>2002-09-27T23:22:56-05:00</dc:date>
+ </item>
+
+ <item>
+ <title>Pingback vs. Trackback</title>
+ <link>http://diveintomark.org/archives/2002/09/27.html#pingback_vs_trackback</link>
+ <description>Ian Hickson: Whitepaper: Pingback vs Trackback. &quot;It seems pingback has caused quite a stir in the Web logging and syndication communities.&quot;</description>
+ <guid isPermaLink="false">1854@http://diveintomark.org/</guid>
+ <content:encoded><![CDATA[<p><cite>Ian Hickson</cite>: <a href="http://ln.hixie.ch/?start=1033171507&amp;count=1">Whitepaper: Pingback vs Trackback</a>. <q>It seems pingback has caused quite a stir in the Web logging and syndication communities! The spec is barely a week old and already I'm seeing pingbacks on sites of people I've never heard of, so implementations are spreading, which is great. It also seems pingback has acted a little like a kick in the backside to the trackback folk, causing them to work on the transparency side of trackback, which is good to see too.</q></p>]]></content:encoded>
+ <dc:subject></dc:subject>
+ <dc:date>2002-09-27T23:17:51-05:00</dc:date>
+ </item>
+
+ <item>
+ <title>Introduction</title>
+ <link>http://diveintomark.org/archives/2002/09/27.html#introduction</link>
+ <description>Jeffrey Zeldman: &quot;Welcome to zeldman.com, a poorly designed website that hides vital content from its many naive, first-time visitors.</description>
+ <guid isPermaLink="false">1853@http://diveintomark.org/</guid>
+ <content:encoded><![CDATA[<p><cite>Jeffrey Zeldman</cite>: <q><a href="http://www.zeldman.com/daily/0902b.html#medesignprettyoneday">Welcome to zeldman.com</a>, a poorly designed website that hides vital content from its many naive, first-time visitors.</q></p>]]></content:encoded>
+ <dc:subject></dc:subject>
+ <dc:date>2002-09-27T18:16:54-05:00</dc:date>
+ </item>
+
+ <item>
+ <title>It's Google's world, we just live in it</title>
+ <link>http://diveintomark.org/archives/2002/09/27.html#its_googles_world_we_just_live_in_it</link>
+ <description>Results of a Google search for &quot;It's so-and-so's world, we just live in it&quot;.</description>
+ <guid isPermaLink="false">1851@http://diveintomark.org/</guid>
+ <content:encoded><![CDATA[<p>A Google search for <a href="http://www.google.com/search?q=%22world+we+just+live+in+it%22">"world we just live in it"</a> reveals that:</p>
+
+<ul>
+<li><a href="http://www.cinepad.com/sinatra/sinatra.htm">It's Frank [Sinatra]'s world, we just live in it</a></li>
+<li><a href="http://www.poopoochoochoo.com/">It's Mandy's world, we just live in it</a></li>
+<li><a href="http://members.tripod.com/~cshel/elijah.html">It's Elijah [Jordan Wood]'s world, we just live in it</a></li>
+<li><a href="http://jerseybeat1.homestead.com/files/52601.html">It's 'N Sync's world, we just live in it</a></li>
+<li><a href="http://www.vh1.com/artists/news/1444632/06202001/aerosmith.jhtml">It's Aerosmith's world, we just live in it</a></li>
+<li><a href="http://www.biennaleofsydney.com.au/vidprog.asp#14">It's Jim's world, we just live in it</a></li>
+<li><a href="http://members.tripod.com/ddraven/psh/">It's Philip [Seymour Hoffman]'s world, we just live in it</a></li>
+<li><a href="http://espn.go.com/page2/s/wiley/001108.html">It's Jeet's [Derek Sanderson Jeter's] world, we just live in it</a></li>
+<li><a href="http://www.bcr.com/bcrmag/1998/11/p06.asp">It's the ILECs' world, we just live in it</a></li>
+<li><a href="http://www.business2.com/articles/mag/0,1640,37760,FF.html">It's Walmart's world, we just live in it</a></li>
+<li><a href="http://www.geocities.com/waltripworld/">It's Mikey's [Michael Waltrip's] world, we just live in it</a></li>
+<li><a href="http://www.angelfire.com/geek/BiancaBrandt/index.html">It's Bianca [Brandt]'s world, we just live in it</a></li>
+<li><a href="http://www.curtsandoval.com/family.htm">It's Tulip's world, we just live in it</a></li>
+<li><a href="http://www.chaseclub.com/news23.htm">It's Bill Gates' world, we just live in it</a></li>
+<li><a href="http://www.cnet.com/software/0-3227883-8-7614087-6.html">It's Microsoft's world, we just live in it</a></li>
+<li><a href="http://www.linux-mag.com/1999-05/linus_01.html">It's Linus [Torvalds]' world, we just live in it</a></li>
+<li><a href="http://www.geocities.com/michellebranchsworld/home.html">It's Michelle Branch's world, we just live in it</a></li>
+<li><a href="http://www.popmatters.com/music/reviews/g/guidedbyvoices-universal.shtml">It's Robert Pollard's world, we just live in it</a></li>
+<li><a href="http://www.theprimeone.com/archives/000067.html">It's Anna and Grace's world, we just live in it</a></li>
+<li><a href="http://www.salon.com/ent/tv/mill/1999/03/08mill.html">It's Mulder and Scully's world, we just live in it</a></li>
+<li><a href="http://www.brunching.com/gladiator.html">It's Russell Crowe's world, we just live in it</a></li>
+<li><a href="http://www.epinions.com/mvie-review-5B0-D8DF92D-38791117-prod1">It's Fellini's world, we just live in it</a></li>
+<li><a href="http://hometown.aol.com/radarama1/">It's Cairo's world, we just live in it</a></li>
+</ul>
+
+<p>And finally:</p>
+
+<ul>
+<li><a href="http://www.snopes.com/weddings/embarras/bothered.htm">It's the Bothered Bride [or Groom]'s world, we just live in it</a></li>
+</ul>
+
+<p></p>]]></content:encoded>
+ <dc:subject></dc:subject>
+ <dc:date>2002-09-27T15:43:02-05:00</dc:date>
+ </item>
+
+ <item>
+ <title>Semantic mapping of RSS elements</title>
+ <link>http://diveintomark.org/archives/2002/09/27.html#semantic_mapping_of_rss_elements</link>
+ <description>Sam Ruby has started a discussion of mapping core RSS elements to namespace-based equivalents.</description>
+ <guid isPermaLink="false">1850@http://diveintomark.org/</guid>
+ <content:encoded><![CDATA[<p>Sam Ruby has started a discussion of <a href="http://groups.yahoo.com/group/rss-dev/message/4124">mapping core RSS elements to namespace-based equivalents</a>. This is useful for developers who want to consume RSS 2.0 feeds and want to know how to handle the new namespace-based elements. Already support <code>language</code>? Be on the lookout for <code>dc:language</code> as well. And so forth. The mapping isn't always that direct (some elements use different formats, like <code>pubDate</code> and <code>dc:date</code>), but it's a good start to an important discussion.</p>]]></content:encoded>
+ <dc:subject></dc:subject>
+ <dc:date>2002-09-27T13:40:34-05:00</dc:date>
+ </item>
+
+ <item>
+ <title>Repair</title>
+ <link>http://diveintomark.org/archives/2002/09/27.html#repair</link>
+ <description>Kevin Guilfoile: The Half-Assed Handyman.</description>
+ <guid isPermaLink="false">1849@http://diveintomark.org/</guid>
+ <content:encoded><![CDATA[<p><cite title="The Morning News">Kevin Guilfoile</cite>: <a href="http://www.themorningnews.org/archives/stories/the_halfassed_handyman.shtml">The Half-Assed Handyman</a>. <q>Once the Half-Assed Handyman decides on a course of repair he must remain committed to it by fixing the broken object the same way over and over, even though the method is clearly ineffective, or even nonsensical.</q></p>]]></content:encoded>
+ <dc:subject>Writers</dc:subject>
+ <dc:date>2002-09-27T13:30:01-05:00</dc:date>
+ </item>
+
+ <item>
+ <title>Rescued pictures</title>
+ <link>http://diveintomark.org/archives/2002/09/27.html#rescued_pictures</link>
+ <description>18 rescued pictures, from 1920, 1983, 1990, 2000, and 2001.</description>
+ <guid isPermaLink="false">1848@http://diveintomark.org/</guid>
+ <content:encoded><![CDATA[<p><a href="http://diveintomark.org/pictures/rescued_pictures/">18 rescued pictures</a>, from 1920, 1983, 1990, 2000, and 2001.</p>]]></content:encoded>
+ <dc:subject>Personal</dc:subject>
+ <dc:date>2002-09-27T01:23:29-05:00</dc:date>
+ </item>
+
+ <item>
+ <title>Chicks dig that</title>
+ <link>http://diveintomark.org/archives/2002/09/27.html#chicks_dig_that</link>
+ <description>Slashdot: 37 Operating Systems, 1 PC.</description>
+ <guid isPermaLink="false">1846@http://diveintomark.org/</guid>
+ <content:encoded><![CDATA[<p><a href="http://www.maximumpc.com/features/feature_2002-09-24.html">One PC, Six Hard Drives, 37 OSes</a>! [via Slashdot: <a href="http://slashdot.org/article.pl?sid=02/09/26/1225200&amp;mode=nested&amp;tid=99&amp;threshold=3">37 Operating Systems, 1 PC</a>]</p>
+
+<blockquote>
+<p>Q: Were there any OSes you couldn't find?</p>
+<p>A: I couldn't find an OS that would tell me how to successfully deal with girls.</p>
+</blockquote>
+
+<p><a href="http://diveintomark.org/pictures/christmas_2001/86.html">Mac OS X, baby</a>. <a href="http://diveintomark.org/pictures/christmas_2001/87.html">Mac OS X</a>.</p>]]></content:encoded>
+ <dc:subject></dc:subject>
+ <dc:date>2002-09-27T01:12:29-05:00</dc:date>
+ </item>
+
+ <item>
+ <title>RSS 2.0 template</title>
+ <link>http://diveintomark.org/archives/2002/09/26.html#rss_20_template</link>
+ <description>RSS 2.0 template for Movable Type, ready to copy and paste over your existing RSS 0.91 template (index.xml). There are several design decisions at work in this tempate that bear explaining.</description>
+ <guid isPermaLink="false">1844@http://diveintomark.org/</guid>
+ <content:encoded><![CDATA[<p><a href="http://diveintomark.org/public/rss2.tmpl">RSS 2.0 template for Movable Type</a>, ready to copy and paste over your existing RSS 0.91 template (<code>index.xml</code>). No modifications are required, unless your weblog is in a language other than English, in which case you'll need to change the <code>dc:language</code> tag to <a href="http://www.loc.gov/standards/iso639-2/englangn.html">your language code</a>. (Use the 2-letter language code, unless there isn't one for your language, in which case, use the 3-letter language code. And while you're at it, put the same language code <a href="http://diveintoaccessibility.org/day_7_identifying_your_language.html">in your <code>HTML</code> tag</a> in your normal page templates. But I digress.)</p>
+
+<p><a href="http://diveintomark.org/xml/rss2.xml">Here's what the RSS 2.0 output looks like</a>.</p>
+
+<p>There are several design decisions at work in this template that bear explaining. First of all, this template is designed to be backward-compatible with all existing aggregators, news readers, and RSS parsers, ranging from the super-smart XML parser built into .NET to the dumb, minimal, regular-expression-based parser that your downstairs neighbor banged out on a Friday night. If you upgrade your existing <code>index.xml</code> right now, none of these parsers should crash, and none of your subscribers should scream bloody murder. This is a good thing.</p>
+
+<p>Now then, if you look at the template, you'll notice a whole slew of lines at the top like <code>xmlns:dc="..."</code>. These are namespaces. Keven Hemenway has written an excellent primer on <a href="http://www.disobey.com/detergent/2002/extendingrss2/">extending RSS 2.0 with namespaces</a>, so I won't explain them here except to say that we use them, and you should get used to seeing them. Most RSS 2.0 documents you see will use namespaces in some way, because they are the primary way of adding functionality beyond the basic title-link-description combination. If all you want is title-link-description, stick with your existing RSS 0.91 template and stop reading now.</p>
+
+<p>Still here? OK. Now, the <a href="http://backend.userland.com/rss">RSS 2.0 specification</a> says nothing about how to actually use namespaces in RSS, just that you're allowed to. So where did these particular namespaces come from? Well, I didn't make them up. They have been developed over the past two years by some smart people, most of whom hang out on the <a href="http://groups.yahoo.com/group/rss-dev/">RSS-DEV mailing list</a>. The namespaces were originally developed for RSS 1.0, and most of them can be used without modification in RSS 2.0. (There's a lot of stuff I'm skipping over here on purpose. There will be a lot more documentation forthcoming in the next few months on exactly how to use various namespaces in RSS 2.0. Some of it still needs to be worked out, but most of it just needs to be written down. Please be patient.)</p>
+
+<p>So anyway, we use namespaces for a lot of stuff. Most stuff, in fact. In the template, you'll see title-link-description for <code>channel</code>, and title-link-description-guid for <code>item</code>. <code>guid</code> is new in RSS 2.0, and it is used to uniquely identify an item, so even if the title or description changes, aggregators know that it's the same item; the end user can choose whether to re-display changed items, but first programs need to be able to track which items are which. (<a href="http://radio.userland.com/">Radio Userland</a> already supports this.) To create the <code>guid</code>, I've combined <code>MTEntryID</code> with <code>MTBlogURL</code> to generate a unique string for each item, and I've arranged them so there's no confusion about it possibly being a URL. It's not a URL; it's just a unique string. (Other systems have stricter format requirements for guids, but RSS 2.0 does not. A guid is a unique string, and that's all.)</p>
+
+<p>Pretty much everything beyond title-link-description (and guid) uses namespaces. This template makes use of all 3 of the <a href="http://purl.org/rss/1.0/modules/standard.html">standard RSS 1.0 namespaces</a>, but there are many other <a href="http://purl.org/rss/1.0/modules/proposed.html">proposed namespaces</a> that have a lot of good design behind them. We use one (<code>admin</code>), which is already widely used; the rest may be useful to you, depending on your niche. (If you think you need to design your own namespace, look through that list and make sure you're not re-inventing the wheel.)</p>
+
+<p>Back to the template. Other than guid, the most important thing to note about this template is that the <code>title</code>, <code>link</code>, and <code>description</code> are all plain text. (<code>description</code> is an excerpt; if you do not enter an excerpt manually for a post, Movable Type will auto-generate one. You can control how long this auto-generated excerpt is by going to Blog Config, then Preferences, then <q>Number of words in excerpt</q>.) <code>title</code> was always supposed to be plain text, but sticking to plain text in the <code>description</code> tag is an intentional compromise, to support parsers that can not handle HTML, or handle it improperly. Never fear, the full HTML text of your post is still included; it's stored in the <code>content:encoded</code> element. (<a href="http://bitworking.org/Aggie.html">Aggie</a> already supports this.) This allows more robust news readers -- that can handle either text or HTML -- to offer the end user the choice of whether to see excerpts or full posts. Some people use news aggregators to find things to read, others like reading everything directly in their aggregator. RSS 0.9x made you (the author) choose one or the other; RSS 2.0 allows you to offer both, and pass the choice along to the end user. This is a good thing.</p>
+
+<p>There's more good stuff in there, but the explanations will have to wait for another day. If you're interested in learning how to extend RSS to suit your needs, your best bet is to read through the documentation of the existing RSS 1.0 namespaces. If you have questions, your best bet is the <a href="http://groups.yahoo.com/group/rss-dev/">RSS-DEV mailing list</a>, where Kevin is currently <a href="http://groups.yahoo.com/group/rss-dev/message/4046">discussing his namespace primer</a>. Archives are public and free, so no subscription is required, and lurking is encouraged.</p>
+
+<p>And watch this space.</p>]]></content:encoded>
+ <dc:subject>Weblogging</dc:subject>
+ <dc:date>2002-09-26T01:28:52-05:00</dc:date>
+ </item>
+
+ <item>
+ <title>FOAF explorer</title>
+ <link>http://diveintomark.org/archives/2002/09/25.html#foaf_explorer</link>
+ <description>Morten Frederiksen has taken a first stab at a real-time social network explorer based on FOAF files. It's heavy on tech details, but you can easily see the potential here.</description>
+ <guid isPermaLink="false">1843@http://diveintomark.org/</guid>
+ <content:encoded><![CDATA[<p>Morten Frederiksen has taken a first stab at a real-time social network explorer based on FOAF files. You could <a href="http://xml.mfd-consult.dk/foaf/?foaf=http%3A%2F%2Fdiveintomark.org%2Fpublic%2Ffoaf.rdf">start on my profile</a> and explore from there, or enter the URL of your own FOAF file (at the bottom of the page). It's heavy on tech details, but you can easily see the potential here. (It's also a great way to debug your FOAF file, if you added anything manually.) Now we need somebody to build a spider that follows <code>foaf:knows</code> links and draws pretty social network diagrams, so we can see the forest for the trees.</p>]]></content:encoded>
+ <dc:subject></dc:subject>
+ <dc:date>2002-09-25T18:18:53-05:00</dc:date>
+ </item>
+
+ <item>
+ <title>Maps</title>
+ <link>http://diveintomark.org/archives/2002/09/25.html#maps</link>
+ <description>Mark Tosczak @ Wired: A New Way to Read, Not See, Maps.</description>
+ <guid isPermaLink="false">1842@http://diveintomark.org/</guid>
+ <content:encoded><![CDATA[<p><cite title="Wired News">Mark Tosczak</cite>: <a href="http://www.wired.com/news/school/0,1383,54916,00.html">A New Way to Read, Not See, Maps</a>. <q>The map-navigation software, dubbed Blind Audio Tactile Mapping System ... takes digital map information and provides nonvisual feedback as a user moves a cursor across the map.</q></p>]]></content:encoded>
+ <dc:subject>Accessibility</dc:subject>
+ <dc:date>2002-09-25T10:45:15-05:00</dc:date>
+ </item>
+
+ <item>
+ <title>Plan</title>
+ <link>http://diveintomark.org/archives/2002/09/25.html#plan</link>
+ <description>Paul Ford: Falling Off a Truck. &quot;In the last 4 days I fell off a truck and was dragged for 30 feet, and was interviewed by an NPR show. Those two facts are not related except that they both happened to me and made me queasy. I also wrote a short plan outlining the rest of my life.&quot;</description>
+ <guid isPermaLink="false">1841@http://diveintomark.org/</guid>
+ <content:encoded><![CDATA[<p><cite>Paul Ford</cite>: <a href="http://ftrain.com/recent_update_etc.html">Falling Off a Truck</a>. <q>In the last 4 days I fell off a truck and was dragged for 30 feet, and was interviewed by an NPR show. Those two facts are not related except that they both happened to me and made me queasy. I also wrote a short plan outlining the rest of my life.</q></p>]]></content:encoded>
+ <dc:subject>Writers</dc:subject>
+ <dc:date>2002-09-25T10:43:06-05:00</dc:date>
+ </item>
+
+ <item>
+ <title>RSS revolt</title>
+ <link>http://diveintomark.org/archives/2002/09/25.html#rss_revolt</link>
+ <description>People appear to be sick of the syndication format wars. Some are protesting, some are creating new formats with new names, others are simply boycotting.</description>
+ <guid isPermaLink="false">1840@http://diveintomark.org/</guid>
+ <content:encoded><![CDATA[<p><cite>Anil Dash</cite>: <a href="http://www.dashes.com/anil/index.php?archives/003183.php">XML version 1.0</a>. <q>Why isn't there a way to syndicate my words without butchering the way they look?</q> Several people protested last week by changing their weblog templates to <a href="http://www.dashes.com/anil/xmlindex.php">something like this</a>. <a href="http://q.queso.com/index.php?archives/001000.php">Jason Levine has more links</a> to those involved. I spoke with one of the people who implemented it, and she claims it wasn't a protest as such, more of an inside joke. Point taken: the entire point of an aggregator (and syndication in general) is to make everyone's words look the same. Counterpoint: the default in most weblog systems is to only publish excerpts in RSS feeds; nobody's forcing you to publish full posts. This would probably be a good place to insert a Zen quote about attachment, but my mind is too fuzzy to find it.</p>
+
+<p><cite>Timothy Appnel</cite>: <a href="http://www.mplode.com/tima/archives/000107.html">More FFKAR, RDF, and FOAF</a>. FFKAR is <q>the format formerly known as RSS</q>. <a href="http://www.intertwingly.net/blog/840.html">Sam has already implemented it</a>.</p>
+
+<p><cite>Nicholas Avenell</cite>: <a href="http://www.aquarionics.com/nodes/view.php?name=esf">ESF</a>. <q>Are you also fed up with the continuing war between RSS 0.9* and 1.0 and 2.0 and whatever else they invent today? Me too. So today I invented the Epistula Syndication Format. ESF. It isn't XML. It isn't RDF. It's just data.</q> <a href="http://www.intertwingly.net/blog/">Sam</a> would love it, then. But <a href="http://www.movabletype.org/docs/mtmanual_tags.html#date tag formats">Movable Type doesn't support outputting dates in Unix timestamp format</a>, which could be an impediment to mainstream acceptance.</p>
+
+<p><cite>Shelley Powers</cite>: <a href="http://weblog.burningbird.net/archives/000544.php">Consumer Rights and RSS</a>. <q>I'm not buying into RSS 0.9x. I'm not buying into RSS 2.0. I'm not buying into RSS 1.0. I changed my RSS 0.91 and RSS 1.0 templates to read the following:</q></p>
+
+<blockquote>
+<p><strong>RSS not supported here</strong></p>
+<p>This weblog does not support RSS 0.9x, RSS 2.0, or RSS 1.0. If you wish to view entries, may I suggest that you visit the weblog, and save your fast skimming for the New York Times and Wall Street Journal.</p>
+</blockquote>
+
+<p>I'm sure this is some sort of DMCA violation or something, but here goes:</p>
+
+<blockquote>
+<p><code>import urllib, re; print "&lt;rss&gt;&lt;channel&gt;\n &lt;title&gt;Burningbird&lt;/title&gt;\n &lt;link&gt;http://weblog.burningbird.net/&lt;/link&gt;\n &lt;language&gt;en-us&lt;/language&gt;\n &lt;/channel&gt;\n" + "\n".join(["&lt;item&gt;&lt;title&gt;%s&lt;/title&gt;&lt;link&gt;%s&lt;/link&gt;&lt;/item&gt;" % t for t in re.compile(r'dc:title="(.*?)"\s*dc:identifier="(.*?)"', re.DOTALL).findall(urllib.urlopen('http://weblog.burningbird.net/').read())]) + "&lt;/rss&gt;"</code></p>
+</blockquote>
+
+<p></p>]]></content:encoded>
+ <dc:subject></dc:subject>
+ <dc:date>2002-09-25T00:38:31-05:00</dc:date>
+ </item>
+
+ <item>
+ <title>Stark raving sane</title>
+ <link>http://diveintomark.org/archives/2002/09/24.html#stark_raving_sane</link>
+ <description>Sam Ruby is stark raving mad.</description>
+ <guid isPermaLink="false">1839@http://diveintomark.org/</guid>
+ <content:encoded><![CDATA[<p><cite>Sam Ruby</cite>: <a href="http://www.intertwingly.net/blog/844.html">Stark raving mad</a>.</p>
+
+<blockquote>
+<p>This post was entered in Radio, extracted using a batch file via some UserTalk, parsed using Perl, cleaned up by tidy and a C program of my own design, transferred to intertwingly using scp, and then ssh triggers unpacking on the destination site, where a shell script takes over: invokes indexing using Jakarta's Lucene, and then a python script pings weblogs.com and blo.gs.</p>
+</blockquote>
+
+<p>Tom Stoppard (<cite>Rosencrantz and Guildenstern are Dead</cite>):</p>
+
+<blockquote>
+<p>Guildenstern: <q>A man talking sense to himself is no madder than a man talking nonsense not to himself.</q><br />
+Rosencrantz: <q>Or just as mad.</q><br />
+Guildenstern: <q>Or just as mad.</q><br />
+Rosencrantz: <q>And he does both.</q><br />
+Guildenstern: <q>So there you are.</q><br />
+Rosencrantz: <q>Stark raving sane.</q></p>
+</blockquote>
+
+<p></p>]]></content:encoded>
+ <dc:subject></dc:subject>
+ <dc:date>2002-09-24T22:05:32-05:00</dc:date>
+ </item>
+
+
+ </channel>
+</rss>
diff --git a/sample/rss/rssTwoExample.xml b/sample/rss/rssTwoExample.xml
new file mode 100644
index 000000000..0889d1680
--- /dev/null
+++ b/sample/rss/rssTwoExample.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0"?>
+<!-- RSS generated by Radio UserLand v8.0.5 on Tue, 17 Sep 2002 20:40:06 GMT -->
+<rss version="2.0" xmlns="http://backend.userland.com/rss2" xmlns:blogChannel="http://backend.userland.com/blogChannelModule">
+ <channel>
+ <title>Scripting News</title>
+ <link>http://www.scripting.com/</link>
+ <description>A weblog about scripting and stuff like that.</description>
+ <language>en-us</language>
+ <blogChannel:blogRoll>http://radio.weblogs.com/0001015/userland/scriptingNewsLeftLinks.opml</blogChannel:blogRoll>
+ <blogChannel:mySubscriptions>http://radio.weblogs.com/0001015/gems/mySubscriptions.opml</blogChannel:mySubscriptions>
+ <blogChannel:blink>http://inessential.com/</blogChannel:blink>
+ <copyright>Copyright 1997-2002 Dave Winer</copyright>
+ <lastBuildDate>Tue, 17 Sep 2002 20:40:06 GMT</lastBuildDate>
+ <docs>http://backend.userland.com/rss</docs>
+ <generator>Radio UserLand v8.0.5</generator>
+ <category domain="Syndic8">1765</category>
+ <managingEditor>dave@userland.com</managingEditor>
+ <webMaster>dave@userland.com</webMaster>
+ <ttl>60</ttl>
+ <item>
+ <description>&lt;a href=&quot;http://frontier.userland.com/stories/storyReader$10657&quot;&gt;JRobb&lt;/a&gt;: &quot;I am proud to announce the launch of Frontier 9.&quot;</description>
+ <guid>http://scriptingnews.userland.com/backissues/2002/09/17#When:11:01:55AM</guid>
+ <pubDate>Tue, 17 Sep 2002 11:01:55 GMT</pubDate>
+ </item>
+ <item>
+ <description>&lt;a href=&quot;http://jrobb.userland.com/stories/2002/09/17/rogueEmail.html&quot;&gt;How to&lt;/a&gt; ruin your life in one email.</description>
+ <pubDate>Tue, 17 Sep 2002 17:41:35 GMT</pubDate>
+ <guid>http://scriptingnews.userland.com/backissues/2002/09/17#When:10:41:35AM</guid>
+ </item>
+ <item>
+ <description>&lt;a href=&quot;http://blogs.salon.com/0001236/2002/09/17.html#a805&quot;&gt;Michel Vuijlsteke&lt;/a&gt;: &quot;And the hits started rolling in.&quot;</description>
+ <pubDate>Tue, 17 Sep 2002 17:04:52 GMT</pubDate>
+ <guid>http://scriptingnews.userland.com/backissues/2002/09/17#When:10:04:52AM</guid>
+ </item>
+ <item>
+ <description>&lt;a href=&quot;http://inessential.com/2002/09/16.php&quot;&gt;Brent Simmons&lt;/a&gt;: &quot;For RSS adoption to continue, stability is important. Developers should not spend their time scrambling to support new specs: they should spend their time building better apps.&quot; &lt;i&gt;Exactly. &lt;/i&gt;</description>
+ <pubDate>Tue, 17 Sep 2002 11:55:37 GMT</pubDate>
+ <guid>http://scriptingnews.userland.com/backissues/2002/09/17#When:4:55:37AM</guid>
+ </item>
+ <item>
+ <description>&lt;a href=&quot;http://bitworking.org/Sep2002.html#X631678518613884736&quot;&gt;Aggie&lt;/a&gt; is the first aggregator to support &lt;a href=&quot;http://backend.userland.com/rss&quot;&gt;RSS 2.0&lt;/a&gt;.</description>
+ <pubDate>Tue, 17 Sep 2002 14:01:03 GMT</pubDate>
+ <guid>http://scriptingnews.userland.com/backissues/2002/09/17#When:7:01:03AM</guid>
+ </item>
+ <item>
+ <description>&lt;a href=&quot;http://radio.weblogs.com/0100875/outlines/rcsAggregatorCache/&quot;&gt;Mikel Maron&lt;/a&gt;: &quot;With this tool, the Radio Community Server can act as a RSS Cache for Radio Userland Aggregators.&quot;</description>
+ <pubDate>Tue, 17 Sep 2002 15:12:50 GMT</pubDate>
+ <guid>http://scriptingnews.userland.com/backissues/2002/09/17#When:8:12:50AM</guid>
+ </item>
+ <item>
+ <description>With almost 2.5 million page reads in the last year, Scripting News would not qualify for the small-flow categories in the &lt;a href=&quot;http://www.onlinejournalismawards.org/pr-2002finalists3.html&quot;&gt;Online Journalism Awards&lt;/a&gt;. Their cutoff is 200,000 visits per month. We did more than that.</description>
+ <pubDate>Tue, 17 Sep 2002 16:50:19 GMT</pubDate>
+ <guid>http://scriptingnews.userland.com/backissues/2002/09/17#When:9:50:19AM</guid>
+ </item>
+ <item>
+ <description>&lt;a href=&quot;http://radio.weblogs.com/0001227/2002/09/17.html&quot;&gt;Sean Gallagher&lt;/a&gt;: &quot;Detroit is a city that looks like you might expect a city to look after a neutron bomb went off in it; most of the buildings are still standing, but the people are gone.&quot;</description>
+ <pubDate>Tue, 17 Sep 2002 14:09:14 GMT</pubDate>
+ <guid>http://scriptingnews.userland.com/backissues/2002/09/17#When:7:09:14AM</guid>
+ </item>
+ <item>
+ <description>The NY Times &lt;a href=&quot;http://www.nytimes.com/2002/09/17/technology/17AOL.html?ex=1032840000&amp;en=9bebebadbb60c3a2&amp;ei=5007&amp;partner=USERLAND&quot;&gt;reports&lt;/a&gt; that there's a move to push Steve Case out as chairman of AOL-Time-Warner; and that Charles Simonyi, an early Microsoft employee, &lt;a href=&quot;http://www.nytimes.com/2002/09/17/technology/17SOFT.html?ex=1032840000&amp;en=32d4d1af8909b6e6&amp;ei=5007&amp;partner=USERLAND&quot;&gt;has left to start&lt;/a&gt; a new software company.</description>
+ <pubDate>Tue, 17 Sep 2002 10:14:55 GMT</pubDate>
+ <guid>http://scriptingnews.userland.com/backissues/2002/09/17#When:10:14:55AM</guid>
+ </item>
+ </channel>
+ </rss>
diff --git a/sample/rss/rss_recent.rb b/sample/rss/rss_recent.rb
new file mode 100644
index 000000000..3ccb4a450
--- /dev/null
+++ b/sample/rss/rss_recent.rb
@@ -0,0 +1,84 @@
+#!/usr/bin/env ruby
+
+require "nkf"
+class String
+ # From tdiary.rb
+ def shorten( len = 120 )
+ lines = NKF::nkf( "-e -m0 -f#{len}", self.gsub( /\n/, ' ' ) ).split( /\n/ )
+ lines[0].concat( '...' ) if lines[0] and lines[1]
+ lines[0]
+ end
+end
+
+require "rss/parser"
+require "rss/1.0"
+require "rss/2.0"
+require "rss/syndication"
+require "rss/dublincore"
+
+items = []
+verbose = false
+
+def error(exception)
+ mark = "=" * 20
+ mark = "#{mark} error #{mark}"
+ puts mark
+ puts exception.class
+ puts exception.message
+ puts exception.backtrace
+ puts mark
+end
+before_time = Time.now
+ARGV.each do |fname|
+ if fname == '-v'
+ verbose = true
+ next
+ end
+ rss = nil
+ f = File.new(fname).read
+ begin
+ ## do validate parse
+ rss = RSS::Parser.parse(f)
+ rescue RSS::InvalidRSSError
+ error($!) if verbose
+ ## do non validate parse for invalid RSS 1.0
+ begin
+ rss = RSS::Parser.parse(f, false)
+ rescue RSS::Error
+ ## invalid RSS.
+ error($!) if verbose
+ end
+ rescue RSS::Error
+ error($!) if verbose
+ end
+ if rss.nil?
+ puts "#{fname} does not include RSS 1.0 or 0.9x/2.0"
+ else
+ begin
+ rss.output_encoding = "euc-jp"
+ rescue RSS::UnknownConversionMethodError
+ error($!) if verbose
+ end
+ rss.items.each do |item|
+ if item.respond_to?(:pubDate) and item.pubDate
+ class << item
+ alias_method(:dc_date, :pubDate)
+ end
+ end
+ if item.respond_to?(:dc_date) and item.dc_date
+ items << [rss.channel, item]
+ end
+ end
+ end
+end
+processing_time = Time.now - before_time
+
+items.sort do |x, y|
+ y[1].dc_date <=> x[1].dc_date
+end[0..20].each do |channel, item|
+ puts "#{item.dc_date.localtime.iso8601} : " <<
+ "#{channel.title} : #{item.title}"
+ puts " description : #{item.description.shorten(50)}" if item.description
+end
+
+puts "Processing Time : #{processing_time}s"
diff --git a/sample/rss/sampleRss.xml b/sample/rss/sampleRss.xml
new file mode 100644
index 000000000..65788c3d0
--- /dev/null
+++ b/sample/rss/sampleRss.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<rss version="0.91">
+ <channel>
+ <title>WriteTheWeb</title>
+ <link>http://writetheweb.com</link>
+ <description>News for web users that write back</description>
+ <language>en-us</language>
+ <copyright>Copyright 2000, WriteTheWeb team.</copyright>
+ <managingEditor>editor@writetheweb.com</managingEditor>
+ <webMaster>webmaster@writetheweb.com</webMaster>
+ <image>
+ <title>WriteTheWeb</title>
+ <url>http://writetheweb.com/images/mynetscape88.gif</url>
+ <link>http://writetheweb.com</link>
+ <width>88</width>
+ <height>31</height>
+ <description>News for web users that write back</description>
+ </image>
+ <item>
+ <title>Giving the world a pluggable Gnutella</title>
+ <link>http://writetheweb.com/read.php?item=24</link>
+ <description>WorldOS is a framework on which to build programs that work like Freenet or Gnutella -allowing distributed applications using peer-to-peer routing.</description>
+ </item>
+ <item>
+ <title>Syndication discussions hot up</title>
+ <link>http://writetheweb.com/read.php?item=23</link>
+ <description>After a period of dormancy, the Syndication mailing list has become active again, with contributions from leaders in traditional media and Web syndication.</description>
+ </item>
+ <item>
+ <title>Personal web server integrates file sharing and messaging</title>
+ <link>http://writetheweb.com/read.php?item=22</link>
+ <description>The Magi Project is an innovative project to create a combined personal web server and messaging system that enables the sharing and synchronization of information across desktop, laptop and palmtop devices.</description>
+ </item>
+ <item>
+ <title>Syndication and Metadata</title>
+ <link>http://writetheweb.com/read.php?item=21</link>
+ <description>RSS is probably the best known metadata format around. RDF is probably one of the least understood. In this essay, published on my O'Reilly Network weblog, I argue that the next generation of RSS should be based on RDF.</description>
+ </item>
+ <item>
+ <title>UK bloggers get organised</title>
+ <link>http://writetheweb.com/read.php?item=20</link>
+ <description>Looks like the weblogs scene is gathering pace beyond the shores of the US. There's now a UK-specific page on weblogs.com, and a mailing list at egroups.</description>
+ </item>
+ <item>
+ <title>Yournamehere.com more important than anything</title>
+ <link>http://writetheweb.com/read.php?item=19</link>
+ <description>Whatever you're publishing on the web, your site name is the most valuable asset you have, according to Carl Steadman.</description>
+ </item>
+ </channel>
+ </rss>
diff --git a/sample/rss/slashdot.rdf b/sample/rss/slashdot.rdf
new file mode 100644
index 000000000..feb992f9c
--- /dev/null
+++ b/sample/rss/slashdot.rdf
@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<rdf:RDF
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns="http://purl.org/rss/1.0/"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:slash="http://slashcode.com/rss/1.0/modules/Slash/"
+ xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/"
+ xmlns:syn="http://purl.org/rss/1.0/modules/syndication/"
+>
+
+<channel rdf:about="http://slashdot.jp/">
+<title>スラッシュドット ジャパン</title>
+<link>http://slashdot.jp/</link>
+<description>アレゲãªãƒ‹ãƒ¥ãƒ¼ã‚¹ã¨é›‘談サイト</description>
+<dc:language>ja-jp</dc:language>
+<dc:rights>Copyright(c) 2001, Slashdot Japan</dc:rights>
+<dc:date>2003-03-02T10:13:10+00:00</dc:date>
+<dc:publisher>Slashdot Japan</dc:publisher>
+<dc:creator>slashmaster@slashdot.jp</dc:creator>
+<dc:subject>Technology</dc:subject>
+<syn:updatePeriod>hourly</syn:updatePeriod>
+<syn:updateFrequency>1</syn:updateFrequency>
+<syn:updateBase>1970-01-01T00:00+00:00</syn:updateBase>
+<items>
+ <rdf:Seq>
+ <rdf:li resource="http://slashdot.jp/article.pl?sid=03/03/02/0924255&amp;topic=1" />
+ <rdf:li resource="http://slashdot.jp/article.pl?sid=03/03/02/0845229&amp;topic=62" />
+ <rdf:li resource="http://slashdot.jp/article.pl?sid=03/03/02/0428233&amp;topic=89" />
+ <rdf:li resource="http://slashdot.jp/article.pl?sid=03/03/01/1345238&amp;topic=1" />
+ <rdf:li resource="http://slashdot.jp/article.pl?sid=03/03/01/1141203&amp;topic=42" />
+ <rdf:li resource="http://slashdot.jp/article.pl?sid=03/03/01/1132259&amp;topic=31" />
+ <rdf:li resource="http://slashdot.jp/article.pl?sid=03/03/01/1045237&amp;topic=31" />
+ <rdf:li resource="http://slashdot.jp/article.pl?sid=03/03/01/1045214&amp;topic=68" />
+ <rdf:li resource="http://slashdot.jp/article.pl?sid=03/03/01/097247&amp;topic=72" />
+ <rdf:li resource="http://slashdot.jp/article.pl?sid=03/03/01/0752218&amp;topic=16" />
+ </rdf:Seq>
+</items>
+<image rdf:resource="http://slashdot.jp/images/topics/topicslashdot.gif" />
+<textinput rdf:resource="http://slashdot.jp/search.pl" />
+</channel>
+
+<image rdf:about="http://slashdot.jp/images/topics/topicslashdot.gif">
+<title>スラッシュドット ジャパン</title>
+<url>http://slashdot.jp/images/topics/topicslashdot.gif</url>
+<link>http://slashdot.jp/</link>
+</image>
+
+<item rdf:about="http://slashdot.jp/article.pl?sid=03/03/02/0924255&amp;topic=1">
+<title>PS2制御ã®ãƒ‰ãƒ©ã‚¤ãƒ“ング・シミュレータ</title>
+<link>http://slashdot.jp/article.pl?sid=03/03/02/0924255&amp;topic=1</link>
+<dc:creator>yourCat</dc:creator>
+<dc:subject>news</dc:subject>
+<dc:date>2003-03-02T09:18:36+00:00</dc:date>
+<slash:department>安全é‹è»¢ã®ãŸã‚ãªã®ã‚’忘れãã†</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>5</slash:comments>
+<slash:hitparade></slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.jp/article.pl?sid=03/03/02/0845229&amp;topic=62">
+<title>脳ã¯éŸ³ã®é€Ÿã•ã‚’知ã£ã¦ã„ã‚‹</title>
+<link>http://slashdot.jp/article.pl?sid=03/03/02/0845229&amp;topic=62</link>
+<dc:creator>yourCat</dc:creator>
+<dc:subject>science</dc:subject>
+<dc:date>2003-03-02T08:40:53+00:00</dc:date>
+<slash:department>40mã¨ã„ã†ã®ãŒé¢ç™½ã„</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>17</slash:comments>
+<slash:hitparade></slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.jp/article.pl?sid=03/03/02/0428233&amp;topic=89">
+<title>外æ¥èªžè¨€ã„æ›ãˆã€ç¬¬2回語案ã®æ案を募集中</title>
+<link>http://slashdot.jp/article.pl?sid=03/03/02/0428233&amp;topic=89</link>
+<dc:creator>GetSet</dc:creator>
+<dc:subject>japan</dc:subject>
+<dc:date>2003-03-02T04:26:27+00:00</dc:date>
+<slash:department>言ã„æ›ãˆãªã„æ–¹ãŒåˆ¤ã‚Šæ˜“ã„ã“ã¨ã‚‚</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>85</slash:comments>
+<slash:hitparade></slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.jp/article.pl?sid=03/03/01/1345238&amp;topic=1">
+<title>ãƒã‚¤ã‚¯ç”¨ETCãŒå®Ÿç”¨åŒ–ã¸</title>
+<link>http://slashdot.jp/article.pl?sid=03/03/01/1345238&amp;topic=1</link>
+<dc:creator>GetSet</dc:creator>
+<dc:subject>news</dc:subject>
+<dc:date>2003-03-01T13:41:52+00:00</dc:date>
+<slash:department>グローブ外ã™ã®ã«æ…Œã¦ãªãã¦ã„ã„ã®ã­</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>122</slash:comments>
+<slash:hitparade></slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.jp/article.pl?sid=03/03/01/1141203&amp;topic=42">
+<title>「ジョーãƒã€ã§Goï¼</title>
+<link>http://slashdot.jp/article.pl?sid=03/03/01/1141203&amp;topic=42</link>
+<dc:creator>GetSet</dc:creator>
+<dc:subject>humor</dc:subject>
+<dc:date>2003-03-01T11:39:37+00:00</dc:date>
+<slash:department>ç§ã®æ„›é¦¬ã¯å‡¶æš´ã§ã™</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>28</slash:comments>
+<slash:hitparade></slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.jp/article.pl?sid=03/03/01/1132259&amp;topic=31">
+<title>ラグナロクオンラインã§å¤§è¦æ¨¡ãªå†¤ç½ªãƒ»è¿½æ”¾é¨’å‹•</title>
+<link>http://slashdot.jp/article.pl?sid=03/03/01/1132259&amp;topic=31</link>
+<dc:creator>GetSet</dc:creator>
+<dc:subject>games</dc:subject>
+<dc:date>2003-03-01T11:23:59+00:00</dc:date>
+<slash:department>正直ãªãƒ¦ãƒ¼ã‚¶ãŒä¸€ç•ªã®è¢«å®³è€…ã‹ã‚‚</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>70</slash:comments>
+<slash:hitparade></slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.jp/article.pl?sid=03/03/01/1045237&amp;topic=31">
+<title>グリッドを使ã£ãŸ100万人用ã®ã‚²ãƒ¼ãƒ ã‚µãƒ¼ãƒ</title>
+<link>http://slashdot.jp/article.pl?sid=03/03/01/1045237&amp;topic=31</link>
+<dc:creator>Oliver</dc:creator>
+<dc:subject>games</dc:subject>
+<dc:date>2003-03-01T10:45:03+00:00</dc:date>
+<slash:department>PS3å…ˆå–ã‚Š</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>24</slash:comments>
+<slash:hitparade></slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.jp/article.pl?sid=03/03/01/1045214&amp;topic=68">
+<title>Sunã€UltraSPARCã®ã‚¹ãƒ«ãƒ¼ãƒ—ットを3年後ã«ã¯30å€ã«</title>
+<link>http://slashdot.jp/article.pl?sid=03/03/01/1045214&amp;topic=68</link>
+<dc:creator>Oliver</dc:creator>
+<dc:subject>sun</dc:subject>
+<dc:date>2003-03-01T10:44:31+00:00</dc:date>
+<slash:department>ãƒã‚¹ã¨ã„ã†ãƒœãƒˆãƒ«ãƒãƒƒã‚¯</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>21</slash:comments>
+<slash:hitparade></slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.jp/article.pl?sid=03/03/01/097247&amp;topic=72">
+<title>ãƒã‚¤ãƒ†ã‚¯ç›£è¦–システムやã¶ã‚‰ã‚Œã€127億円ã®å®çŸ³ãŒç›—難</title>
+<link>http://slashdot.jp/article.pl?sid=03/03/01/097247&amp;topic=72</link>
+<dc:creator>Oliver</dc:creator>
+<dc:subject>money</dc:subject>
+<dc:date>2003-03-01T09:05:46+00:00</dc:date>
+<slash:department>å²ä¸Šæœ€å¼·ã®ã‚¯ãƒ©ãƒƒã‚­ãƒ³ã‚°ï¼Ÿ</slash:department>
+<slash:section>security</slash:section>
+<slash:comments>29</slash:comments>
+<slash:hitparade></slash:hitparade>
+</item>
+
+<item rdf:about="http://slashdot.jp/article.pl?sid=03/03/01/0752218&amp;topic=16">
+<title>国内ã®èˆªç©ºç®¡åˆ¶ãŒä¸€æ™‚å…¨åœæ­¢</title>
+<link>http://slashdot.jp/article.pl?sid=03/03/01/0752218&amp;topic=16</link>
+<dc:creator>Oliver</dc:creator>
+<dc:subject>bug</dc:subject>
+<dc:date>2003-03-01T07:51:30+00:00</dc:date>
+<slash:department>3å°ã§å¤šæ•°æ±ºã‚’</slash:department>
+<slash:section>articles</slash:section>
+<slash:comments>126</slash:comments>
+<slash:hitparade></slash:hitparade>
+</item>
+
+<textinput rdf:about="http://slashdot.jp/search.pl">
+<title>Search スラッシュドット ジャパン</title>
+<description>Search スラッシュドット ジャパン stories</description>
+<name>query</name>
+<link>http://slashdot.jp/search.pl</link>
+</textinput>
+
+</rdf:RDF>
diff --git a/sample/rss/slashdotorg.rdf b/sample/rss/slashdotorg.rdf
new file mode 100644
index 000000000..543270613
--- /dev/null
+++ b/sample/rss/slashdotorg.rdf
@@ -0,0 +1,76 @@
+<?xml version="1.0"?>
+
+<rdf:RDF
+xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+xmlns="http://my.netscape.com/rdf/simple/0.9/">
+
+<channel>
+<title>Slashdot</title>
+<link>http://slashdot.org/</link>
+<description>News for nerds, stuff that matters</description>
+</channel>
+
+<image>
+<title>Slashdot</title>
+<url>http://images.slashdot.org/topics/topicslashdot.gif</url>
+<link>http://slashdot.org/</link>
+</image>
+
+<item>
+<title>McDonalds to go Wireless?</title>
+<link>http://slashdot.org/article.pl?sid=03/03/11/135255</link>
+</item>
+
+<item>
+<title>Feds Move to Secure Net</title>
+<link>http://slashdot.org/article.pl?sid=03/03/11/0246210</link>
+</item>
+
+<item>
+<title>Linus Comments on SCO v IBM</title>
+<link>http://slashdot.org/article.pl?sid=03/03/11/0137251</link>
+</item>
+
+<item>
+<title>New Windows Worm Inching Around Internet</title>
+<link>http://slashdot.org/article.pl?sid=03/03/11/0058219</link>
+</item>
+
+<item>
+<title>Tcl Core Team Interview</title>
+<link>http://slashdot.org/article.pl?sid=03/03/10/229219</link>
+</item>
+
+<item>
+<title>MA Dept. of Revenue consider Linux</title>
+<link>http://slashdot.org/article.pl?sid=03/03/10/2156202</link>
+</item>
+
+<item>
+<title>Perl 6: Apocalypse 6 Released</title>
+<link>http://slashdot.org/article.pl?sid=03/03/10/2134229</link>
+</item>
+
+<item>
+<title>SuSE may drop out of UnitedLinux</title>
+<link>http://slashdot.org/article.pl?sid=03/03/10/212241</link>
+</item>
+
+<item>
+<title>New Legit Napster Service Coming</title>
+<link>http://slashdot.org/article.pl?sid=03/03/10/1931252</link>
+</item>
+
+<item>
+<title>Swapping Clock Cycles for Free Music?</title>
+<link>http://slashdot.org/article.pl?sid=03/03/10/1845230</link>
+</item>
+
+<textinput>
+<title>Search Slashdot</title>
+<description>Search Slashdot stories</description>
+<name>query</name>
+<link>http://slashdot.org/search.pl</link>
+</textinput>
+
+</rdf:RDF> \ No newline at end of file
diff --git a/sample/rss/tdiary_plugin/rss-recent.rb b/sample/rss/tdiary_plugin/rss-recent.rb
new file mode 100644
index 000000000..103d3358b
--- /dev/null
+++ b/sample/rss/tdiary_plugin/rss-recent.rb
@@ -0,0 +1,118 @@
+# rss-recent.rb: RSS recent plugin
+#
+# rss_recnet: show recnet list from RSS
+# parameters (default):
+# url: URL of RSS
+# max: max of list itmes(5)
+# cache_time: cache time(second) of RSS(60*60)
+#
+#
+# Copyright (c) 2003 Kouhei Sutou <kou@cozmixng.org>
+# Distributed under the GPL
+#
+
+require "rss/rss"
+
+RSS_RECENT_FIELD_SEPARATOR = "\0"
+RSS_RECENT_VERSION = "0.0.2"
+RSS_RECENT_CONTENT_TYPE = {
+ "User-Agent" => "tDiary RSS recent plugin version #{RSS_RECENT_VERSION}. " <<
+ "Using RSS parser version is #{::RSS::VERSION}."
+}
+
+
+def rss_recent(url, max=5, cache_time=3600)
+ cache_file = "#{@cache_path}/rss-recent.#{CGI.escape(url)}"
+
+ rss_recent_cache_rss(url, cache_file, cache_time.to_i)
+
+ return '' unless test(?r, cache_file)
+
+ rv = "<ul>\n"
+ File.open(cache_file) do |f|
+ max.to_i.times do
+ title = f.gets(RSS_RECENT_FIELD_SEPARATOR)
+ break if title.nil?
+ rv << '<li>'
+ link = f.gets(RSS_RECENT_FIELD_SEPARATOR)
+ unless link.nil?
+ rv << %Q!<a href="#{CGI.escapeHTML(link.chomp(RSS_RECENT_FIELD_SEPARATOR))}">!
+ end
+ rv << CGI::escapeHTML(title.chomp(RSS_RECENT_FIELD_SEPARATOR))
+ rv << '</a>' unless link.nil?
+ rv << "</li>\n"
+ end
+ end
+ rv << "</ul>\n"
+
+ rv
+end
+
+class InvalidResourceError < StandardError; end
+
+def rss_recent_cache_rss(url, cache_file, cache_time)
+
+ begin
+ raise if Time.now > File.mtime(cache_file) + cache_time
+ rescue
+ require 'net/http'
+ require 'uri/generic'
+ require 'rss/parser'
+ require 'rss/1.0'
+ require 'rss/2.0'
+
+ begin
+ ur = URI.parse(url)
+
+ raise URI::InvalidURIError if ur.scheme != "http"
+
+ rss_source = rss_recent_fetch_rss(ur)
+
+ # parse RSS
+ rss = ::RSS::Parser.parse(rss_source, false)
+ raise ::RSS::Error if rss.nil?
+
+ # pre processing
+ begin
+ rss.output_encoding = charset
+ rescue ::RSS::UnknownConversionMethodError
+ end
+
+ tlary = rss.items.collect{|item| [item.title, item.link]}
+ rss_recent_write_to_cache(cache_file, tlary)
+
+ rescue URI::InvalidURIError
+ rss_recent_write_to_cache(cache_file, [['Invalid URI', url]])
+ rescue InvalidResourceError, ::RSS::Error
+ rss_recent_write_to_cache(cache_file, [['Invalid Resource', url]])
+ end
+ end
+
+end
+
+def rss_recent_fetch_rss(uri)
+ rss = ''
+ begin
+ Net::HTTP.start(uri.host, uri.port || 80) do |http|
+ path = uri.path
+ path << "?#{uri.query}" if uri.query
+ req = http.request_get(path)
+ raise InvalidResourceError unless req.code == "200"
+ rss << req.body
+ end
+ rescue TimeoutError, SocketError
+ raise InvalidResourceError
+ end
+ rss
+end
+
+def rss_recent_write_to_cache(cache_file, array_of_titles_and_links)
+ File.open(cache_file, 'w') do |f|
+ f.flock(File::LOCK_EX)
+ array_of_titles_and_links.each do |title, link|
+ f << "#{title}#{RSS_RECENT_FIELD_SEPARATOR}"
+ f << "#{link}#{RSS_RECENT_FIELD_SEPARATOR}"
+ end
+ f.flock(File::LOCK_UN)
+ end
+end
diff --git a/sample/rss/w3c.rdf b/sample/rss/w3c.rdf
new file mode 100644
index 000000000..d62d8364e
--- /dev/null
+++ b/sample/rss/w3c.rdf
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<?xml-stylesheet href="http://www.w3.org/2000/08/w3c-synd/style.css" type="text/css"?>
+<rdf:RDF xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:hr="http://www.w3.org/2000/08/w3c-synd/#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/">
+<channel rdf:about="http://www.w3.org/2000/08/w3c-synd/home.rss">
+<title>World Wide Web Consortium</title>
+<description>Leading the Web to its Full Potential...</description>
+<link>http://www.w3.org/</link>
+<dc:date>2003-03-11T00:11:20Z</dc:date>
+<items>
+<rdf:Seq>
+<rdf:li rdf:resource="http://www.w3.org/News/2003#item50"/>
+<rdf:li rdf:resource="http://www.w3.org/News/2003#item53"/>
+<rdf:li rdf:resource="http://www.w3.org/News/2003#item52"/>
+<rdf:li rdf:resource="http://www.w3.org/News/2003#item51"/>
+<rdf:li rdf:resource="http://www.w3.org/News/2003#item49"/>
+<rdf:li rdf:resource="http://www.w3.org/News/2003#item45"/>
+<rdf:li rdf:resource="http://www.w3.org/News/2003#item46"/>
+</rdf:Seq>
+</items>
+</channel>
+<item rdf:about="http://www.w3.org/News/2003#item50">
+<title>W3C Hosts Technical Plenary and All-Group Meeting</title>
+<description>3 March 2003: W3C holds its third annual Technical Plenary and All Working Group Meeting from 3-7 March in Cambridge, MA, USA. 30 W3C Working Groups and Interest Groups hold face-to-face meetings. Mid-week, many of the more than 400 participants attend the all day public plenary, by far the largest group in the event's history. If your organization would like to join W3C, please refer to the Membership page. (News archive)</description>
+<link>http://www.w3.org/News/2003#item50</link>
+<dc:date>2003-03-03</dc:date>
+</item>
+<item rdf:about="http://www.w3.org/News/2003#item53">
+<title>China International Forum on WWW's Development Announced</title>
+<description>10 March 2003: The China International Forum on WWW's Development 2003 will be held in Beijing, China on 16-17 April. W3C Team members Judy Brewer, Martin Dürst, Ivan Herman, Philipp Hoschka and Matt May present keynotes and tutorials. Attendees will participate in panels on accessibility, SVG, mobile Web, the Semantic Web, VoiceXML and internationalization. Registration is open. The event is co-organized by the China Computer Federation and the W3C Office in Hong Kong. (News archive)</description>
+<link>http://www.w3.org/News/2003#item53</link>
+<dc:date>2003-03-10</dc:date>
+</item>
+<item rdf:about="http://www.w3.org/News/2003#item52">
+<title>Call for Participation: W3C Teleconference on Collaboration</title>
+<description>4 March 2003: W3C is pleased to announce the first in a series of teleconferences on Web accessibility research. Researchers and practitioners in document collaboration, human-computer interaction, assistive technologies, disability studies, Web accessibility, and related fields are invited. The event is sponsored by the Web Accessibility Initiative's Research and Development Interest Group. The first telecon is tentatively 14 April. Position papers are due 21 March. Please refer to the call for papers. (News archive)</description>
+<link>http://www.w3.org/News/2003#item52</link>
+<dc:date>2003-03-04</dc:date>
+</item>
+<item rdf:about="http://www.w3.org/News/2003#item51">
+<title>Web Services Description Language (WSDL) 1.2 Working Draft Published</title>
+<description>3 March 2003: The Web Services Description Working Group has released an updated Working Draft of the Web Services Description Language (WSDL) Version 1.2. WSDL is a model and an XML format for describing Web services that allows separation of abstract functionality from concrete details. Read about Web Services. (News archive)</description>
+<link>http://www.w3.org/News/2003#item51</link>
+<dc:date>2003-03-03</dc:date>
+</item>
+<item rdf:about="http://www.w3.org/News/2003#item49">
+<title>W3C Team Talks in March</title>
+<description>1 March 2003: Browse upcoming W3C appearances and events. (News archive)</description>
+<link>http://www.w3.org/News/2003#item49</link>
+<dc:date>2003-03-01</dc:date>
+</item>
+<item rdf:about="http://www.w3.org/News/2003#item45">
+<title>W3C Co-Sponsors 23rd Internationalization &amp; Unicode Conference</title>
+<description>26 February 2003: Registration is open for the 23rd Internationalization &amp; Unicode Conference to be held 24-26 March in Prague, Czech Republic, near most major cities in Europe. Come and meet W3C Team members Martin Dürst, Richard Ishida, and Chris Lilley who are presenting. The event is the premier technical conference worldwide for software and Web internationalization. Read about Unicode and the W3C Internationalization Activity. (News archive)</description>
+<link>http://www.w3.org/News/2003#item45</link>
+<dc:date>2003-02-26</dc:date>
+</item>
+<item rdf:about="http://www.w3.org/News/2003#item46">
+<title>CSS3 Text Last Call Working Draft Published</title>
+<description>26 February 2003: The CSS Working Group has released a second Last Call Working Draft of the CSS3 module: Text incorporating all comments from the first Last Call. The group welcomes feedback through 5 March. The document is a set of text formatting properties. Many address international contexts, particularly East Asian and bidirectional text. Visit the CSS home page. (News archive)</description>
+<link>http://www.w3.org/News/2003#item46</link>
+<dc:date>2003-02-26</dc:date>
+</item>
+</rdf:RDF>
diff --git a/sample/rss/wiliki.rss b/sample/rss/wiliki.rss
new file mode 100644
index 000000000..8f1c45757
--- /dev/null
+++ b/sample/rss/wiliki.rss
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="euc-jp" ?>
+<rdf:RDF
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns="http://purl.org/rss/1.0/"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ >
+<channel rdf:about="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi"><title>WiLiKi</title>
+<link>http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi</link>
+<description>WiLiKi, a Wiki engine written in Scheme</description>
+<items><rdf:Seq><rdf:li rdf:resource="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?todo&amp;l=jp" />
+<rdf:li rdf:resource="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aWindows%2fVC%2b%2b&amp;l=jp" />
+<rdf:li rdf:resource="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aBugs&amp;l=jp" />
+<rdf:li rdf:resource="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?%b5%ba&amp;l=jp" />
+<rdf:li rdf:resource="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aCygwin&amp;l=jp" />
+<rdf:li rdf:resource="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aSpamFilter&amp;l=jp" />
+<rdf:li rdf:resource="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?skimu&amp;l=jp" />
+<rdf:li rdf:resource="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?WiLiKi%3aRSSMix&amp;l=jp" />
+<rdf:li rdf:resource="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?WiLiKi&amp;l=jp" />
+<rdf:li rdf:resource="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?SHIMADA&amp;l=jp" />
+<rdf:li rdf:resource="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?WiLiKi%a5%bd%a1%bc%a5%b9%b2%f2%c6%c9&amp;l=jp" />
+<rdf:li rdf:resource="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?MakotoS&amp;l=jp" />
+<rdf:li rdf:resource="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?WiLiKi%3aWishList&amp;l=jp" />
+<rdf:li rdf:resource="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aPackages&amp;l=jp" />
+<rdf:li rdf:resource="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aMacOSX&amp;l=jp" />
+</rdf:Seq></items>
+
+</channel>
+<item rdf:about="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?todo&amp;l=jp"><title>todo</title>
+<link>http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?todo&amp;l=jp</link>
+<dc:date>2003-03-15T11:47:00+00:00</dc:date>
+</item>
+<item rdf:about="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aWindows%2fVC%2b%2b&amp;l=jp"><title>Gauche:Windows/VC++</title>
+<link>http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aWindows%2fVC%2b%2b&amp;l=jp</link>
+<dc:date>2003-03-15T04:41:42+00:00</dc:date>
+</item>
+<item rdf:about="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aBugs&amp;l=jp"><title>Gauche:Bugs</title>
+<link>http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aBugs&amp;l=jp</link>
+<dc:date>2003-03-15T01:59:57+00:00</dc:date>
+</item>
+<item rdf:about="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?%b5%ba&amp;l=jp"><title>µº</title>
+<link>http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?%b5%ba&amp;l=jp</link>
+<dc:date>2003-03-14T17:47:24+00:00</dc:date>
+</item>
+<item rdf:about="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aCygwin&amp;l=jp"><title>Gauche:Cygwin</title>
+<link>http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aCygwin&amp;l=jp</link>
+<dc:date>2003-03-13T15:34:27+00:00</dc:date>
+</item>
+<item rdf:about="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aSpamFilter&amp;l=jp"><title>Gauche:SpamFilter</title>
+<link>http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aSpamFilter&amp;l=jp</link>
+<dc:date>2003-03-13T11:46:12+00:00</dc:date>
+</item>
+<item rdf:about="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?skimu&amp;l=jp"><title>skimu</title>
+<link>http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?skimu&amp;l=jp</link>
+<dc:date>2003-03-13T04:46:56+00:00</dc:date>
+</item>
+<item rdf:about="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?WiLiKi%3aRSSMix&amp;l=jp"><title>WiLiKi:RSSMix</title>
+<link>http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?WiLiKi%3aRSSMix&amp;l=jp</link>
+<dc:date>2003-03-13T04:27:01+00:00</dc:date>
+</item>
+<item rdf:about="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?WiLiKi&amp;l=jp"><title>WiLiKi</title>
+<link>http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?WiLiKi&amp;l=jp</link>
+<dc:date>2003-03-13T01:01:11+00:00</dc:date>
+</item>
+<item rdf:about="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?SHIMADA&amp;l=jp"><title>SHIMADA</title>
+<link>http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?SHIMADA&amp;l=jp</link>
+<dc:date>2003-03-11T05:19:03+00:00</dc:date>
+</item>
+<item rdf:about="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?WiLiKi%a5%bd%a1%bc%a5%b9%b2%f2%c6%c9&amp;l=jp"><title>WiLiKi¥½¡¼¥¹²òÆÉ</title>
+<link>http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?WiLiKi%a5%bd%a1%bc%a5%b9%b2%f2%c6%c9&amp;l=jp</link>
+<dc:date>2003-03-10T08:46:29+00:00</dc:date>
+</item>
+<item rdf:about="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?MakotoS&amp;l=jp"><title>MakotoS</title>
+<link>http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?MakotoS&amp;l=jp</link>
+<dc:date>2003-03-10T08:00:47+00:00</dc:date>
+</item>
+<item rdf:about="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?WiLiKi%3aWishList&amp;l=jp"><title>WiLiKi:WishList</title>
+<link>http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?WiLiKi%3aWishList&amp;l=jp</link>
+<dc:date>2003-03-10T07:56:40+00:00</dc:date>
+</item>
+<item rdf:about="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aPackages&amp;l=jp"><title>Gauche:Packages</title>
+<link>http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aPackages&amp;l=jp</link>
+<dc:date>2003-03-09T10:40:43+00:00</dc:date>
+</item>
+<item rdf:about="http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aMacOSX&amp;l=jp"><title>Gauche:MacOSX</title>
+<link>http://www.shiro.dreamhost.com/scheme/wiliki/wiliki.cgi?Gauche%3aMacOSX&amp;l=jp</link>
+<dc:date>2003-03-09T08:05:22+00:00</dc:date>
+</item>
+</rdf:RDF>
diff --git a/test/rss/common.rb b/test/rss/common.rb
new file mode 100644
index 000000000..d92057f62
--- /dev/null
+++ b/test/rss/common.rb
@@ -0,0 +1,100 @@
+require 'test/my-assertions'
+
+module TestRSSMixin
+
+ include RSS
+
+ XMLDECL_VERSION = "1.0"
+ XMLDECL_ENCODING = "UTF-8"
+ XMLDECL_STANDALONE = "no"
+
+ RDF_ABOUT = "http://www.xml.com/xml/news.rss"
+ RDF_RESOURCE = "http://xml.com/universal/images/xml_tiny.gif"
+ TITLE_VALUE = "XML.com"
+ LINK_VALUE = "http://xml.com/pub"
+ URL_VALUE = "http://xml.com/universal/images/xml_tiny.gif"
+ NAME_VALUE = "hogehoge"
+ DESCRIPTION_VALUE = "
+ XML.com features a rich mix of information and services
+ for the XML community.
+ "
+ RESOURCES = [
+ "http://xml.com/pub/2000/08/09/xslt/xslt.html",
+ "http://xml.com/pub/2000/08/09/rdfdb/index.html",
+ ]
+
+ private
+ def make_xmldecl(v=XMLDECL_VERSION, e=XMLDECL_ENCODING, s=XMLDECL_STANDALONE)
+ rv = "<?xml version='#{v}'"
+ rv << " encoding='#{e}'" if e
+ rv << " standalone='#{s}'" if s
+ rv << "?>"
+ rv
+ end
+
+ def make_RDF(content=nil, xmlns=[])
+ <<-EORSS
+#{make_xmldecl}
+<rdf:RDF xmlns="#{URI}" xmlns:rdf="#{RDF::URI}"
+#{xmlns.collect {|pre, uri| "xmlns:#{pre}='#{uri}'"}.join(' ')}>
+#{block_given? ? yield : content}
+</rdf:RDF>
+EORSS
+ end
+
+ def make_channel(content=nil)
+ <<-EOC
+<channel rdf:about="#{RDF_ABOUT}">
+ <title>#{TITLE_VALUE}</title>
+ <link>#{LINK_VALUE}</link>
+ <description>#{DESCRIPTION_VALUE}</description>
+
+ <image rdf:resource="#{RDF_RESOURCE}" />
+
+ <items>
+ <rdf:Seq>
+#{RESOURCES.collect do |res| '<rdf:li resource="' + res + '" />' end.join("\n")}
+ </rdf:Seq>
+ </items>
+
+ <textinput rdf:resource="#{RDF_RESOURCE}" />
+
+#{block_given? ? yield : content}
+</channel>
+EOC
+ end
+
+ def make_image(content=nil)
+ <<-EOI
+<image rdf:about="#{RDF_ABOUT}">
+ <title>#{TITLE_VALUE}</title>
+ <url>#{URL_VALUE}</url>
+ <link>#{LINK_VALUE}</link>
+#{block_given? ? yield : content}
+</image>
+EOI
+ end
+
+ def make_item(content=nil)
+ <<-EOI
+<item rdf:about="#{RDF_ABOUT}">
+ <title>#{TITLE_VALUE}</title>
+ <link>#{LINK_VALUE}</link>
+ <description>#{DESCRIPTION_VALUE}</description>
+#{block_given? ? yield : content}
+</item>
+EOI
+ end
+
+ def make_textinput(content=nil)
+ <<-EOT
+<textinput rdf:about="#{RDF_ABOUT}">
+ <title>#{TITLE_VALUE}</title>
+ <description>#{DESCRIPTION_VALUE}</description>
+ <name>#{NAME_VALUE}</name>
+ <link>#{LINK_VALUE}</link>
+#{block_given? ? yield : content}
+</textinput>
+EOT
+ end
+end
diff --git a/test/rss/each_parser.rb b/test/rss/each_parser.rb
new file mode 100644
index 000000000..b1ea9c5e1
--- /dev/null
+++ b/test/rss/each_parser.rb
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+
+require "rbconfig"
+
+c = Config::CONFIG
+ruby = File.join(c['bindir'], c['ruby_install_name'])
+
+module RSS
+ AVAILABLE_PARSERS = [ARGV.shift]
+end
+
+def load_test_file(name)
+ puts "Loading #{name} ..."
+ require name
+end
+
+load_test_file(ARGV.shift)
diff --git a/test/rss/my-assertions.rb b/test/rss/my-assertions.rb
new file mode 100644
index 000000000..6e8883998
--- /dev/null
+++ b/test/rss/my-assertions.rb
@@ -0,0 +1,89 @@
+module Test
+ module Unit
+ module Assertions
+
+ def assert_parse(rss, assert_method, *args)
+ send("assert_#{assert_method}", *args) do
+ ::RSS::Parser.parse(rss)
+ end
+ send("assert_#{assert_method}", *args) do
+ ::RSS::Parser.parse(rss, false).validate
+ end
+ end
+
+ def assert_ns(prefix, uri)
+ _wrap_assertion do
+ begin
+ yield
+ flunk("Not raise NSError")
+ rescue ::RSS::NSError => e
+ assert_equal(prefix, e.prefix)
+ assert_equal(uri, e.uri)
+ end
+ end
+ end
+
+ def assert_missing_tag(tag, parent)
+ _wrap_assertion do
+ begin
+ yield
+ flunk("Not raise MissingTagError")
+ rescue ::RSS::MissingTagError => e
+ assert_equal(tag, e.tag)
+ assert_equal(parent, e.parent)
+ end
+ end
+ end
+
+ def assert_too_much_tag(tag, parent)
+ _wrap_assertion do
+ begin
+ yield
+ flunk("Not raise TooMuchTagError")
+ rescue ::RSS::TooMuchTagError => e
+ assert_equal(tag, e.tag)
+ assert_equal(parent, e.parent)
+ end
+ end
+ end
+
+ def assert_missing_attribute(tag, attrname)
+ _wrap_assertion do
+ begin
+ yield
+ flunk("Not raise MissingAttributeError")
+ rescue ::RSS::MissingAttributeError => e
+ assert_equal(tag, e.tag)
+ assert_equal(attrname, e.attribute)
+ end
+ end
+ end
+
+ def assert_not_excepted_tag(tag, parent)
+ _wrap_assertion do
+ begin
+ yield
+ flunk("Not raise NotExceptedTagError")
+ rescue ::RSS::NotExceptedTagError => e
+ assert_equal(tag, e.tag)
+ assert_equal(parent, e.parent)
+ end
+ end
+ end
+
+ def assert_not_available_value(tag, value)
+ _wrap_assertion do
+ begin
+ yield
+ flunk("Not raise NotAvailableValueError")
+ rescue ::RSS::NotAvailableValueError => e
+ assert_equal(tag, e.tag)
+ assert_equal(value, e.value)
+ end
+ end
+ end
+
+ end
+ end
+end
+
diff --git a/test/rss/test.rb b/test/rss/test.rb
new file mode 100644
index 000000000..3b462cc4a
--- /dev/null
+++ b/test/rss/test.rb
@@ -0,0 +1,16 @@
+#!/usr/bin/env ruby
+
+require "rbconfig"
+require "rss/parser"
+
+c = Config::CONFIG
+ruby = File.join(c['bindir'], c['ruby_install_name'])
+
+RSS::AVAILABLE_PARSERS.each do |parser|
+ puts "------------------------------------"
+ puts "Using #{parser}"
+ puts "------------------------------------"
+ Dir.glob(ARGV.shift || "test/test_*") do |file|
+ puts(`#{ruby} #{if $DEBUG then '-d' end} -I. -I./lib test/each_parser.rb #{parser} #{file} #{ARGV.join(' ')}`)
+ end
+end
diff --git a/test/rss/test_1.0.rb b/test/rss/test_1.0.rb
new file mode 100644
index 000000000..485a8c4e0
--- /dev/null
+++ b/test/rss/test_1.0.rb
@@ -0,0 +1,237 @@
+require "test/unit"
+require "rexml/document"
+
+require "rss/1.0"
+require "test/common"
+
+class TestCore < Test::Unit::TestCase
+
+ include TestRSSMixin
+
+ def setup
+
+ @rdf_prefix = "rdf"
+ @rdf_uri = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ @uri = "http://purl.org/rss/1.0/"
+
+ end
+
+ def test_RDF
+
+ version = "1.0"
+ encoding = "UTF-8"
+ standalone = "no"
+
+ rdf = RDF.new(version, encoding, standalone)
+
+ doc = REXML::Document.new(rdf.to_s(false))
+
+ xmldecl = doc.xml_decl
+
+ %w(version encoding standalone).each do |x|
+ assert_equal(instance_eval(x), xmldecl.send(x))
+ end
+
+ assert_equal(@rdf_uri, doc.root.namespace)
+
+ end
+
+ def test_channel
+
+ about = "http://hoge.com"
+ title = "fugafuga"
+ link = "http://hoge.com"
+ description = "fugafugafugafuga"
+ resource = "http://hoge.com/hoge.png"
+ image = RDF::Channel::Image.new(resource)
+ items = RDF::Channel::Items.new
+ textinput = RDF::Channel::Textinput.new(resource)
+
+ channel = RDF::Channel.new(about)
+ %w(title link description image items textinput).each do |x|
+ channel.send("#{x}=", instance_eval(x))
+ end
+
+ doc = REXML::Document.new(make_RDF(channel.to_s))
+ c = doc.root.elements[1]
+
+ assert_equal(about, c.attributes["about"])
+ %w(title link description image textinput).each do |x|
+ elem = c.elements[x]
+ assert_equal(x, elem.name)
+ assert_equal(@uri, elem.namespace)
+ if x == "image" or x == "textinput"
+ excepted = resource
+ res = elem.attributes.get_attribute("resource")
+ assert_equal(@rdf_uri, res.namespace)
+ value = res.value
+ else
+ excepted = instance_eval(x)
+ value = elem.text
+ end
+ assert_equal(excepted, value)
+ end
+ assert_equal(@uri, c.elements["items"].namespace)
+ assert_equal("items", c.elements["items"].name)
+
+ end
+
+ def test_channel_image
+
+ resource = "http://hoge.com/hoge.png"
+ image = RDF::Channel::Image.new(resource)
+
+ doc = REXML::Document.new(make_RDF(image.to_s))
+ i = doc.root.elements[1]
+
+ assert_equal("image", i.name)
+ assert_equal(@uri, i.namespace)
+
+ res = i.attributes.get_attribute("resource")
+
+ assert_equal(@rdf_uri, res.namespace)
+ assert_equal(resource, res.value)
+
+ end
+
+ def test_channel_textinput
+
+ resource = "http://hoge.com/hoge.png"
+ textinput = RDF::Channel::Textinput.new(resource)
+
+ doc = REXML::Document.new(make_RDF(textinput.to_s))
+ t = doc.root.elements[1]
+
+ assert_equal("textinput", t.name)
+ assert_equal(@uri, t.namespace)
+
+ res = t.attributes.get_attribute("resource")
+
+ assert_equal(@rdf_uri, res.namespace)
+ assert_equal(resource, res.value)
+
+ end
+
+ def test_items
+
+ items = RDF::Channel::Items.new
+
+ doc = REXML::Document.new(make_RDF(items.to_s))
+ i = doc.root.elements[1]
+
+ assert_equal("items", i.name)
+ assert_equal(@uri, i.namespace)
+
+ assert_equal(1, i.elements.size)
+ assert_equal("Seq", i.elements[1].name)
+ assert_equal(@rdf_uri, i.elements[1].namespace)
+
+ end
+
+ def test_seq
+
+ seq = RDF::Seq.new
+
+ doc = REXML::Document.new(make_RDF(seq.to_s))
+ s = doc.root.elements[1]
+
+ assert_equal("Seq", s.name)
+ assert_equal(@rdf_uri, s.namespace)
+
+ end
+
+ def test_li
+
+ resource = "http://hoge.com/"
+ li = RDF::Li.new(resource)
+
+ doc = REXML::Document.new(make_RDF(li.to_s))
+ l = doc.root.elements[1]
+
+ assert_equal("li", l.name)
+ assert_equal(@rdf_uri, l.namespace(l.prefix))
+
+ res = l.attributes.get_attribute("resource")
+
+ assert_equal('', res.instance_eval("@prefix"))
+ assert_equal(resource, res.value)
+
+ end
+
+ def test_image
+
+ about = "http://hoge.com"
+ title = "fugafuga"
+ url = "http://hoge.com/hoge"
+ link = "http://hoge.com/fuga"
+
+ image = RDF::Image.new(about)
+ %w(title url link).each do |x|
+ image.send("#{x}=", instance_eval(x))
+ end
+
+ doc = REXML::Document.new(make_RDF(image.to_s))
+ i = doc.root.elements[1]
+
+ assert_equal(about, i.attributes["about"])
+ %w(title url link).each do |x|
+ elem = i.elements[x]
+ assert_equal(x, elem.name)
+ assert_equal(@uri, elem.namespace)
+ assert_equal(instance_eval(x), elem.text)
+ end
+
+ end
+
+ def test_item
+
+ about = "http://hoge.com"
+ title = "fugafuga"
+ link = "http://hoge.com/fuga"
+ description = "hogehogehoge"
+
+ item = RDF::Item.new(about)
+ %w(title link description).each do |x|
+ item.send("#{x}=", instance_eval(x))
+ end
+
+ doc = REXML::Document.new(make_RDF(item.to_s))
+ i = doc.root.elements[1]
+
+ assert_equal(about, i.attributes["about"])
+ %w(title link description).each do |x|
+ elem = i.elements[x]
+ assert_equal(x, elem.name)
+ assert_equal(@uri, elem.namespace)
+ assert_equal(instance_eval(x), elem.text)
+ end
+
+ end
+
+ def test_textinput
+
+ about = "http://hoge.com"
+ title = "fugafuga"
+ link = "http://hoge.com/fuga"
+ name = "foo"
+ description = "hogehogehoge"
+
+ textinput = RDF::Textinput.new(about)
+ %w(title link name description).each do |x|
+ textinput.send("#{x}=", instance_eval(x))
+ end
+
+ doc = REXML::Document.new(make_RDF(textinput.to_s))
+ t = doc.root.elements[1]
+
+ assert_equal(about, t.attributes["about"])
+ %w(title link name description).each do |x|
+ elem = t.elements[x]
+ assert_equal(x, elem.name)
+ assert_equal(@uri, elem.namespace)
+ assert_equal(instance_eval(x), elem.text)
+ end
+
+ end
+
+end
diff --git a/test/rss/test_accessor.rb b/test/rss/test_accessor.rb
new file mode 100644
index 000000000..563e5eca9
--- /dev/null
+++ b/test/rss/test_accessor.rb
@@ -0,0 +1,24 @@
+require "test/unit"
+require "rss/parser"
+require "rss/1.0"
+require "rss/2.0"
+require "test/common"
+
+class TestAccessor < Test::Unit::TestCase
+ include TestRSSMixin
+
+ def test_date
+ channel = Rss::Channel.new
+ channel.do_validate = false
+ channel.pubDate = nil
+ assert_nil(channel.pubDate)
+
+ time = Time.now
+ channel.pubDate = time
+ assert_equal(time, channel.pubDate)
+
+ channel.pubDate = nil
+ assert_nil(channel.pubDate)
+ end
+
+end
diff --git a/test/rss/test_content.rb b/test/rss/test_content.rb
new file mode 100644
index 000000000..46a76b1ae
--- /dev/null
+++ b/test/rss/test_content.rb
@@ -0,0 +1,94 @@
+require "test/unit"
+require "cgi-lib"
+require "rexml/document"
+
+require "rss/parser"
+require "rss/content"
+require "test/common"
+
+class TestContent < Test::Unit::TestCase
+ include TestRSSMixin
+
+ def setup
+ @prefix = "content"
+ @uri = "http://purl.org/rss/1.0/modules/content/"
+
+ @parents = %w(item)
+
+ @elems = {
+ :encoded => "<em>ATTENTION</em>",
+ }
+
+ @content_nodes = @elems.collect do |name, value|
+ "<#{@prefix}:#{name}>#{CGI.escapeHTML(value.to_s)}</#{@prefix}:#{name}>"
+ end.join("\n")
+
+ @rss_source = make_RDF(<<-EOR, {@prefix => @uri})
+#{make_channel()}
+#{make_image()}
+#{make_item(@content_nodes)}
+#{make_textinput()}
+EOR
+
+ @rss = Parser.parse(@rss_source)
+ end
+
+ def test_parser
+
+ assert_nothing_raised do
+ Parser.parse(@rss_source)
+ end
+
+ @elems.each do |tag, value|
+ assert_too_much_tag(tag.to_s, "item") do
+ Parser.parse(make_RDF(<<-EOR, {@prefix => @uri}))
+#{make_channel()}
+#{make_item(("<" + @prefix + ":" + tag.to_s + ">" +
+ CGI.escapeHTML(value.to_s) +
+ "</" + @prefix + ":" + tag.to_s + ">") * 2)}
+EOR
+ end
+ end
+
+ end
+
+ def test_accessor
+
+ new_value = {
+ :encoded => "<![CDATA[<it>hoge</it>]]>",
+ }
+
+ @elems.each do |name, value|
+ @parents.each do |parent|
+ meth = "#{RSS::CONTENT_PREFIX}_#{name}"
+ assert_equal(value, @rss.send(parent).send(meth))
+ @rss.send(parent).send("#{meth}=", new_value[name].to_s)
+ assert_equal(new_value[name], @rss.send(parent).send(meth))
+ end
+ end
+
+ end
+
+ def test_to_s
+
+ @elems.each do |name, value|
+ excepted = "<#{@prefix}:#{name}>#{CGI.escapeHTML(value)}</#{@prefix}:#{name}>"
+ @parents.each do |parent|
+ meth = "#{RSS::CONTENT_PREFIX}_#{name}_element"
+ assert_equal(excepted, @rss.send(parent).send(meth))
+ end
+ end
+
+ REXML::Document.new(@rss_source).root.each_element do |parent|
+ if @parents.include?(parent.name)
+ parent.each_element do |elem|
+ if elem.namespace == @uri
+ assert_equal(elem.text, @elems[elem.name.intern].to_s)
+ end
+ end
+ end
+ end
+
+ end
+
+end
diff --git a/test/rss/test_dublincore.rb b/test/rss/test_dublincore.rb
new file mode 100644
index 000000000..e33c3cda3
--- /dev/null
+++ b/test/rss/test_dublincore.rb
@@ -0,0 +1,123 @@
+require "test/unit"
+require "cgi-lib"
+require "rexml/document"
+
+require "rss/parser"
+require "rss/dublincore"
+require "test/common"
+
+class TestDublinCore < Test::Unit::TestCase
+ include TestRSSMixin
+
+ def setup
+ @prefix = "dc"
+ @uri = "http://purl.org/dc/elements/1.1/"
+
+ @parents = %w(channel image item textinput)
+
+ t = Time.iso8601("2000-01-01T12:00:05+00:00")
+ class << t
+ alias_method(:to_s, :iso8601)
+ end
+
+ @elems = {
+ :title => "hoge",
+ :description =>
+ " XML is placing increasingly heavy loads on the existing technical
+ infrastructure of the Internet.",
+ :creator => "Rael Dornfest (mailto:rael@oreilly.com)",
+ :subject => "XML",
+ :publisher => "The O'Reilly Network",
+ :contributor => "hogehoge",
+ :type => "fugafuga",
+ :format => "hohoho",
+ :identifier => "fufufu",
+ :source => "barbar",
+ :language => "ja",
+ :relation => "cococo",
+ :rights => "Copyright (c) 2000 O'Reilly &amp; Associates, Inc.",
+ :date => t,
+ }
+
+ @dc_nodes = @elems.collect do |name, value|
+ "<#{@prefix}:#{name}>#{value}</#{@prefix}:#{name}>"
+ end.join("\n")
+
+ @rss_source = make_RDF(<<-EOR, {@prefix => @uri})
+#{make_channel(@dc_nodes)}
+#{make_image(@dc_nodes)}
+#{make_item(@dc_nodes)}
+#{make_textinput(@dc_nodes)}
+EOR
+
+ @rss = Parser.parse(@rss_source)
+ end
+
+ def test_parser
+
+ assert_nothing_raised do
+ Parser.parse(@rss_source)
+ end
+
+ @elems.each do |tag, value|
+ assert_too_much_tag(tag.to_s, "channel") do
+ Parser.parse(make_RDF(<<-EOR, {@prefix => @uri}))
+#{make_channel(("<" + @prefix + ":" + tag.to_s + ">" +
+ value.to_s +
+ "</" + @prefix + ":" + tag.to_s + ">") * 2)}
+#{make_item}
+EOR
+ end
+ end
+
+ end
+
+ def test_accessor
+
+ new_value = "hoge"
+
+ @elems.each do |name, value|
+ @parents.each do |parent|
+ parsed_value = @rss.send(parent).send("dc_#{name}")
+ if parsed_value.kind_of?(String)
+ parsed_value = CGI.escapeHTML(parsed_value)
+ end
+ assert_equal(value, parsed_value)
+ if name == :date
+ t = Time.iso8601("2003-01-01T02:30:23+09:00")
+ class << t
+ alias_method(:to_s, :iso8601)
+ end
+ @rss.send(parent).send("dc_#{name}=", t.iso8601)
+ assert_equal(t, @rss.send(parent).send("dc_#{name}"))
+ else
+ @rss.send(parent).send("dc_#{name}=", new_value)
+ assert_equal(new_value, @rss.send(parent).send("dc_#{name}"))
+ end
+ end
+ end
+
+ end
+
+ def test_to_s
+
+ @elems.each do |name, value|
+ excepted = "<#{@prefix}:#{name}>#{value}</#{@prefix}:#{name}>"
+ @parents.each do |parent|
+ assert_equal(excepted, @rss.send(parent).send("dc_#{name}_element"))
+ end
+ end
+
+ REXML::Document.new(@rss_source).root.each_element do |parent|
+ if @parents.include?(parent.name)
+ parent.each_element do |elem|
+ if elem.namespace == @uri
+ assert_equal(CGI.escapeHTML(elem.text), @elems[elem.name.intern].to_s)
+ end
+ end
+ end
+ end
+
+ end
+
+end
diff --git a/test/rss/test_parser.rb b/test/rss/test_parser.rb
new file mode 100644
index 000000000..ed6f4d662
--- /dev/null
+++ b/test/rss/test_parser.rb
@@ -0,0 +1,418 @@
+require "test/unit"
+require "rss/parser"
+require "rss/1.0"
+require "test/common"
+
+class TestParser < Test::Unit::TestCase
+ include TestRSSMixin
+
+ def test_RDF
+ assert_ns("", RDF::URI) do
+ Parser.parse(<<-EOR)
+#{make_xmldecl}
+<RDF/>
+EOR
+ end
+
+ assert_ns("", RDF::URI) do
+ Parser.parse(<<-EOR)
+#{make_xmldecl}
+<RDF xmlns="hoge"/>
+EOR
+ end
+
+ assert_ns("rdf", RDF::URI) do
+ Parser.parse(<<-EOR)
+#{make_xmldecl}
+<rdf:RDF xmlns:rdf="hoge"/>
+EOR
+ end
+
+ assert_parse(<<-EOR, :missing_tag, "channel", "RDF")
+#{make_xmldecl}
+<rdf:RDF xmlns:rdf="#{RSS::RDF::URI}"/>
+EOR
+
+ assert_parse(<<-EOR, :missing_tag, "channel", "RDF")
+#{make_xmldecl}
+<RDF xmlns="#{RSS::RDF::URI}"/>
+EOR
+
+ assert_parse(<<-EOR, :missing_tag, "channel", "RDF")
+#{make_xmldecl}
+<RDF xmlns="#{RSS::RDF::URI}"/>
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "item", "RDF")
+#{make_channel}
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "item", "RDF")
+#{make_channel}
+#{make_image}
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "item", "RDF")
+#{make_channel}
+#{make_textinput}
+EOR
+
+ assert_too_much_tag("image", "RDF") do
+ Parser.parse(make_RDF(<<-EOR))
+#{make_channel}
+#{make_image}
+#{make_image}
+#{make_item}
+#{make_textinput}
+EOR
+ end
+
+ assert_not_excepted_tag("image", "RDF") do
+ Parser.parse(make_RDF(<<-EOR))
+#{make_channel}
+#{make_item}
+#{make_image}
+#{make_textinput}
+EOR
+ end
+
+ assert_parse(make_RDF(<<-EOR), :nothing_raised)
+#{make_channel}
+#{make_image}
+#{make_item}
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :nothing_raised)
+#{make_channel}
+#{make_image}
+#{make_item}
+#{make_textinput}
+EOR
+
+ 1.step(15, 3) do |i|
+ rss = make_RDF() do
+ res = make_channel
+ i.times { res << make_item }
+ res
+ end
+ assert_parse(rss, :nothing_raised)
+ end
+
+ end
+
+ def test_channel
+
+ assert_parse(make_RDF(<<-EOR), :missing_attribute, "channel", "about")
+<channel />
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "title", "channel")
+<channel rdf:about="http://example.com/"/>
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "link", "channel")
+<channel rdf:about="http://example.com/">
+ <title>hoge</title>
+</channel>
+EOR
+
+ assert_parse(make_RDF(<<EOR), :missing_tag, "description", "channel")
+<channel rdf:about="http://example.com/">
+ <title>hoge</title>
+ <link>http://example.com/</link>
+</channel>
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "items", "channel")
+<channel rdf:about="http://example.com/">
+ <title>hoge</title>
+ <link>http://example.com/</link>
+ <description>hogehoge</description>
+</channel>
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_attribute, "image", "resource")
+<channel rdf:about="http://example.com/">
+ <title>hoge</title>
+ <link>http://example.com/</link>
+ <description>hogehoge</description>
+ <image/>
+</channel>
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "items", "channel")
+<channel rdf:about="http://example.com/">
+ <title>hoge</title>
+ <link>http://example.com/</link>
+ <description>hogehoge</description>
+ <image rdf:resource="http://example.com/hoge.png" />
+</channel>
+EOR
+
+ rss = make_RDF(<<-EOR)
+<channel rdf:about="http://example.com/">
+ <title>hoge</title>
+ <link>http://example.com/</link>
+ <description>hogehoge</description>
+ <image rdf:resource="http://example.com/hoge.png" />
+ <items/>
+</channel>
+EOR
+
+ assert_missing_tag("Seq", "items") do
+ Parser.parse(rss)
+ end
+
+ assert_missing_tag("item", "RDF") do
+ Parser.parse(rss, false).validate
+ end
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "item", "RDF")
+<channel rdf:about="http://example.com/">
+ <title>hoge</title>
+ <link>http://example.com/</link>
+ <description>hogehoge</description>
+ <image rdf:resource="http://example.com/hoge.png" />
+ <items>
+ <rdf:Seq>
+ </rdf:Seq>
+ </items>
+</channel>
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_attribute, "textinput", "resource")
+<channel rdf:about="http://example.com/">
+ <title>hoge</title>
+ <link>http://example.com/</link>
+ <description>hogehoge</description>
+ <image rdf:resource="http://example.com/hoge.png" />
+ <items>
+ <rdf:Seq>
+ </rdf:Seq>
+ </items>
+ <textinput/>
+</channel>
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "item", "RDF")
+<channel rdf:about="http://example.com/">
+ <title>hoge</title>
+ <link>http://example.com/</link>
+ <description>hogehoge</description>
+ <image rdf:resource="http://example.com/hoge.png" />
+ <items>
+ <rdf:Seq>
+ </rdf:Seq>
+ </items>
+ <textinput rdf:resource="http://example.com/search" />
+</channel>
+EOR
+
+ end
+
+ def test_image
+
+ assert_parse(make_RDF(<<-EOR), :missing_attribute, "image", "about")
+#{make_channel}
+<image>
+</image>
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "title", "image")
+#{make_channel}
+<image rdf:about="http://example.com/hoge.png">
+</image>
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "url", "image")
+#{make_channel}
+<image rdf:about="http://example.com/hoge.png">
+ <title>hoge</title>
+</image>
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "link", "image")
+#{make_channel}
+<image rdf:about="http://example.com/hoge.png">
+ <title>hoge</title>
+ <url>http://example.com/hoge.png</url>
+</image>
+EOR
+
+ rss = make_RDF(<<-EOR)
+#{make_channel}
+<image rdf:about="http://example.com/hoge.png">
+ <title>hoge</title>
+ <link>http://example.com/</link>
+ <url>http://example.com/hoge.png</url>
+</image>
+EOR
+
+ assert_missing_tag("url", "image") do
+ Parser.parse(rss)
+ end
+
+ assert_missing_tag("item", "RDF") do
+ Parser.parse(rss, false).validate
+ end
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "item", "RDF")
+#{make_channel}
+<image rdf:about="http://example.com/hoge.png">
+ <title>hoge</title>
+ <url>http://example.com/hoge.png</url>
+ <link>http://example.com/</link>
+</image>
+EOR
+
+ end
+
+ def test_item
+
+ assert_parse(make_RDF(<<-EOR), :missing_attribute, "item", "about")
+#{make_channel}
+#{make_image}
+<item>
+</item>
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "title", "item")
+#{make_channel}
+#{make_image}
+<item rdf:about="http://example.com/hoge.html">
+</item>
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "link", "item")
+#{make_channel}
+#{make_image}
+<item rdf:about="http://example.com/hoge.html">
+ <title>hoge</title>
+</item>
+EOR
+
+ assert_too_much_tag("title", "item") do
+ Parser.parse(make_RDF(<<-EOR))
+#{make_channel}
+#{make_image}
+<item rdf:about="http://example.com/hoge.html">
+ <title>hoge</title>
+ <title>hoge</title>
+ <link>http://example.com/hoge.html</link>
+</item>
+EOR
+ end
+
+ assert_parse(make_RDF(<<-EOR), :nothing_raised)
+#{make_channel}
+#{make_image}
+<item rdf:about="http://example.com/hoge.html">
+ <title>hoge</title>
+ <link>http://example.com/hoge.html</link>
+</item>
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :nothing_raised)
+#{make_channel}
+#{make_image}
+<item rdf:about="http://example.com/hoge.html">
+ <title>hoge</title>
+ <link>http://example.com/hoge.html</link>
+ <description>hogehoge</description>
+</item>
+EOR
+
+ end
+
+ def test_textinput
+
+ assert_parse(make_RDF(<<-EOR), :missing_attribute, "textinput", "about")
+#{make_channel}
+#{make_image}
+#{make_item}
+<textinput>
+</textinput>
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "title", "textinput")
+#{make_channel}
+#{make_image}
+#{make_item}
+<textinput rdf:about="http://example.com/search.html">
+</textinput>
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "description", "textinput")
+#{make_channel}
+#{make_image}
+#{make_item}
+<textinput rdf:about="http://example.com/search.html">
+ <title>hoge</title>
+</textinput>
+EOR
+
+ assert_too_much_tag("title", "textinput") do
+ Parser.parse(make_RDF(<<-EOR))
+#{make_channel}
+#{make_image}
+#{make_item}
+<textinput rdf:about="http://example.com/search.html">
+ <title>hoge</title>
+ <title>hoge</title>
+ <description>hogehoge</description>
+</textinput>
+EOR
+ end
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "name", "textinput")
+#{make_channel}
+#{make_image}
+#{make_item}
+<textinput rdf:about="http://example.com/search.html">
+ <title>hoge</title>
+ <description>hogehoge</description>
+</textinput>
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :missing_tag, "link", "textinput")
+#{make_channel}
+#{make_image}
+#{make_item}
+<textinput rdf:about="http://example.com/search.html">
+ <title>hoge</title>
+ <description>hogehoge</description>
+ <name>key</name>
+</textinput>
+EOR
+
+ assert_parse(make_RDF(<<-EOR), :nothing_raised)
+#{make_channel}
+#{make_image}
+#{make_item}
+<textinput rdf:about="http://example.com/search.html">
+ <title>hoge</title>
+ <description>hogehoge</description>
+ <name>key</name>
+ <link>http://example.com/search.html</link>
+</textinput>
+EOR
+
+ end
+
+ def test_ignore
+
+ rss = make_RDF(<<-EOR)
+#{make_channel}
+#{make_item}
+<a/>
+EOR
+
+ assert_parse(rss, :nothing_raised)
+
+ assert_not_excepted_tag("a", "RDF") do
+ Parser.parse(rss, true, false)
+ end
+
+ end
+
+end
diff --git a/test/rss/test_syndication.rb b/test/rss/test_syndication.rb
new file mode 100644
index 000000000..45e55c6fc
--- /dev/null
+++ b/test/rss/test_syndication.rb
@@ -0,0 +1,122 @@
+require "test/unit"
+require "cgi-lib"
+require "rexml/document"
+
+require "rss/parser"
+require "rss/syndication"
+require "test/common"
+
+class TestSyndication < Test::Unit::TestCase
+ include TestRSSMixin
+
+ def setup
+ @prefix = "sy"
+ @uri = "http://purl.org/rss/1.0/modules/syndication/"
+
+ @parents = %w(channel)
+
+ t = Time.iso8601("2000-01-01T12:00:05+00:00")
+ class << t
+ alias_method(:to_s, :iso8601)
+ end
+
+ @elems = {
+ :updatePeriod => "hourly",
+ :updateFrequency => 2,
+ :updateBase => t,
+ }
+
+ @sy_nodes = @elems.collect do |name, value|
+ "<#{@prefix}:#{name}>#{CGI.escapeHTML(value.to_s)}</#{@prefix}:#{name}>"
+ end.join("\n")
+
+ @rss_source = make_RDF(<<-EOR, {@prefix => @uri})
+#{make_channel(@sy_nodes)}
+#{make_image()}
+#{make_item()}
+#{make_textinput()}
+EOR
+
+ @rss = Parser.parse(@rss_source)
+ end
+
+ def test_parser
+
+ assert_nothing_raised do
+ Parser.parse(@rss_source)
+ end
+
+ @elems.each do |tag, value|
+ assert_too_much_tag(tag.to_s, "channel") do
+ Parser.parse(make_RDF(<<-EOR, {@prefix => @uri}))
+#{make_channel(("<" + @prefix + ":" + tag.to_s + ">" +
+ CGI.escapeHTML(value.to_s) +
+ "</" + @prefix + ":" + tag.to_s + ">") * 2)}
+#{make_item}
+EOR
+ end
+ end
+
+ end
+
+ def test_accessor
+
+ t = Time.iso8601("2003-01-01T12:00:23+09:00")
+ class << t
+ alias_method(:to_s, :iso8601)
+ end
+
+ new_value = {
+ :updatePeriod => "daily",
+ :updateFrequency => +11,
+ :updateBase => t,
+ }
+
+ @elems.each do |name, value|
+ @parents.each do |parent|
+ assert_equal(value, @rss.send(parent).send("sy_#{name}"))
+ @rss.send(parent).send("sy_#{name}=", new_value[name].to_s)
+ assert_equal(new_value[name], @rss.send(parent).send("sy_#{name}"))
+ end
+ end
+
+ %w(hourly daily weekly monthly yearly).each do |x|
+ @parents.each do |parent|
+ assert_nothing_raised do
+ @rss.send(parent).sy_updatePeriod = x
+ end
+ end
+ end
+
+ %w(-2 0.3 -0.4).each do |x|
+ @parents.each do |parent|
+ assert_not_available_value("updateBase", x) do
+ @rss.send(parent).sy_updateBase = x
+ end
+ end
+ end
+
+ end
+
+ def test_to_s
+
+ @elems.each do |name, value|
+ excepted = "<#{@prefix}:#{name}>#{value}</#{@prefix}:#{name}>"
+ @parents.each do |parent|
+ assert_equal(excepted, @rss.send(parent).send("sy_#{name}_element"))
+ end
+ end
+
+ REXML::Document.new(@rss_source).root.each_element do |parent|
+ if @parents.include?(parent.name)
+ parent.each_element do |elem|
+ if elem.namespace == @uri
+ assert_equal(elem.text, @elems[elem.name.intern].to_s)
+ end
+ end
+ end
+ end
+
+ end
+
+end
diff --git a/test/rss/test_trackback.rb b/test/rss/test_trackback.rb
new file mode 100644
index 000000000..c49bda5e3
--- /dev/null
+++ b/test/rss/test_trackback.rb
@@ -0,0 +1,110 @@
+require "test/unit"
+require "cgi-lib"
+require "rexml/document"
+
+require "rss/parser"
+require "rss/trackback"
+require "test/common"
+
+class TestTrackBack < Test::Unit::TestCase
+ include TestRSSMixin
+
+ def setup
+ @prefix = "trackback"
+ @uri = "http://madskills.com/public/xml/rss/module/trackback/"
+
+ @parents = %w(item)
+
+ @elems = {
+ :ping => "http://bar.com/tb.cgi?tb_id=rssplustrackback",
+ :about => "http://foo.com/trackback/tb.cgi?tb_id=20020923",
+ }
+
+ @content_nodes = @elems.collect do |name, value|
+ "<#{@prefix}:#{name} rdf:resource=\"#{CGI.escapeHTML(value.to_s)}\"/>"
+ end.join("\n")
+
+ @rss_source = make_RDF(<<-EOR, {@prefix => @uri})
+#{make_channel()}
+#{make_image()}
+#{make_item(@content_nodes)}
+#{make_textinput()}
+EOR
+
+ @rss = Parser.parse(@rss_source)
+ end
+
+ def test_parser
+
+ assert_nothing_raised do
+ Parser.parse(@rss_source)
+ end
+
+ @elems.find_all{|k, v| k == :ping}.each do |tag, value|
+ assert_too_much_tag(tag.to_s, "item") do
+ Parser.parse(make_RDF(<<-EOR, {@prefix => @uri}))
+#{make_channel()}
+#{make_item(("<" + @prefix + ":" + tag.to_s + " rdf:resource=\"" +
+ CGI.escapeHTML(value.to_s) +
+ "\"/>") * 2)}
+EOR
+ end
+ end
+
+ @elems.find_all{|k, v| k == :about}.each do |tag, value|
+ assert_missing_tag("trackback:ping", "item") do
+ Parser.parse(make_RDF(<<-EOR, {@prefix => @uri}))
+#{make_channel()}
+#{make_item(("<" + @prefix + ":" + tag.to_s + " rdf:resource=\"" +
+ CGI.escapeHTML(value.to_s) +
+ "\"/>") * 2)}
+EOR
+ end
+
+ end
+
+ end
+
+ def test_accessor
+
+ new_value = {
+ :ping => "http://baz.com/trackback/tb.cgi?tb_id=20030808",
+ :about => "http://hoge.com/trackback/tb.cgi?tb_id=90030808",
+ }
+
+ @elems.each do |name, value|
+ @parents.each do |parent|
+ elem = @rss.send(parent).send("#{RSS::TRACKBACK_PREFIX}_#{name}")
+ meth = "resource"
+ assert_equal(value, elem.send(meth))
+ elem.send("#{meth}=", new_value[name].to_s)
+ assert_equal(new_value[name], elem.send(meth))
+ end
+ end
+
+ end
+
+ def test_to_s
+
+ @elems.each do |name, value|
+ excepted = %Q!<#{@prefix}:#{name} rdf:resource="#{CGI.escapeHTML(value)}"/>!
+ @parents.each do |parent|
+ meth = "#{RSS::TRACKBACK_PREFIX}_#{name}_element"
+ meth << "s" if name == :about
+ assert_equal(excepted, @rss.send(parent).send(meth))
+ end
+ end
+
+ REXML::Document.new(@rss_source).root.each_element do |parent|
+ if @parents.include?(parent.name)
+ parent.each_element do |elem|
+ if elem.namespace == @uri
+ assert_equal(elem.attributes["resource"], @elems[elem.name.intern])
+ end
+ end
+ end
+ end
+
+ end
+
+end