summaryrefslogtreecommitdiff
path: root/lib/rss/parser.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rss/parser.rb')
-rw-r--r--lib/rss/parser.rb445
1 files changed, 0 insertions, 445 deletions
diff --git a/lib/rss/parser.rb b/lib/rss/parser.rb
deleted file mode 100644
index 6b3fe06419..0000000000
--- a/lib/rss/parser.rb
+++ /dev/null
@@ -1,445 +0,0 @@
-require "forwardable"
-require "open-uri"
-
-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_PARSER_LIBRARIES.inspect}.")
- end
- end
-
- class NotValidXMLParser < Error
- def initialize(parser)
- super("#{parser} is not available XML parser. " <<
- "available XML parser is " <<
- "#{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 Parser
-
- extend Forwardable
-
- class << self
-
- @@default_parser = nil
-
- def default_parser
- @@default_parser || AVAILABLE_PARSERS.first
- end
-
- def default_parser=(new_value)
- if AVAILABLE_PARSERS.include?(new_value)
- @@default_parser = new_value
- else
- raise NotValidXMLParser.new(new_value)
- end
- end
-
- def parse(rss, do_validate=true, ignore_unknown_element=true, parser_class=default_parser)
- parser = new(rss, parser_class)
- parser.do_validate = do_validate
- parser.ignore_unknown_element = ignore_unknown_element
- parser.parse
- end
-
- end
-
- def_delegators(:@parser, :parse, :rss,
- :ignore_unknown_element,
- :ignore_unknown_element=, :do_validate,
- :do_validate=)
-
- def initialize(rss, parser_class=self.class.default_parser)
- @parser = parser_class.new(normalize_rss(rss))
- end
-
- private
- def normalize_rss(rss)
- return rss if maybe_xml?(rss)
-
- uri = to_uri(rss)
-
- if uri.respond_to?(:read)
- uri.read
- elsif !rss.tainted? and File.readable?(rss)
- File.open(rss) {|f| f.read}
- else
- rss
- end
- end
-
- def maybe_xml?(source)
- source.is_a?(String) and /</ =~ source
- end
-
- def to_uri(rss)
- return rss if rss.is_a?(::URI::Generic)
-
- begin
- URI(rss)
- rescue ::URI::Error
- rss
- end
- 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
-
- end
-
- class BaseListener
-
- extend Utils
-
- class << self
-
- @@setters = {}
- @@registered_uris = {}
- @@class_names = {}
-
- def install_setter(uri, tag_name, setter)
- @@setters[uri] ||= {}
- @@setters[uri][tag_name] = setter
- end
-
- def setter(uri, tag_name)
- begin
- @@setters[uri][tag_name]
- rescue NameError
- nil
- end
- end
-
- def available_tags(uri)
- begin
- @@setters[uri].keys
- rescue NameError
- []
- end
- end
-
- def register_uri(uri, name)
- @@registered_uris[name] ||= {}
- @@registered_uris[name][uri] = nil
- end
-
- def uri_registered?(uri, name)
- @@registered_uris[name].has_key?(uri)
- end
-
- def install_class_name(uri, tag_name, class_name)
- @@class_names[uri] ||= {}
- @@class_names[uri][tag_name] = class_name
- end
-
- def class_name(uri, tag_name)
- begin
- @@class_names[uri][tag_name]
- rescue NameError
- tag_name[0,1].upcase + tag_name[1..-1]
- end
- end
-
- def install_get_text_element(uri, name, setter)
- install_setter(uri, name, setter)
- def_get_text_element(uri, name, *get_file_and_line_from_caller(1))
- end
-
- private
-
- def def_get_text_element(uri, name, file, line)
- register_uri(uri, name)
- unless private_instance_methods(false).include?("start_#{name}")
- module_eval(<<-EOT, file, line)
- def start_#{name}(name, prefix, attrs, ns)
- uri = ns[prefix]
- if self.class.uri_registered?(uri, #{name.inspect})
- 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)
- else
- start_else_element(name, prefix, attrs, ns)
- end
- end
- EOT
- send("private", "start_#{name}")
- end
- 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
- @xml_stylesheets = []
- end
-
- def xmldecl(version, encoding, standalone)
- @version, @encoding, @standalone = version, encoding, standalone
- end
-
- def instruction(name, content)
- if name == "xml-stylesheet"
- params = parse_pi_content(content)
- if params.has_key?("href")
- @xml_stylesheets << XMLStyleSheet.new(*params)
- end
- end
- end
-
- def tag_start(name, attributes)
- @text_stack.push('')
-
- ns = @ns_stack.last.dup
- attrs = {}
- attributes.each do |n, v|
- if /\Axmlns(?:\z|:)/ =~ n
- ns[$POSTMATCH] = v
- 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?
- @ns_stack.pop
- end
-
- def text(data)
- @text_stack.last << data
- end
-
- private
-
- CONTENT_PATTERN = /\s*([^=]+)=(["'])([^\2]+?)\2/
- def parse_pi_content(content)
- params = {}
- content.scan(CONTENT_PATTERN) do |name, quote, value|
- params[name] = value
- end
- params
- end
-
- def start_else_element(local, prefix, attrs, ns)
- class_name = self.class.class_name(ns[prefix], local)
- current_class = @last_element.class
- if current_class.constants.include?(class_name)
- next_class = current_class.const_get(class_name)
- start_have_something_element(local, prefix, attrs, ns, next_class)
- else
- if @ignore_unknown_element
- @proc_stack.push(nil)
- else
- parent = "ROOT ELEMENT???"
- if current_class.tag_name
- parent = current_class.tag_name
- 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.is_a?(String) or !a_uri.respond_to?(:include?)
- a_uri = [a_uri]
- end
- unless a_uri == [nil]
- for prefix, uri in ns
- if a_uri.include?(uri)
- val = attrs["#{prefix}:#{a_name}"]
- break if val
- end
- end
- end
- if val.nil? and a_uri.include?(nil)
- val = attrs[a_name]
- end
-
- if @do_validate and required and val.nil?
- unless a_uri.include?(nil)
- for prefix, uri in ns
- if a_uri.include?(uri)
- a_name = "#{prefix}:#{a_name}"
- end
- end
- end
- 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
- prefix = ""
- prefix << "#{klass.required_prefix}_" if klass.required_prefix
- previous.instance_eval {set_next_element(prefix, tag_name, 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_PARSER_LIBRARIES
- AVAILABLE_PARSER_LIBRARIES = [
- ["rss/xmlparser", :XMLParserParser],
- ["rss/xmlscanner", :XMLScanParser],
- ["rss/rexmlparser", :REXMLParser],
- ]
- end
-
- AVAILABLE_PARSERS = []
-
- AVAILABLE_PARSER_LIBRARIES.each do |lib, parser|
- begin
- require lib
- AVAILABLE_PARSERS.push(const_get(parser))
- rescue LoadError
- end
- end
-
- if AVAILABLE_PARSERS.empty?
- raise XMLParserNotFound
- end
-end