mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* test/rss/test_xml-stylesheet.rb: added tests for xml-stylesheet.
* lib/rss/xml-stylesheet.rb: added xml-stylesheet parsing function. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@5989 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
2639d6dc80
commit
7ead69e5b3
15 changed files with 385 additions and 85 deletions
|
@ -10,6 +10,8 @@ module RSS
|
|||
class Rss < Element
|
||||
|
||||
include RSS09
|
||||
include RootElementMixin
|
||||
include XMLStyleSheetMixin
|
||||
|
||||
[
|
||||
["channel", nil],
|
||||
|
@ -24,18 +26,9 @@ module RSS
|
|||
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
|
||||
super
|
||||
end
|
||||
|
||||
def output_encoding=(enc)
|
||||
@output_encoding = enc
|
||||
self.converter = Converter.new(@output_encoding, @encoding)
|
||||
end
|
||||
|
||||
def items
|
||||
if @channel
|
||||
@channel.items
|
||||
|
@ -55,7 +48,7 @@ module RSS
|
|||
def to_s(convert=true)
|
||||
rv = <<-EOR
|
||||
#{xmldecl}
|
||||
<rss version="#{@rss_version}"#{ns_declaration}>
|
||||
#{xml_stylesheet_pi}<rss version="#{@rss_version}"#{ns_declaration}>
|
||||
#{channel_element(false)}
|
||||
#{other_element(false, "\t")}
|
||||
</rss>
|
||||
|
@ -65,25 +58,6 @@ EOR
|
|||
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
|
||||
|
@ -423,6 +397,7 @@ EOT
|
|||
check_ns(tag_name, prefix, ns, nil)
|
||||
|
||||
@rss = Rss.new(attrs['version'], @version, @encoding, @standalone)
|
||||
@rss.xml_stylesheets = @xml_stylesheets
|
||||
@last_element = @rss
|
||||
@proc_stack.push Proc.new { |text, tags|
|
||||
@rss.validate_for_stream(tags) if @do_validate
|
||||
|
|
|
@ -10,6 +10,8 @@ module RSS
|
|||
class RDF < Element
|
||||
|
||||
include RSS10
|
||||
include RootElementMixin
|
||||
include XMLStyleSheetMixin
|
||||
|
||||
class << self
|
||||
|
||||
|
@ -45,23 +47,13 @@ module RSS
|
|||
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)
|
||||
super('1.0', version, encoding, standalone)
|
||||
end
|
||||
|
||||
def to_s(convert=true)
|
||||
rv = <<-EORDF
|
||||
#{xmldecl}
|
||||
<#{PREFIX}:RDF#{ns_declaration}>
|
||||
#{xml_stylesheet_pi}<#{PREFIX}:RDF#{ns_declaration}>
|
||||
#{channel_element(false)}
|
||||
#{image_element(false)}
|
||||
#{item_elements(false)}
|
||||
|
@ -74,25 +66,6 @@ EORDF
|
|||
end
|
||||
|
||||
private
|
||||
def xmldecl
|
||||
rv = %Q[<?xml version="#{@version}"]
|
||||
if @output_encoding or @encoding
|
||||
rv << %Q[ encoding="#{@output_encoding or @encoding}"]
|
||||
end
|
||||
rv << %Q[ 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
|
||||
|
@ -647,4 +620,19 @@ EOT
|
|||
BaseListener.install_get_text_element(x, URI, "#{x}=")
|
||||
end
|
||||
|
||||
module ListenerMixin
|
||||
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
|
||||
@rss.xml_stylesheets = @xml_stylesheets
|
||||
@last_element = @rss
|
||||
@proc_stack.push Proc.new { |text, tags|
|
||||
@rss.validate_for_stream(tags) if @do_validate
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -135,6 +135,7 @@ EOT
|
|||
# check_ns(tag_name, prefix, ns, Rss::URI)
|
||||
|
||||
@rss = Rss.new(attrs['version'], @version, @encoding, @standalone)
|
||||
@rss.xml_stylesheets = @xml_stylesheets
|
||||
@last_element = @rss
|
||||
@proc_stack.push Proc.new { |text, tags|
|
||||
@rss.validate_for_stream(tags) if @do_validate
|
||||
|
|
|
@ -25,8 +25,8 @@ module RSS
|
|||
value
|
||||
end
|
||||
|
||||
def def_convert()
|
||||
instance_eval(<<-EOC, *get_file_and_line_from_caller(0))
|
||||
def def_convert(depth=0)
|
||||
instance_eval(<<-EOC, *get_file_and_line_from_caller(depth))
|
||||
def convert(value)
|
||||
if value.kind_of?(String)
|
||||
#{yield('value')}
|
||||
|
@ -37,10 +37,10 @@ module RSS
|
|||
EOC
|
||||
end
|
||||
|
||||
def def_iconv_convert(to_enc, from_enc)
|
||||
def def_iconv_convert(to_enc, from_enc, depth=0)
|
||||
begin
|
||||
require "iconv"
|
||||
def_convert do |value|
|
||||
def_convert(depth+1) do |value|
|
||||
<<-EOC
|
||||
@iconv ||= Iconv.new("#{to_enc}", "#{from_enc}")
|
||||
begin
|
||||
|
@ -68,7 +68,7 @@ module RSS
|
|||
def def_uconv_convert_if_can(meth, to_enc, from_enc)
|
||||
begin
|
||||
require "uconv"
|
||||
def_convert do |value|
|
||||
def_convert(1) do |value|
|
||||
<<-EOC
|
||||
begin
|
||||
Uconv.#{meth}(#{value})
|
||||
|
@ -78,7 +78,7 @@ module RSS
|
|||
EOC
|
||||
end
|
||||
rescue LoadError
|
||||
def_iconv_convert(to_enc, from_enc)
|
||||
def_iconv_convert(to_enc, from_enc, 1)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -191,12 +191,22 @@ module RSS
|
|||
@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('')
|
||||
|
||||
|
@ -204,7 +214,7 @@ module RSS
|
|||
attrs = {}
|
||||
attributes.each do |n, v|
|
||||
if n =~ /\Axmlns:?/
|
||||
ns[$'] = v # $' is post match
|
||||
ns[$POSTMATCH] = v
|
||||
else
|
||||
attrs[n] = v
|
||||
end
|
||||
|
@ -238,15 +248,13 @@ module RSS
|
|||
|
||||
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
|
||||
}
|
||||
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)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
require "time"
|
||||
|
||||
require "English"
|
||||
require "rss/utils"
|
||||
require "rss/converter"
|
||||
require "rss/xml-stylesheet"
|
||||
|
||||
module RSS
|
||||
|
||||
|
@ -365,7 +367,6 @@ EOC
|
|||
|
||||
def initialize(do_validate=true)
|
||||
@converter = nil
|
||||
@output_encoding = nil
|
||||
@do_validate = do_validate
|
||||
initialize_variables
|
||||
end
|
||||
|
@ -561,4 +562,44 @@ EOC
|
|||
|
||||
end
|
||||
|
||||
module RootElementMixin
|
||||
|
||||
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
|
||||
|
||||
private
|
||||
def xmldecl
|
||||
rv = %Q[<?xml version="#{@version}"]
|
||||
if @output_encoding or @encoding
|
||||
rv << %Q[ encoding="#{@output_encoding or @encoding}"]
|
||||
end
|
||||
rv << %Q[ 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
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -3,10 +3,8 @@ 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]
|
||||
file, line, = caller[i].split(':')
|
||||
[file, line.to_i]
|
||||
end
|
||||
|
||||
def html_escape(s)
|
||||
|
|
94
lib/rss/xml-stylesheet.rb
Normal file
94
lib/rss/xml-stylesheet.rb
Normal file
|
@ -0,0 +1,94 @@
|
|||
require "rss/utils"
|
||||
|
||||
module RSS
|
||||
|
||||
module XMLStyleSheetMixin
|
||||
attr_accessor :xml_stylesheets
|
||||
def initialize(*args)
|
||||
super
|
||||
@xml_stylesheets = []
|
||||
end
|
||||
|
||||
private
|
||||
def xml_stylesheet_pi
|
||||
xsss = @xml_stylesheets.collect do |xss|
|
||||
pi = xss.to_s
|
||||
pi = nil if /\A\s*\z/ =~ pi
|
||||
pi
|
||||
end.compact
|
||||
xsss.push("") unless xsss.empty?
|
||||
xsss.join("\n")
|
||||
end
|
||||
end
|
||||
|
||||
class XMLStyleSheet
|
||||
|
||||
include Utils
|
||||
|
||||
ATTRIBUTES = %w(href type title media charset alternate)
|
||||
|
||||
GUESS_TABLE = {
|
||||
"xsl" => "text/xsl",
|
||||
"css" => "text/css",
|
||||
}
|
||||
|
||||
attr_accessor(*ATTRIBUTES)
|
||||
attr_accessor(:do_validate)
|
||||
def initialize(*attrs)
|
||||
@do_validate = true
|
||||
ATTRIBUTES.each do |attr|
|
||||
self.send("#{attr}=", nil)
|
||||
end
|
||||
vars = ATTRIBUTES.dup
|
||||
vars.unshift(:do_validate)
|
||||
attrs.each do |name, value|
|
||||
if vars.include?(name.to_s)
|
||||
self.send("#{name}=", value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def to_s
|
||||
rv = ""
|
||||
if @href
|
||||
rv << %Q[<?xml-stylesheet]
|
||||
ATTRIBUTES.each do |name|
|
||||
if self.send(name)
|
||||
rv << %Q[ #{name}="#{h self.send(name)}"]
|
||||
end
|
||||
end
|
||||
rv << %Q[?>]
|
||||
end
|
||||
rv
|
||||
end
|
||||
|
||||
remove_method(:href=)
|
||||
def href=(value)
|
||||
@href = value
|
||||
if @href and @type.nil?
|
||||
@type = guess_type(@href)
|
||||
end
|
||||
@href
|
||||
end
|
||||
|
||||
remove_method(:alternate=)
|
||||
def alternate=(value)
|
||||
if value.nil? or /\A(?:yes|no)\z/ =~ value
|
||||
@alternate = value
|
||||
else
|
||||
if @do_validate
|
||||
args = ["?xml-stylesheet?", %Q[alternate="#{value}"]]
|
||||
raise NotAvailableValueError.new(*args)
|
||||
end
|
||||
end
|
||||
@alternate
|
||||
end
|
||||
|
||||
private
|
||||
def guess_type(filename)
|
||||
/\.([^.]+)/ =~ filename
|
||||
GUESS_TABLE[$1]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,3 +1,9 @@
|
|||
begin
|
||||
require "xml/parser"
|
||||
rescue LoadError
|
||||
require "xmlparser"
|
||||
end
|
||||
|
||||
begin
|
||||
require "xml/encoding-ja"
|
||||
rescue LoadError
|
||||
|
@ -15,7 +21,7 @@ module RSS
|
|||
|
||||
class REXMLLikeXMLParser < ::XML::Parser
|
||||
|
||||
include XML::Encoding_ja
|
||||
include ::XML::Encoding_ja
|
||||
|
||||
def listener=(listener)
|
||||
@listener = listener
|
||||
|
@ -37,6 +43,10 @@ module RSS
|
|||
@listener.xmldecl(version, encoding, standalone == 1)
|
||||
end
|
||||
|
||||
def processingInstruction(target, content)
|
||||
@listener.instruction(target, content)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class XMLParserParser < BaseParser
|
||||
|
@ -51,7 +61,7 @@ module RSS
|
|||
parser = REXMLLikeXMLParser.new
|
||||
parser.listener = @listener
|
||||
parser.parse(@rss)
|
||||
rescue XMLParserError => e
|
||||
rescue ::XML::Parser::Error => e
|
||||
raise NotWellFormedError.new(parser.line){e.message}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -48,6 +48,7 @@ module RSS
|
|||
xmldecl(@version, @encoding, @standalone)
|
||||
end
|
||||
|
||||
alias_method(:on_pi, :instruction)
|
||||
alias_method(:on_chardata, :text)
|
||||
alias_method(:on_cdata, :text)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue