Hatena::ブログ(Diary)

葉っぱ日記 このページをアンテナに追加

2009-09-28

[][] Using jQuery on WSH  Using jQuery on WSH を含むブックマーク

jQueryを使うと、ajax 経由で取得した XML ドキュメントのような、ブラウザ(window,document)と切り離された対象でも簡単に操作することができます。例えば、リモートから取得したRSSであれば、以下のようなコードで各項目(item)のタイトル(title)やリンク先(link)、日時(dc:date)を取得することができます*1

    $.ajax( {
        url : "http://www.example.com/rss.xml",
        dataType : "xml",
        type : "get",
        success : function( xml ){
            var s = "";
            $( xml ).find( "item" ).each( function(){
                s += 
                    $(this).find( "title" ).text() + " <" +
                    $(this).find( "link" ).text() + ">(" +
                    $(this).find( "dc\\:date" ).text() + ")\n";
            } );
            alert( s );
        }
    } );

このように、jQueryを使うと直接DOMを操作するのに比べてXMLでも楽に扱えるので、ブラウザから切り離された環境である WSH / JScript でも jQuery を使ってみたいと思うのは当然でもあります。というわけで、jQuery を WSH 環境で使えるのか試してみました。

結論から言うと、簡単な準備をしてくことで、少し制限はあるものの十分実用的に WSH 環境でも jQuery を利用することができました。

以下、jQuery をWSHで使うためのコードです。

// グローバル名前空間に window や document などを準備する
(function(){
    if( typeof( document ) == "undefined" ){
        document = new ActiveXObject( "htmlfile" );
        document.write("<html></html>"); // これ重要
    }
    if( typeof( window     ) == "undefined" ) window = document.parentWindow;
    if( typeof( alert      ) == "undefined" ) //alert = window.alert; 
        alert = function(s){ return window.alert( s )};
    if( typeof( confirm       ) == "undefined" ) confirm = function(s){ return window.confirm(s) };
    if( typeof( location      ) == "undefined" ) location = window.location;
    if( typeof( navigator     ) == "undefined" ) navigator = window.navigator;
    _util = {};
    _util.cat = function( filename ){
        var fso = new ActiveXObject( "Scripting.FileSystemObject" );
        var f = fso.OpenTextFile( filename, 1, false );
        return f.ReadAll();
    }
})();

// jQuery の読み込み
eval( _util.cat( "jquery-1.3.2.min.js" ) );

// 簡単な jQuery オブジェクトの操作例
WScript.Echo( $( "<div>" ).attr( "a", "fo" ).get(0).outerHTML );

// もちろん alert も使える。
alert( $( "<div>" ).attr( "a", "fo" ).get(0).outerHTML );

// jQuery.ajax を使ってリモートからXMLを読み込み
$.ajax( {
    url : "http://www.example.com/rss.xml",
    dataType : "xml",
    type : "get",
    async : false, // これ重要
    success : function( xml ){
        var s = "";
        $( xml ).find( "item" ).each( function(){
            s += 
                $(this).find( "title" ).text() + " <" +
                $(this).find( "link" ).text() + "> (" +
                $(this).find( "dc\\:date" ).text() + ")\n";
        } );
        alert( s );
    }
} );

まず、グローバルに document を用意するため、new ActiveXObject( "htmlfile" ) でHTMLDocumentを生成します。これは new ActiveXObject( "Internet Explorer.Application" ) とした場合と異なり、アウトプロセスでIEのインスタンスを生成しないため、非常に軽量です。これで、グローバルな document が用意できたのですが、このままだと document.body や document.documentElement が null なままですので、とりあえずダミーで body を用意してやるために document.write( "<html></html>" ); としてやります。ここまでで document の準備が完了です。

つぎに window ですが、これは document.parentWindow がそのまま利用可能なので、グローバル名前空間に放り出してやります。

通常の JavaScript であればグローバル名前空間は window に支配されているので、例えば alert を呼び出せばそれは暗黙のうちに window.alert の呼び出しとなるわけですが、WSH ではグローバルな名前空間は window とは無関係ですので、window のメンバのうち必要そうなものをグローバルな名前空間に export してやる必要があります。navigator のような単純なプロパティであれば同名のグローバル変数を用意してそこに代入するだけでよいのですが、alert のようなメソッドをexportする場合、alert = window.alert; のような代入では、なぜか呼び出しに失敗するため*2、ラッパ関数を用意してやる必要があります。

window、document をはじめとする一連のグローバルなオブジェクト類の準備ができればあとはjQueryを読み込み、いつもどおりのプログラミングができます。

ただし、本当の window を持っていないため setInterval や setTimeout がうまく扱えません。そのため、jQuery.ajax を呼び出す場合には、async:false が必須となりますので、注意が必要です。(2009-09-30追記: seInterval を誤魔化して async:true で動きました。)もちろん、dataType:"jsonp" などはうまく動きません。

以上、IE8環境でのテストですので他のバージョンのIEでは異なる動作となるかも知れませんが、jQueryが動けばWSHでのちょっとしたツールの作成もとても簡単で楽しいものになります!

追記:激しくガイシュツというのを umq さん、ZIGOROu さんに教えてもらった(´・ω・`)ショボーン

*1:":"を含む要素名のセレクタの書き方は、Wassrでmonmonさんに教えてもらいました。ありがとうございます。

*2:typeof(alert) == "object"になっている

yohgakiyohgaki 2009/09/29 09:28 個人的には新しいので問題ないです。このエントリを見なければこんな事ができるとは知りもしなかったかも知れません。

車輪の再発明?車輪は再発明して改善/普及するのです :)
セキュリティ問題って問題と対策の再発明の連続ですよね :)

トラックバック - http://d.hatena.ne.jp/hasegawayosuke/20090928/p1