スクリプトによる
インタラクション

インタラクティブなスタイルの変更

XSLTでは、条件を設定してデータの抽出をしたり、 並び替えをしたりすることができます。 そこで、1つのXML文書に対して、 条件を替えてデータ抽出などを行いたいという要求が当然出てきます。 そこで、とりあえずの解決方法は次のようになります。

  1. XSLTのファイルを変更したい条件の数だけ用意し、それぞれ異なる条件を指定する。
  2. 元のXML文書を条件の数だけ複製し、それぞれスタイルシートの指定(xml-stylesheet)だけ変更する。
  3. それぞれのXML文書にリンクを張っておけばOk。

たしかにこうすれば切り替えることができますが、 似たようなファイルをいくつも用意しなくてはならないところがいかにも無駄です。 スタイルシートを動的に指定したり、条件を動的に指定したりできないのでしょうか。

実は、サーバ側でXSLTプロセッサを動かすときには、 これらの問題は容易に解決することができます。 ただ、今回はクライアント側のWebブラウザで処理を行うため、 クライアント側でちょっと特殊な処理をする必要があります。

スクリプトによるスタイルの変更手法

これまでのやり方では、 XML文書の中でXSLTのスタイルシートを明示的に指定していました(xml-stylesheet)。 これではスタイルシートを動的に切り替えることができません。 また、XSLTスタイルシートにパラメータを与え、 動作を変化させることもできません。

そこで、XML文書の中では適用するスタイルシートの指定をせず、 適用するスタイルシートを外部から(といってもクライアント側で) 動的に変更することを考えます。 ここで、クライアント側で何らかのスクリプトを動かすことが必要になります。

JavaScriptによるXSLTプロセッサの呼び出しと利用

ブラウザで動くスクリプトの定番は JavaScript ですが、 JavaScript にはXMLを扱う機能がありません。 そこで、JavaScript から XML を扱うプログラム(ライブラリ)を呼び出すことを考えます。

Mozilla の場合には、TransforMiix という XSLTプロセッサが組み込まれています。 また Internet Explorer の場合には、MSXML というライブラリを呼び出す方法があります。 クライアントのブラウザによって呼び出すライブラリを切り替えることで、 Mozilla と Internet Explorer の両方に対応したページとします。

JavaScriptって?

JavaScriptはWebブラウザ上での実行が可能なスクリプト言語です。 スクリプト言語はプログラミング言語の一種ですが、 スクリプト言語で書かれたプログラム(スクリプト)はコンパイル不要で直接実行されます。 スクリプト言語としては、シェルスクリプトのほか、CGIプログラミングでよく使われるPerlやRubyが有名です。

JavaScriptの場合、HTML文書の中にソースを直接書くことができます。 HTMLの文書自体を処理対象にできるため、 ダイナミックなページの作成に広く利用されています。 JavaScriptを使って実現されているものとしては…

なお、JavaScriptはオブジェクト指向的なプログラミングもできますが、 Javaとの関連性はほとんどありません。

JavaScriptの記述方法

HTML文書内では、script要素の内容として記述します。 属性type="text/javascript"を指定することにより、 スクリプト言語としてJavaScriptを使っていることを明示します (language属性を使うのは旧式です)。 なお、src属性を使って外部ファイルを指定することもできます。

<script type="text/javascript">
  document.write("す");
  for(i = 0; i < 8; i++)
    document.write("も");
  document.writeln("のうち");
</script>

実行例:

script要素ではなく、onClick、onMouseOver などといった属性の値として書くこともあります。

<a href="http://www.w3.org/"
   onMouseOver="window.alert('JavaScriptが動いてますよ!'); return true;">
W3Cへのリンク(JavaScriptは動いているかな?)</a>

実行例: W3Cへのリンク(JavaScriptは動いているかな?)

上記のように属性としてスクリプトを書く場合、 type(text/javascript)の指定ができません。 そこで、このような使い方をする場合にはHTML文書全体のデフォルトのスクリプト言語をhead要素内のmeta要素で指定しておきます。

<head>
  ...
  <meta http-equiv="Content-Script-Type" content="text/javascript">
... </head>

JavaScriptの言語仕様

JavaScriptからのXSLTプロセッサの利用

XSLTプロセッサを呼び出すJavaScriptの記述されたページを用意し、 そこから.xmlファイルや.xslファイルを読み込みます。

スタイルシートにパラメータを与え、そのスタイルシートで変換を行う JavaScriptのスクリプトの例を以下に示します。

この例では、まずload関数で artists.xml と artists.xsl を読み込みます。 ボタンを押すと呼び出されるtransform関数で、 countryNameというパラメータをスタイルシートに渡し、 そのスタイルシートで変換を行って結果を表示させます。

