よしだです

siena / cr.chiba-u.ac.jp (Siena.) writes:
> Source を継承して、という話に戻ると、あちこちで REXML::Source
> クラスを直接参照しているので、これをパラメータ化してもらうか、
> REXML::Source を直接上書き定義するようにしないといけないのですよね。
> 多分、#write のために、REXML::Output も同様かと。

REXML::Source は継承しにくかったので,REXML::Source の文字エ
ンコーディングを拡張可能に書き換えてみました。
rexml/source/エンコーディング名.rb というファイルを読み込みます。

例えば EUC-JP だと rexml/source/euc_jp.rb を読みます。ファイ
ルの内容は以下のような感じです。

require 'uconv'

module REXML
  class Source
    module EUC_JP
      def self.encoding_val(enc)
        :EUC_JP
      end

      def self.val_encoding(enc)
        "EUC-JP"
      end

      def self.utf8_enc(str)
        Uconv.euctou8(str)
      end
    end
  end
end

個人的にはこんなものでも十分なんじゃないかなぁと思います。


diff -ur rexml/rexml/document.rb rexml.new/rexml/document.rb
--- rexml/rexml/document.rb	Sun Apr 28 02:48:18 2002
+++ rexml.new/rexml/document.rb	Fri May 17 20:08:24 2002
@@ -203,7 +203,6 @@
 						self.add( DocType.new( source ) )
 					when XMLDecl::START_RE
 						x = XMLDecl.new( source )
-						source.encoding = x.encoding
 						self.add( x )
 					when Instruction::START_RE
 						self.add( Instruction.new(source) )
diff -ur rexml/rexml/source.rb rexml.new/rexml/source.rb
--- rexml/rexml/source.rb	Tue May 14 13:04:51 2002
+++ rexml.new/rexml/source.rb	Fri May 17 20:12:31 2002
@@ -23,10 +23,10 @@
 		attr_reader :line
 		attr_reader :encoding
 
-		UTF16=0
-		UTF8=1
-		ISO_8859_1=2
-		UNILE=3
+		UTF16=:UTF16
+		UTF8=:UTF8
+		ISO_8859_1=:ISO_8859_1
+		UNILE=:UNILE
 		ENCODINGS = {
 			UTF16=>"UTF-16",
 			UTF8=>"UTF-8",
@@ -43,16 +43,36 @@
 			@line = 0
 		end
 
+		def Source::ext_encoding(enc)
+			if enc.is_a?(String)
+				fname = enc.gsub('-', '_').downcase
+				begin
+					require "rexml/source/#{fname}"
+				rescue LoadError
+					raise "unknown encoding"
+				end
+				eval "REXML::Source::" + fname.upcase
+			elsif enc.is_a?(Symbol)
+				eval "REXML::Source::" + enc.to_s
+			else
+				raise ArgumentError.new("invalid argument")
+			end
+		end
+
 		def Source::encoding_val( enc )
+			return nil if enc.nil?
 			case enc
 			when /^iso-8859-1$/i; ISO_8859_1
 			when /^utf-8$/i; UTF8
 			when /^unile$/i; UNILE
 			when /^utf-16/i; UTF16
+			else
+				ext_encoding(enc).encoding_val(enc)
 			end
 		end
 		def Source::val_encoding( enc )
-			ENCODINGS[enc]
+			return nil if enc.nil?
+			ENCODINGS[enc] || ext_encoding(enc).val_encoding(enc)
 		end
 
 		def encoding=(enc)
@@ -63,9 +83,15 @@
 			when UTF16; :utf16
 			when UNILE; :unile
 			when ISO_8859_1; :asc
-			else
+			when UTF8, nil
 				@to_utf = false
 				:utf8
+			else
+				instance_eval %(
+					def urf8_enc(str)
+						#{Source::ext_encoding(@encoding)}.utf8_enc(str)
+					end)
+				:utf8_enc
 			end
 			instance_eval "alias :encode #{al}"
 		end
@@ -134,6 +160,8 @@
 				utf16(str)
 			elsif @encoding==UNILE
 				unile(str)
+			elsif !@encoding.nil? && @encoding!=UTF8
+				Source::ext_encoding(@encoding).utf8_enc(str)
 			else
 				return str
 			end
diff -ur rexml/rexml/xmldecl.rb rexml.new/rexml/xmldecl.rb
--- rexml/rexml/xmldecl.rb	Tue May 14 13:04:50 2002
+++ rexml.new/rexml/xmldecl.rb	Fri May 17 20:07:22 2002
@@ -73,6 +73,7 @@
 			encoding = encoding[1] unless encoding.nil?
 			standalone = STANDALONE_RE.match(results)
 			standalone = standalone[1] unless standalone.nil?
+			source.encoding = encoding
 			[version, encoding, standalone]
 		end