ファイルメーカーProのページへ戻る


JavaScriptで、並べ替えを動的に変化させる(1)

order-byでソート

 FMPXMLRESULT文法のXMLデータを、XSLでHTMLへ変換することができました。ここではXMLデータをソートする方法を考えます。XSLでソートさせる方法は、以前やったとおりorder-by属性を使えばできます(これも繰返しになりますが、W3Cが推奨しているのはxsl:sortの使用です)。先ほど作ったXSLにソート方法を加えましょう。20行目を次のように書き換えます。

XSLでソート方法を指定する
<xsl:apply-templates select="ROW" order-by="+COL[0]/DATA" />

 ROW要素にテンプレートを適用する際に、1番目のCOL要素(このデータベースの場合はname要素)のDATA要素の値に従って昇順で処理をすることになります。COL要素の1番目は「0」ですので、注意してください。

 これだけだと、おもしろくないですね。ソート方法を自在に変えられるようにしましょう。XMLによるWeb配信では、ファイルメーカーは単なるデータの羅列としてXMLを送出しているだけです。ソートや抽出、配置方法などのレイアウト規則はXSLの記述に基づいています。ピンときた方もいるでしょう。XSLが書き変われば、レイアウトも変化します。画面上のボタンをクリックすると、受信済みのXSLが書き変わるようにすれば、サーバー側に何のリクエストも発生しないまま、自在にレイアウトを変化させることができるのです。

 そこで、JavaScriptの出番です。JavaScriptはネットスケープ社が自社ブラウザの機能を拡張させるために考案したプログラム言語です(ちなみに、JavaとJavaScriptは違うプログラム言語です)。HTMLにJavaScriptを書き込んでおくと、絵が動いたり、音が鳴ったり、応用次第でゲームが作れたりします。JavaScriptは受信済みのHTML自身を書き変えることすらできます。例えば、<font color="red">〜</font>で赤字で表示している部分を、JavaScriptを実行して<font color="green">〜</font>と書き換えることで緑字に変えるなど。JavaScriptは、ホームページに幅広い表現方法を提供してくれるプログラム言語として人気が高まり、ライバルのマイクロソフト社も自社ブラウザにJavaScriptとほぼ同じプログラム言語「JScript」を搭載するようになりました。JScriptは、JavaScriptとほとんど同じなので、一般には両方ともJavaScriptと呼ばれています。しかし、まったく一緒というわけではないので、高度なプログラムを組もうとするとすると両者の差異に悩まされることもありますが、まあその辺は専門書にまかせるとしましょう。

 では、JavaScriptの力を借りて、<xsl:apply-templates select="ROW" order-by="+COL[0]/DATA" />のorder-by属性値を自由に書き変えられるようにしましょう。

JavaScriptでorder-by属性の値を自在にコントロール

 さて、肝心のorder-by属性値を書き変えるスクリプトは以下の通りです。

order-by属性値を書き替えるJavaScript
function sort(sortfld) {
 var key = document.XSLDocument.selectSingleNode("*/xsl:template[@match='RESULTSET']/xsl:apply-templates[@select='ROW']/@order-by");
 key.value = "+COL[" + sortfld + "]/DATA"
 var d = document.XMLDocument.selectSingleNode("FMPXMLRESULT/RESULTSET");
 content.innerHTML = d.transformNode(document.XSLDocument);
}
1行目:
 関数の開始。ここでは、「sort( )」という名前の関数を作った。「function 関数名(引数){命令}」という構文で関数が定義できる。
2行目:
 document.XSLDocument.selectSingleNodeは、「文書中の.XSL中の.とある1つの要素」という意味。「とある1つの要素」が具体的に何であるかは( )中のパターンマッチングで指定します。パターンマッチングは、URLの考え方と似ていて、親要素から子要素へ下っていって、目的の部分を絞り込んでいく方法です。まず先頭の「*」は「どこからスタートしてもいい」という意味。『どっからでもいい→その子要素で[match属性値がRESULTSETである]xsl:template要素→その子要素で[select属性がROWである]xsl:apply-templates要素→そのorder-by属性』。このパターンに該当する部分、すなわちorder-by="+COL[0]/DATA"が取り出されて、keyに代入される。
3行目:
 order-by属性値を書き変える部分。key.valueは、keyの値(今は+COL[0]/DATA)。これに右辺でつくられる値を代入する。右辺は、関数を実行するときに一緒に受け取るsortfldという値を使って、+COL[sortfld]/DATAを作っている。sortfldにどんな数字を入れて関数を実行するかによって、+COL[1]/DATAになったり+COL[3]/DATAになったりして、ソート対象のフィールドを変えることができるわけです。