<script type="text/javascript">
var xml, xslt, xslProc;
function load() {
    // 読み込む前に空のドキュメントを生成
    if(!document.all) { // ブラウザ判別
        // Mozilla
        xml = document.implementation.createDocument("", "", null);
        xslt = document.implementation.createDocument("", "", null);
    }
    else {
        // Internet Explorer
        xml = new ActiveXObject("Msxml2.DOMDocument");
        xml.async = false;
        xslt = new ActiveXObject("Msxml2.FreeThreadedDOMDocument");
        xslt.async = false;
    }

    // 読み込み(*.xml,*.xsl)
    xml.load("artists.xml");
    xslt.load("artists.xsl");
    
    // XSLTプロセッサにスタイルシート(*.xsl)をセット
    if(!document.all) { // ブラウザ判別
        // Mozilla
        xslProc = new XSLTProcessor();
        xslProc.importStylesheet(xslt);
    }
    else {
        // Internet Explorer
        var xslTemp = new ActiveXObject("Msxml2.XSLTemplate");
        xslTemp.stylesheet = xslt;
        xslProc = xslTemp.createProcessor();
        xslProc.input = xml;
    }
}
function transform(country) {
    // XSLTプロセッサにパラメータを与えて変換、結果はresult要素に
    if(!document.all) { // ブラウザ判別
        // Mozilla
        xslProc.setParameter(null, "countryName", country);
        var fragment = xslProc.transformToFragment(xml, document);
        document.getElementById('result').innerHTML = "";
        document.getElementById('result').appendChild(fragment);
    }
    else {
        // Internet Explorer
        xslProc.addParameter("countryName", country);
        try { 
            xslProc.transform;
            document.getElementById('result').innerHTML = xslProc.output;
        }
        catch(e)
        {
            document.getElementById('result').innerHTML = e.description;
        }
    }
}
</script>

document.all は Internet Explorer の独自拡張なため、 これが存在するか否か(真か偽か)でブラウザの判別をしています。

このscript要素をhead要素の中に記述しておき、 body要素を次のようにしておくと、ページが表示されるときにまずload()が実行されます。

<body onLoad="load()">

ボタンと変換結果の表示場所は以下のように作ります。

<form>
  <input type="button" value="UKを表示" onClick="transform('UK')" />
  <input type="button" value="USを表示" onClick="transform('US')" />
</form>

<div id="result">ここに変換結果が表示されます。</div>

元となるXML文書にはスタイルシートの指定(xml-stylesheet)がありません。 これはあとからJavaScript側で指定するからです。 なお、xml-stylesheetがあった場合には無視されます。

XLST スタイルシートのポイントは、パラメータの受け渡し部分です。 xsl:param 要素を使いますが、ここで、 JavaScriptで指定したものと同じ名前にします。 値を参照するときには、名前の前に$をつけます。

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <!-- 外部から設定するパラメータ -->
  <xsl:param name="countryName"/>
<!-- 文書全体にマッチする最初のテンプレート --> <xsl:template match="/"> <h1> <xsl:value-of select="$countryName"/> Bands and Artists </h1> <xsl:apply-templates select="artists/artist[country=$countryName]"/> </xsl:template> <!-- artist 要素ごとにh2要素で名前を表示 --> <xsl:template match="artist"> <h2> <xsl:value-of select="name"/> <!-- 子要素nameの内容を取得 --> </h2> </xsl:template> </xsl:stylesheet>

パラメータを複数用意したい場合には、xsl:param 要素を複数記述します。 呼び出すJavaScript側では、setParameter を複数回行います。

    xslProc.setParameter(null, "パラメータ名1 ", 値1 );
    xslProc.setParameter(null, "パラメータ名2 ", 値2 );
    ...

Internet Explorer の場合には addParameter になります。

    xslProc.addParameter("パラメータ名1 ", 値1 );
    xslProc.addParameter("パラメータ名2 ", 値2 );
    ...

変換結果はdiv要素に現れます。div要素に result という id がついていますが、 これをJavaScript側で参照し、内容を入れ替えています。 例えば Internet Explorer の場合には、以下のようにします。

        document.getElementById('result').innerHTML = xslProc.output;

ここで、resultというidの要素の中身(innerHTML)を、 丸ごとXSLTによる変換の出力(xslProc.output)に置き換えています。

なお、この例ではボタンを一度押さないと変換が行われませんが、 ページの読み込み時に一度変換を行いたい場合には、 load関数の最後でtransform関数を呼ぶようにします。

function load() {
    
    ...
    
    transform('UK');
}

スタイルシートの切り替え

スタイルシートへのパラメータを切り替えるのではなく、 スタイルシート自体を切り替えるには、次のようにします。

なお、表示箇所を2箇所にするには2つのdiv要素などを用意することになりますが、 その際、同じ id を使用することはできません。 例えば、id="result1" と id="result2" といった、 異なる id のdiv要素などを用意することになります。 当然、変換結果をinnerHTMLで指定する部分も変更が必要です。

RSS への適用

RSS に適用するには、RSS の規格に定められている名前空間の指定をする必要があります。 また、RSS とそれを JavaScript で読み込む HTMLファイルは同一ドメインに存在する必要があります。