summaryrefslogtreecommitdiff
path: root/ruby_1_8_5/lib/rss/rss.rb
diff options
context:
space:
mode:
Diffstat (limited to 'ruby_1_8_5/lib/rss/rss.rb')
-rw-r--r--ruby_1_8_5/lib/rss/rss.rb1015
1 files changed, 1015 insertions, 0 deletions
diff --git a/ruby_1_8_5/lib/rss/rss.rb b/ruby_1_8_5/lib/rss/rss.rb
new file mode 100644
index 0000000000..a06985af94
--- /dev/null
+++ b/ruby_1_8_5/lib/rss/rss.rb
@@ -0,0 +1,1015 @@
+require "time"
+
+class Time
+ class << self
+ unless respond_to?(:w3cdtf)
+ def w3cdtf(date)
+ if /\A\s*
+ (-?\d+)-(\d\d)-(\d\d)
+ (?:T
+ (\d\d):(\d\d)(?::(\d\d))?
+ (\.\d+)?
+ (Z|[+-]\d\d:\d\d)?)?
+ \s*\z/ix =~ date and (($5 and $8) or (!$5 and !$8))
+ datetime = [$1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i]
+ datetime << $7.to_f * 1000000 if $7
+ if $8
+ Time.utc(*datetime) - zone_offset($8)
+ else
+ Time.local(*datetime)
+ end
+ else
+ raise ArgumentError.new("invalid date: #{date.inspect}")
+ end
+ end
+ end
+ end
+
+ unless instance_methods.include?("w3cdtf")
+ alias w3cdtf iso8601
+ end
+end
+
+require "English"
+require "rss/utils"
+require "rss/converter"
+require "rss/xml-stylesheet"
+
+module RSS
+
+ VERSION = "0.1.6"
+
+ URI = "http://purl.org/rss/1.0/"
+
+ DEBUG = false
+
+ 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 NotExpectedTagError < InvalidRSSError
+ attr_reader :tag, :uri, :parent
+ def initialize(tag, uri, parent)
+ @tag, @uri, @parent = tag, uri, parent
+ super("tag <{#{uri}}#{tag}> is not expected in tag <#{parent}>")
+ end
+ end
+ # For backward compatibility :X
+ NotExceptedTagError = NotExpectedTagError
+
+ class NotAvailableValueError < InvalidRSSError
+ attr_reader :tag, :value, :attribute
+ def initialize(tag, value, attribute=nil)
+ @tag, @value, @attribute = tag, value, attribute
+ message = "value <#{value}> of "
+ message << "attribute <#{attribute}> of " if attribute
+ message << "tag <#{tag}> is not available."
+ super(message)
+ end
+ end
+
+ class UnknownConversionMethodError < Error
+ attr_reader :to, :from
+ def initialize(to, from)
+ @to = to
+ @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 = to
+ @from = from
+ super("can't convert #{@string} to #{to} from #{from}.")
+ end
+ end
+
+ class NotSetError < Error
+ attr_reader :name, :variables
+ def initialize(name, variables)
+ @name = name
+ @variables = variables
+ super("required variables of #{@name} are not set: #{@variables.join(', ')}")
+ end
+ end
+
+ module BaseModel
+
+ include Utils
+
+ def install_have_child_element(tag_name, uri, occurs, name=nil)
+ name ||= tag_name
+ add_need_initialize_variable(name)
+ install_model(tag_name, uri, occurs, name)
+
+ attr_accessor name
+ install_element(name) do |n, elem_name|
+ <<-EOC
+ if @#{n}
+ "\#{@#{n}.to_s(need_convert, indent)}"
+ else
+ ''
+ end
+EOC
+ end
+ end
+ alias_method(:install_have_attribute_element, :install_have_child_element)
+
+ def install_have_children_element(tag_name, uri, occurs, name=nil, plural_name=nil)
+ name ||= tag_name
+ plural_name ||= "#{name}s"
+ add_have_children_element(name, plural_name)
+ add_plural_form(name, plural_name)
+ install_model(tag_name, uri, occurs, plural_name)
+
+ def_children_accessor(name, plural_name)
+ install_element(name, "s") do |n, elem_name|
+ <<-EOC
+ rv = []
+ @#{n}.each do |x|
+ value = "\#{x.to_s(need_convert, indent)}"
+ rv << value if /\\A\\s*\\z/ !~ value
+ end
+ rv.join("\n")
+EOC
+ end
+ end
+
+ def install_text_element(tag_name, uri, occurs, name=nil, type=nil, disp_name=nil)
+ name ||= tag_name
+ disp_name ||= name
+ self::ELEMENTS << name
+ add_need_initialize_variable(name)
+ install_model(tag_name, uri, occurs, name)
+
+ def_corresponded_attr_writer name, type, disp_name
+ convert_attr_reader name
+ install_element(name) do |n, elem_name|
+ <<-EOC
+ if @#{n}
+ rv = "\#{indent}<#{elem_name}>"
+ value = html_escape(@#{n})
+ if need_convert
+ rv << convert(value)
+ else
+ rv << value
+ end
+ rv << "</#{elem_name}>"
+ rv
+ else
+ ''
+ end
+EOC
+ end
+ end
+
+ def install_date_element(tag_name, uri, occurs, name=nil, type=nil, disp_name=nil)
+ name ||= tag_name
+ type ||= :w3cdtf
+ disp_name ||= name
+ self::ELEMENTS << name
+ add_need_initialize_variable(name)
+ install_model(tag_name, uri, occurs, name)
+
+ # accessor
+ convert_attr_reader name
+ date_writer(name, type, disp_name)
+
+ install_element(name) do |n, elem_name|
+ <<-EOC
+ if @#{n}
+ rv = "\#{indent}<#{elem_name}>"
+ value = html_escape(@#{n}.#{type})
+ if need_convert
+ rv << 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('_', ':')
+ method_name = "#{name}_element#{postfix}"
+ add_to_element_method(method_name)
+ module_eval(<<-EOC, *get_file_and_line_from_caller(2))
+ def #{method_name}(need_convert=true, indent='')
+ #{yield(name, elem_name)}
+ end
+ private :#{method_name}
+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 date_writer(name, type, disp_name=name)
+ module_eval(<<-EOC, *get_file_and_line_from_caller(2))
+ def #{name}=(new_value)
+ if new_value.nil? or 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
+ else
+ @#{name} = nil
+ if /\\A\\s*\\z/ !~ new_value.to_s
+ begin
+ @#{name} = Time.parse(new_value)
+ rescue ArgumentError
+ end
+ end
+ end
+ end
+
+ # Is it need?
+ if @#{name}
+ class << @#{name}
+ undef_method(:to_s)
+ alias_method(:to_s, :#{type})
+ end
+ end
+
+ end
+EOC
+ end
+
+ def integer_writer(name, disp_name=name)
+ module_eval(<<-EOC, *get_file_and_line_from_caller(2))
+ def #{name}=(new_value)
+ if new_value.nil?
+ @#{name} = new_value
+ else
+ if @do_validate
+ begin
+ @#{name} = Integer(new_value)
+ rescue ArgumentError
+ raise NotAvailableValueError.new('#{disp_name}', new_value)
+ end
+ else
+ @#{name} = new_value.to_i
+ end
+ end
+ end
+EOC
+ end
+
+ def positive_integer_writer(name, disp_name=name)
+ module_eval(<<-EOC, *get_file_and_line_from_caller(2))
+ def #{name}=(new_value)
+ if new_value.nil?
+ @#{name} = new_value
+ else
+ if @do_validate
+ begin
+ tmp = Integer(new_value)
+ raise ArgumentError if tmp <= 0
+ @#{name} = tmp
+ rescue ArgumentError
+ raise NotAvailableValueError.new('#{disp_name}', new_value)
+ end
+ else
+ @#{name} = new_value.to_i
+ end
+ end
+ end
+EOC
+ end
+
+ def boolean_writer(name, disp_name=name)
+ module_eval(<<-EOC, *get_file_and_line_from_caller(2))
+ def #{name}=(new_value)
+ if new_value.nil?
+ @#{name} = new_value
+ else
+ if @do_validate and
+ ![true, false, "true", "false"].include?(new_value)
+ raise NotAvailableValueError.new('#{disp_name}', new_value)
+ end
+ if [true, false].include?(new_value)
+ @#{name} = new_value
+ else
+ @#{name} = new_value == "true"
+ end
+ end
+ end
+EOC
+ end
+
+ def def_children_accessor(accessor_name, plural_name)
+ module_eval(<<-EOC, *get_file_and_line_from_caller(2))
+ def #{plural_name}
+ @#{accessor_name}
+ end
+
+ def #{accessor_name}(*args)
+ if args.empty?
+ @#{accessor_name}.first
+ else
+ @#{accessor_name}[*args]
+ end
+ end
+
+ def #{accessor_name}=(*args)
+ warn("Warning:\#{caller.first.sub(/:in `.*'\z/, '')}: " \
+ "Don't use `#{accessor_name} = XXX'/`set_#{accessor_name}(XXX)'. " \
+ "Those APIs are not sense of Ruby. " \
+ "Use `#{plural_name} << XXX' instead of them.")
+ 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
+
+ class Element
+
+ extend BaseModel
+ include Utils
+
+ INDENT = " "
+
+ MUST_CALL_VALIDATORS = {}
+ MODELS = []
+ GET_ATTRIBUTES = []
+ HAVE_CHILDREN_ELEMENTS = []
+ TO_ELEMENT_METHODS = []
+ NEED_INITIALIZE_VARIABLES = []
+ PLURAL_FORMS = {}
+
+ class << self
+
+ def must_call_validators
+ MUST_CALL_VALIDATORS
+ end
+ def models
+ MODELS
+ end
+ def get_attributes
+ GET_ATTRIBUTES
+ end
+ def have_children_elements
+ HAVE_CHILDREN_ELEMENTS
+ end
+ def to_element_methods
+ TO_ELEMENT_METHODS
+ end
+ def need_initialize_variables
+ NEED_INITIALIZE_VARIABLES
+ end
+ def plural_forms
+ PLURAL_FORMS
+ end
+
+
+ def inherited(klass)
+ klass.const_set("MUST_CALL_VALIDATORS", {})
+ klass.const_set("MODELS", [])
+ klass.const_set("GET_ATTRIBUTES", [])
+ klass.const_set("HAVE_CHILDREN_ELEMENTS", [])
+ klass.const_set("TO_ELEMENT_METHODS", [])
+ klass.const_set("NEED_INITIALIZE_VARIABLES", [])
+ klass.const_set("PLURAL_FORMS", {})
+
+ klass.module_eval(<<-EOC)
+ public
+
+ @tag_name = name.split(/::/).last
+ @tag_name[0,1] = @tag_name[0,1].downcase
+ @have_content = false
+
+ def self.must_call_validators
+ super.merge(MUST_CALL_VALIDATORS)
+ end
+ def self.models
+ MODELS + super
+ end
+ def self.get_attributes
+ GET_ATTRIBUTES + super
+ end
+ def self.have_children_elements
+ HAVE_CHILDREN_ELEMENTS + super
+ end
+ def self.to_element_methods
+ TO_ELEMENT_METHODS + super
+ end
+ def self.need_initialize_variables
+ NEED_INITIALIZE_VARIABLES + super
+ end
+ def self.plural_forms
+ super.merge(PLURAL_FORMS)
+ end
+
+
+ def self.install_must_call_validator(prefix, uri)
+ MUST_CALL_VALIDATORS[uri] = prefix
+ end
+
+ def self.install_model(tag, uri, occurs=nil, getter=nil)
+ getter ||= tag
+ if m = MODELS.find {|t, u, o, g| t == tag and u == uri}
+ m[2] = occurs
+ else
+ MODELS << [tag, uri, occurs, getter]
+ end
+ end
+
+ def self.install_get_attribute(name, uri, required=true,
+ type=nil, disp_name=nil,
+ element_name=nil)
+ disp_name ||= name
+ element_name ||= name
+ def_corresponded_attr_writer name, type, disp_name
+ convert_attr_reader name
+ if type == :boolean and /^is/ =~ name
+ alias_method "\#{$POSTMATCH}?", name
+ end
+ GET_ATTRIBUTES << [name, uri, required, element_name]
+ add_need_initialize_variable(disp_name)
+ end
+
+ def self.def_corresponded_attr_writer(name, type=nil, disp_name=name)
+ case type
+ when :integer
+ integer_writer name, disp_name
+ when :positive_integer
+ positive_integer_writer name, disp_name
+ when :boolean
+ boolean_writer name, disp_name
+ when :w3cdtf, :rfc822, :rfc2822
+ date_writer name, type, disp_name
+ else
+ attr_writer name
+ end
+ end
+
+ def self.content_setup(type=nil)
+ def_corresponded_attr_writer "content", type
+ convert_attr_reader :content
+ @have_content = true
+ end
+
+ def self.have_content?
+ @have_content
+ end
+
+ def self.add_have_children_element(variable_name, plural_name)
+ HAVE_CHILDREN_ELEMENTS << [variable_name, plural_name]
+ end
+
+ def self.add_to_element_method(method_name)
+ TO_ELEMENT_METHODS << method_name
+ end
+
+ def self.add_need_initialize_variable(variable_name)
+ NEED_INITIALIZE_VARIABLES << variable_name
+ end
+
+ def self.add_plural_form(singular, plural)
+ PLURAL_FORMS[singular] = plural
+ end
+
+ EOC
+ end
+
+ def required_prefix
+ nil
+ end
+
+ def required_uri
+ ""
+ end
+
+ def install_ns(prefix, uri)
+ if self::NSPOOL.has_key?(prefix)
+ raise OverlappedPrefixError.new(prefix)
+ end
+ self::NSPOOL[prefix] = uri
+ end
+
+ def tag_name
+ @tag_name
+ end
+ end
+
+ attr_accessor :do_validate
+
+ def initialize(do_validate=true, attrs={})
+ @converter = nil
+ @do_validate = do_validate
+ initialize_variables(attrs)
+ end
+
+ def tag_name
+ self.class.tag_name
+ end
+
+ def full_name
+ tag_name
+ end
+
+ def converter=(converter)
+ @converter = converter
+ targets = children.dup
+ self.class.have_children_elements.each do |variable_name, plural_name|
+ targets.concat(__send__(plural_name))
+ end
+ targets.each do |target|
+ target.converter = converter unless target.nil?
+ end
+ end
+
+ def convert(value)
+ if @converter
+ @converter.convert(value)
+ else
+ value
+ end
+ end
+
+ def validate(ignore_unknown_element=true)
+ validate_attribute
+ __validate(ignore_unknown_element)
+ end
+
+ def validate_for_stream(tags, ignore_unknown_element=true)
+ validate_attribute
+ __validate(ignore_unknown_element, tags, false)
+ end
+
+ def setup_maker(maker)
+ target = maker_target(maker)
+ unless target.nil?
+ setup_maker_attributes(target)
+ setup_maker_element(target)
+ setup_maker_elements(target)
+ end
+ end
+
+ def to_s(need_convert=true, indent='')
+ if self.class.have_content?
+ return "" unless @content
+ rv = tag(indent) do |next_indent|
+ h(@content)
+ end
+ else
+ rv = tag(indent) do |next_indent|
+ self.class.to_element_methods.collect do |method_name|
+ __send__(method_name, false, next_indent)
+ end
+ end
+ end
+ rv = convert(rv) if need_convert
+ rv
+ end
+
+ private
+ def initialize_variables(attrs)
+ normalized_attrs = {}
+ attrs.each do |key, value|
+ normalized_attrs[key.to_s] = value
+ end
+ self.class.need_initialize_variables.each do |variable_name|
+ value = normalized_attrs[variable_name.to_s]
+ if value
+ __send__("#{variable_name}=", value)
+ else
+ instance_eval("@#{variable_name} = nil")
+ end
+ end
+ initialize_have_children_elements
+ @content = "" if self.class.have_content?
+ end
+
+ def initialize_have_children_elements
+ self.class.have_children_elements.each do |variable_name, plural_name|
+ instance_eval("@#{variable_name} = []")
+ end
+ end
+
+ def tag(indent, additional_attrs={}, &block)
+ next_indent = indent + INDENT
+
+ attrs = collect_attrs
+ return "" if attrs.nil?
+
+ attrs.update(additional_attrs)
+ start_tag = make_start_tag(indent, next_indent, attrs)
+
+ if block
+ content = block.call(next_indent)
+ else
+ content = []
+ end
+
+ if content.is_a?(String)
+ content = [content]
+ start_tag << ">"
+ end_tag = "</#{full_name}>"
+ else
+ content = content.reject{|x| x.empty?}
+ if content.empty?
+ end_tag = "/>"
+ else
+ start_tag << ">\n"
+ end_tag = "\n#{indent}</#{full_name}>"
+ end
+ end
+
+ start_tag + content.join("\n") + end_tag
+ end
+
+ def make_start_tag(indent, next_indent, attrs)
+ start_tag = ["#{indent}<#{full_name}"]
+ unless attrs.empty?
+ start_tag << attrs.collect do |key, value|
+ %Q[#{h key}="#{h value}"]
+ end.join("\n#{next_indent}")
+ end
+ start_tag.join(" ")
+ end
+
+ def collect_attrs
+ attrs = {}
+ _attrs.each do |name, required, alias_name|
+ value = __send__(alias_name || name)
+ return nil if required and value.nil?
+ next if value.nil?
+ return nil if attrs.has_key?(name)
+ attrs[name] = value
+ end
+ attrs
+ end
+
+ def tag_name_with_prefix(prefix)
+ "#{prefix}:#{tag_name}"
+ end
+
+ # For backward compatibility
+ def calc_indent
+ ''
+ end
+
+ def maker_target(maker)
+ nil
+ end
+
+ def setup_maker_attributes(target)
+ end
+
+ def setup_maker_element(target)
+ self.class.need_initialize_variables.each do |var|
+ value = __send__(var)
+ if value.respond_to?("setup_maker") and
+ !not_need_to_call_setup_maker_variables.include?(var)
+ value.setup_maker(target)
+ else
+ setter = "#{var}="
+ if target.respond_to?(setter)
+ target.__send__(setter, value)
+ end
+ end
+ end
+ end
+
+ def not_need_to_call_setup_maker_variables
+ []
+ end
+
+ def setup_maker_elements(parent)
+ self.class.have_children_elements.each do |name, plural_name|
+ if parent.respond_to?(plural_name)
+ target = parent.__send__(plural_name)
+ __send__(plural_name).each do |elem|
+ elem.setup_maker(target)
+ end
+ end
+ end
+ end
+
+ def set_next_element(tag_name, next_element)
+ klass = next_element.class
+ prefix = ""
+ prefix << "#{klass.required_prefix}_" if klass.required_prefix
+ key = "#{prefix}#{tag_name}"
+ if self.class.plural_forms.has_key?(key)
+ ary = __send__("#{self.class.plural_forms[key]}")
+ ary << next_element
+ else
+ __send__("#{prefix}#{tag_name}=", next_element)
+ end
+ end
+
+ def children
+ rv = []
+ self.class.models.each do |name, uri, occurs, getter|
+ value = __send__(getter)
+ next if value.nil?
+ value = [value] unless value.is_a?(Array)
+ value.each do |v|
+ rv << v if v.is_a?(Element)
+ end
+ end
+ rv
+ end
+
+ def _tags
+ rv = []
+ self.class.models.each do |name, uri, occurs, getter|
+ value = __send__(getter)
+ next if value.nil?
+ if value.is_a?(Array)
+ rv.concat([[uri, name]] * value.size)
+ else
+ rv << [uri, name]
+ end
+ end
+ rv
+ end
+
+ def _attrs
+ self.class.get_attributes.collect do |name, uri, required, element_name|
+ [element_name, required, name]
+ end
+ end
+
+ def __validate(ignore_unknown_element, 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
+ must_call_validators.each do |uri, prefix|
+ _validate(ignore_unknown_element, tags[uri], uri)
+ meth = "#{prefix}_validate"
+ if respond_to?(meth, true)
+ __send__(meth, ignore_unknown_element, tags[uri], uri)
+ end
+ end
+ end
+
+ def validate_attribute
+ _attrs.each do |a_name, required, alias_name|
+ if required and __send__(alias_name || a_name).nil?
+ raise MissingAttributeError.new(tag_name, a_name)
+ end
+ end
+ end
+
+ def _validate(ignore_unknown_element, tags, uri, models=self.class.models)
+ count = 1
+ do_redo = false
+ not_shift = false
+ tag = nil
+ models = models.find_all {|model| model[1] == uri}
+ element_names = models.collect {|model| model[0]}
+ if tags
+ tags_size = tags.size
+ tags = tags.sort_by {|x| element_names.index(x) || tags_size}
+ end
+
+ models.each_with_index do |model, i|
+ name, model_uri, occurs, getter = model
+
+ if DEBUG
+ p "before"
+ p tags
+ p model
+ end
+
+ if not_shift
+ not_shift = false
+ elsif tags
+ tag = tags.shift
+ end
+
+ if DEBUG
+ p "mid"
+ p count
+ end
+
+ case occurs
+ when '?'
+ if count > 2
+ raise TooMuchTagError.new(name, tag_name)
+ else
+ if name == tag
+ do_redo = true
+ else
+ not_shift = true
+ end
+ end
+ when '*'
+ if name == tag
+ do_redo = true
+ else
+ not_shift = true
+ end
+ when '+'
+ if name == tag
+ do_redo = true
+ else
+ if count > 1
+ not_shift = true
+ else
+ raise MissingTagError.new(name, tag_name)
+ end
+ end
+ else
+ if name == tag
+ if models[i+1] and models[i+1][0] != name and
+ tags and tags.first == name
+ raise TooMuchTagError.new(name, tag_name)
+ end
+ else
+ raise MissingTagError.new(name, 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 !ignore_unknown_element and !tags.nil? and !tags.empty?
+ raise NotExpectedTagError.new(tags.first, uri, 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
+
+ module RootElementMixin
+
+ include XMLStyleSheetMixin
+
+ attr_reader :output_encoding
+
+ def initialize(rss_version, version=nil, encoding=nil, standalone=nil)
+ super()
+ @rss_version = rss_version
+ @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 setup_maker(maker)
+ maker.version = version
+ maker.encoding = encoding
+ maker.standalone = standalone
+
+ xml_stylesheets.each do |xss|
+ xss.setup_maker(maker)
+ end
+
+ setup_maker_elements(maker)
+ end
+
+ def to_xml(version=nil, &block)
+ if version.nil? or version == @rss_version
+ to_s
+ else
+ RSS::Maker.make(version) do |maker|
+ setup_maker(maker)
+ block.call(maker) if block
+ end.to_s
+ end
+ end
+
+ private
+ def tag(indent, attrs={}, &block)
+ rv = xmldecl + xml_stylesheet_pi
+ rv << super(indent, ns_declarations.merge(attrs), &block)
+ rv
+ end
+
+ def xmldecl
+ rv = %Q[<?xml version="#{@version}"]
+ if @output_encoding or @encoding
+ rv << %Q[ encoding="#{@output_encoding or @encoding}"]
+ end
+ rv << %Q[ standalone="yes"] if @standalone
+ rv << "?>\n"
+ rv
+ end
+
+ def ns_declarations
+ decls = {}
+ self.class::NSPOOL.collect do |prefix, uri|
+ prefix = ":#{prefix}" unless prefix.empty?
+ decls["xmlns#{prefix}"] = uri
+ end
+ decls
+ end
+
+ def setup_maker_elements(maker)
+ channel.setup_maker(maker) if channel
+ image.setup_maker(maker) if image
+ textinput.setup_maker(maker) if textinput
+ super(maker)
+ end
+ end
+
+end