4〜5行目:
 order-by属性値を書き換えた結果を、画面に反映するために、XMLデータのRESULTSET要素以下の部分を取り出して、XSL変換を適用し直します。変換し直した結果は、id="content"で指定された範囲に埋め込まれます。

 ところで、4行目の命令は、XMLデータの一部(RESULTSET要素以下)だけを取り出しています。XMLデータ全体を再度XSL変換すると、<head>などを含んだHTML全体が作られてしまいます。今は、検索結果の表の部分を書き変えたいだけなので、RESULTSET要素以下を対象にXSL変換します。こうすることで、検索結果の部分のHTMLだけが生成されます。

 スクリプトの最後の行content.innerHTML = d.transformNode(document.XSLDocument);が、「content」というidが付けられた範囲にXSL変換結果を埋め込む命令です。そこで、XSLの検索結果の表を構成する部分<xsl:apply-templates select="RESULTSET" /><span id="content">〜</span>で挟んでおきます。これで、スクリプトを実行すると、表が書き変わります。

 さてスクリプトは完成しました。最後に、スクリプトを呼び出すための仕掛けを用意しましょう。ここでは、検索結果の項目タイトル部分をクリックすると、指定したJavaScriptが呼び出される仕掛けを組み込みます。先のresult.xslのタイトル行を作っている部分(17行目<tr>〜</tr>)を以下のように書き換えます。

sort()関数を呼び出せるように<tr>〜</tr>を書き換える
<tr>
	<th><a href="javascript:sort(0)">name</a></th>
	<th><a href="javascript:sort(1)">os</a></th>
	<th><a href="javascript:sort(2)">price</a></th>
	<th><a href="javascript:sort(3)">color</a></th>
</tr>

 表の項目タイトル部分がリンクになっていて、リンク部分をクリックするとsort( )関数が呼び出される仕掛けです。それぞれのリンクは、sort( )関数を呼び出す際に、ソート対象を特定するための数字を1つ渡すようになっています。例えば、nameをクリックすると、sort( )関数に「0」を渡します。その結果、order-by属性が+COL[0]/DATAに書き換わって、検索結果がname昇順にソートされます。osをクリックすれば、sort( )関数に「1」が渡されて、その結果order-by属性値は+COL[1]/DATAに書き換わって、検索結果はos昇順にソートされます。

動的ソート機能を追加したXSLファイル「result.xsl」
<?xml version="1.0" encoding="Shift_JIS"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl" xmlns:fm="http://www.filemaker.com/fmpdsoresult" xml:lang="ja">
	<xsl:template><xsl:apply-templates /></xsl:template>
	<xsl:template match="text()"><xsl:value-of select="."/></xsl:template>

	<xsl:template match="FMPXMLRESULT">
		<html>
			<head><title>検索結果</title>
<script language="javascript"><xsl:comment><![CDATA[
function sort(sortfld) {
	var key = document.XSLDocument.selectSingleNode("*/xsl:template[@match='RESULTSET']/xsl:apply-templates/@order-by");
	key.value = "+COL[" + sortfld + "]/DATA";
	var d = document.XMLDocument.selectSingleNode("FMPXMLRESULT/RESULTSET");
	content.innerHTML = d.transformNode(document.XSLDocument);
}
]]></xsl:comment></script>
</head>
			<body>
				<span id="content">
					<xsl:apply-templates select="RESULTSET" />
				</span>
			</body>
		</html>
	</xsl:template>

	<xsl:template match="RESULTSET">
		<table border="1">
			<tr>
				<th><a href="javascript:sort(0)">name</a></th>
				<th><a href="javascript:sort(1)">os</a></th>
				<th><a href="javascript:sort(2)">price</a></th>
				<th><a href="javascript:sort(3)">color</a></th>
			</tr>
			<xsl:apply-templates select="ROW" order-by="COL[0]/DATA" />
		</table>
	</xsl:template>

	<xsl:template match="ROW">
		<tr>
			<xsl:apply-templates select="COL" />
		</tr>
	</xsl:template>

	<xsl:template match="COL">
			<td><xsl:value-of select="DATA" /></td>
	</xsl:template>
	
</xsl:stylesheet>

 サーバーから送出した時点では、「order-by="+COL[0]/DATA"」なので、nameをソート対象として表示されます。表の1行目がタイトル行になっていて、JavaScriptを実行するリンクになってます。例えば、「os」をクリックすると、sort( )関数が呼び出されます。このとき関数には同時に「1」という数字が渡されます。sort( )関数は、XSL内のorder-by属性を見つけ出し、受け取った数字「1」を使ってorder-by属性を「order-by="+COL[1]/DATA"」と書き換えます。書き換えた内容を有効にするために、レイアウトの再描画を実行させます。これで、サーバーへ再度リクエストすることなくソート対象を自由自在に変更することができます。>>