AjaxでShift_JISやEUC-JPは使えるのか?-2- responseXML編
(XHR/responseXMLで読み込むファイルのcharset別 動作ブラウザ)

一般に、Ajaxで使用する文字コードは、UTF-8が推奨されていますが、日本では、過去の資産の多くがShift_JISやEUCで書かれており、 システム上そのデータの文字コードを変更することができないケースも少なくありません。

そこで、 Shift_JISやEUCで書いたXMLを、XMLHttpRequestのresponseXMLで問題なく使えそうなブラウザとそのバージョンを調べてみました。予想通り、responseText以上に多くのブラウザで利用できることがわかりました。

特に、今回は、responseText代用としても使えそうな、XMLの最初のCDATAセクションへ文字列を置くという方法を試しています。

<?xml version="1.0" encoding="EUC-JP"?><res><![CDATA[ 
 今、読み込みました
]]></res>
上記では仮に<res>としてありますが、ルート要素名は何でも構いません。これを、たとえば、下記のように取り出します。
    var xmlDoc = oj.responseXML 
    var resText = xmlDoc.documentElement.firstChild.nodeValue

この時、Ajax側は、見ての通り、XMLデータ側のルート要素名を知っている必要はありません。 ここで取り出した、resTextはただの文字列ですから、これ以上DOMを解析する必要もありません。つまり、responseTextでの処理と同じです。

#ちなみに、この他にxmlDoc.getElementsByTagName("root要素名")[0].firstChild.nodeValue などで取り出すことなどもできまが、
#この場合は、呼び出し側にXML内のルート要素名を書かないといけないのが少し不便。→この検証

これは、responseTextではブラウザ側の文字コード判定に、いまだに実装毎のブレが存在する(注1)のに対し、XML要素のencoding属性を利用して明示することで文字コード判定を確実化する(注2)効果があるのではないかと思います。responseTextに比べて追加しなければならないコード量もわずかですので、得られる文字化け回避という利益と手軽さを考えれば、responseText代替処理としては十分に有効なのではないかと思います。

注1:3.4.1 Charset の誤り
http://www.studyinghttp.net/cgi-bin/rfc.cgi?2616#Sec3.4.1
注2:XML1.0 4.3.3 実体内のキャラクタエンコーディング
http://www.doraneko.org/xml/xml10/19980210/Overview.html#charencoding
http://www.w3.org/TR/REC-xml/#charencoding

もちろん、上記のような、responseText代用として使うのではなく、普通にXMLで、responseXML受信した内容を解析して利用することもできます。

さらに、この結果と過去の調査を踏まえて、バグや文字化けリスクを抱えたバージョンのブラウザは、たとえXmlHttpRequestが使えるものでも勇気をもって静的HTMLなどへ分岐しよう、という場合に使えるブラウザ分岐コードも考えてみました。


【動作確認表】
リンクをクリックして確かめられます。
UTF-8 BOM
win
f1f2e6e7o8o9
mac
f1f2o8o9s1.2s2
Linux
f1f2o8o9k3.5
WinCE
x01ht
UTF-8N
win
f1f2e6e7o8o9
mac
f1f2o8o9s1.2s2
Linux
f1f2o8o9k3.5
WinCE
x01ht
Shift_JIS
win
f1f2e6e7o8o9
mac
f1f2o8o9s1.2s2
Linux
f1f2o8o9k3.5
WinCE
x01ht
EUC_JP
win
f1f2e6e7o8o9
mac
f1f2o8o9s1.2s2
Linux
f1f2o8o9k3.5
WinCE
x01ht

上記リンクをクリックすると、表示されるHTMLが文字化けすることもありますが、その場合は、 ブラウザ側のエンコーディング設定を手動で修正してご確認ください。 ブラウザのメニューから「表示」-「エンコーディング」などから該当するエンコードを選択してください。

Memo:
  • Opera8は、onreadystatechangeでイベントが2重発生してしまいます。v8.01で修正されました。
  • Opera8は、statusTextが使えません。v9で使用可能になりました。
  • Opera8は、CSSのopacityが使えません。v9で使用可能になりました。
  • UTF-8(BOM付き)で作ったファイルは、BOM自体を解釈できずに文字化けしたりエラーを起こすケース(MacIEやPHP)もあります。
  • WinCEのx01htは、SoftBank携帯X01HTで、OSは正確にはWindows Mobile Version 5.0で、ブラウザは、IE Mobile です。

  • 【responseXMLで推奨できそうなブラウザ】(上記動作確認表から○だけ抽出)
    UTF-8 BOM, UTF-8N, Shift_JIS, EUC_JP
    win
    f1f2e6e7o9
    mac
    f1f2o9s1.2s2
    Linux
    f1f2o9k3.5
    Memo:
    responseXMLで日本語利用時のブラウザとして推奨できそうなブラウザは、下記の通りです。
    Win m1 f1 f2 e6 e7 o9
    Mac m1 f1 f2 s1.2 s2 o9
    Linux m1 f1 f2 k3.4 o9

    【参考:最近のブラウザシェア】
    W3Counter Global Web Stats
    July 24, 2006 
    
    Web Browser % 
    1 Internet Explorer 6.0 65% 
    2 Firefox 1.5 22% 
    3 Firefox 1.0 4% 
    4 Internet Explorer 7.0 2% 
    5 Safari 2.0 1% 
    6 Opera 9.0 <1% 
    7 Opera 8.5 <1% 
    8 Mozilla 1.7 <1% 
    9 Safari 1.3 <1% 
    10 Internet Explorer 5.5 <1% 
    
    上記、推奨できそうなブラウザ計 約97%
    

    【ブラウザ分岐サンプルコード】

    これは、上記安定したブラウザでのみAjaxを行い、それ以外のバグや文字化けリスクを抱えたバージョンは、たとえXmlHttpRequestが使えるブラウザでも勇気をもって静的HTMLなどへ分岐しようという場合に使えるコードです。

    
    	////
    	// 上記推奨できそうなブラウザ専用判定
    	//
    	// @sample        if(!chkAjaBrowser()){ location.href='nonajax.htm' }
    	// @sample        oj = new chkAjaBrowser();if(oj.bw.safari){ /* Safari code */ }
    	// @return        ライブラリが動作可能なブラウザだけtrue  true|false
    	//
    	//  Enable list 
    	//   WinIE 5.5+ 
    	//   Konqueror 3.4+
    	//   AppleWebKit系(Safari,OmniWeb,Shiira) 412+ 
    	//   Mozilla系(Firefox,Netscape,Galeon,Epiphany,K-Meleon,Sylera) 20011128+ 
    	//   Opera 9+ 
    	//
    	
    	function chkAjaBrowser()
    	{
    		var a,ua = navigator.userAgent;
    		this.bw= { 
    		  safari    : ((a=ua.split('AppleWebKit/')[1])?(a.split('(')[0]).split('.')[0]:0)>=412 ,
    		  konqueror : ((a=ua.split('Konqueror/')[1])?a.split(';')[0]:0)>=3.4 ,
    		  mozes     : ((a=ua.split('Gecko/')[1])?a.split(" ")[0]:0) >= 20011128 ,
    		  opera     : (!!window.opera) && (document.body.style.opacity=="") ,
    		  msie      : (!!window.ActiveXObject)?(!!(new ActiveXObject("Microsoft.XMLHTTP"))):false 
    		}
    		return (this.bw.safari||this.bw.konqueror||this.bw.mozes||this.bw.opera||this.bw.msie)
    	}
    
    	//もし、Safari1.25まで含めたければ412となっている場所を125とします。あまりお勧めはしませんが。
    

    【検証に使用したコード】

    呼び出される側のデータsjis.xmlなど(各文字コードで保存します。▲▲▲を文字コード別に書換えます UTF-8,Shift_JIS,EUC-JP)

    <?xml version="1.0" encoding="▲▲▲"?><res><![CDATA[ 
     今、読み込みました
    ]]></res>
    

    呼び出し側スクリプト(▲▲▲を文字コード別に書換えます UTF-8,Shift_JIS,EUC-JP)

    <meta http-equiv="Content-Type" content="text/html; charset=▲▲▲" />
    
    <script type="text/javascript">
    
      // XMLHttpRequestオブジェクト生成関数
      function createHttpRequest(){
        
        if(window.XMLHttpRequest){
        
          //Win Mac Linux m1,f1,o8 Mac s1 Linux k3 & Win e7用
          return new XMLHttpRequest() ;
          
        } else if(window.ActiveXObject){
        
          //Win e4,e5,e6用
          try {
            return new ActiveXObject("Msxml2.XMLHTTP") ;
          } catch (e) {
            try {
              return new ActiveXObject("Microsoft.XMLHTTP") ;
            } catch (e2) {  return null; }
           }
        } 
      }
    
      function sendReq(data,method,url){
      
        //XMLHttpRequestオブジェクト生成
        var oj = createHttpRequest();
        
        //着信コールバックメソッド
        oj.onreadystatechange =function () {
          if(oj.readyState==4){
            //レスポンスを取得
            var xmlDoc = oj.responseXML 
            var res = xmlDoc.documentElement.firstChild.nodeValue
            //レスポンスされた文字列をダイアログ表示
            alert(res);
          }
        }
    
        //open メソッド
        oj.open(method,url);
        
        //sendメソッド
        oj.send('');
        
      }
      
    
    </script>
    
    <form>
      <input type    = "button"
             value   = "xxxx.xmlを読み込み、ダイアログ表示します"
             onclick = "sendReq('','GET','./xxxx.xml')">
    </form>
    
    注意:そのページの文字コードがShift_JISやEUC-JPであっても、データ送出時には、
    UTF-8でURLエンコードされている必要があります。「UTF-8でURLエンコード」は、
    JavascriptのencodeURIComponent(文字列)によって処理できます。
    この処理は、一般的な、Ajax関連のライブラリには実装されています。
    
    もし、できるなら、http.confなどへのContent-Typeも指定しておきます。 .htaccessやhttp.confへのAddType設定(▲▲▲を文字コード別に書換えます UTF-8,Shift_JIS,EUC-JP。)
    AddType "text/xml;charset=▲▲▲" .xml
    
    *AddType "application/xml;charset=▲▲▲" .xml でもOK。参考:ajax - Content-Type: 許容判定
    *もし、レンタルサーバーなどで自分ではcharsetを設定できなければ、そのサーバーの文字コードに合わせるのが安全です。


    今回、検証に利用したブラウザバージョン:

    Win f1 : バージョン 1.5.0.4
    Win f2 : バージョン 2.0b1
    Win e6 : バージョン 6.0.2900.2180.xpsp_sp2_gdr.050301-1519
    Win e7 : バージョン 7.0.5450.4
    Win o8 : バージョン8.00 Build 7561
    Win o8 : バージョン8.01 Build 7642
    Win o8.5 : バージョン8.5 Build 7702
    Win o9 : バージョン9.00 Build 8502

    Mac f1 : バージョン 1.5.0.4
    Mac f2 : バージョン 2.0b1
    Mac s1.2 : バージョン 1.2(v125)
    Mac s2 : バージョン 2.0.4(419.3)
    Mac o8.5 : バージョン 8.5 Build 2182
    Mac o9 : バージョン 9.00 Build 3447

    Linux f1 : バージョン 1.5.0.1
    Linux f2 : バージョン 2.0b1
    Linux o8.54 : バージョン 8.54 Build 1745
    Linux o9 : バージョン 9.00 Build 344
    Linux k3.5 : バージョン 3.5.3

    WinCE : X01HT Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; HTC/X01HT; PPC; 240x320)

    この他に、文字コードによって生じる文字化け調査
    http://jsgt.org/ajax/ref/charset_test/responseXML/test_1_make_table.php