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


JavaScriptで、表示範囲を動的に変化させる(ホップ)

ROW[index()$ge$0 and index()$le$4]は使えない

 以前、ROW[index()$ge$0 and index()$le$4]という評価式をROW要素の処理時に適用して、特定の範囲のレコードだけを表示することを実現しました。「ああ、この評価式の0とか4をJavaScriptで書き替えられるようにしておけば、OKか?」と考えて、まずはXSLを以下のように書き換えましたが、結果は失敗でした。

初めに考えた方法(これはうまくいかない)
<xsl:apply-templates select="ROW[index()$ge$0 and index()$le$4]" order-by="COL[3]/DATA"/>

 この場合、評価式に合致したROW要素に対してorder-by属性が適用されてしまいます。つまりXMLデータの1〜5番目までが抽出されたあとで、ソートされます。ソートと抽出の順序が逆になってしまいました。

 そこで、テンプレートの指定は、order-byでROW要素の処理順番を指定するだけにします。そして、<xsl:template match="ROW">〜</xsl:template>の中のテンプレートアクションに、抽出作業を入れ込むことにします。つまり、全てのROW要素をorder-by属性通りの順番で処理しつつ、実際に処理されるときに「今何番目の処理なのか」を計算して、その行を表示するかしないかを決めるのです。

 Windows版のInternetExplorerはXSLの実装が進んでいて、position()という便利な関数があるらしいのですが、Mac版のIEにはまだなさそうです。仕方ないので、XSLとは違う方法で「今何番目の処理をしているのか」を計算しなければなりません。ここでもJavaScriptのお世話になることにします。

今、何番目を処理しているかを数えるJavaScript
pos = 0;
function getpos(){
	pos = pos + 1;
}

 まず事前にpos = 0;で、posという変数に0を代入しておきます。これは関数の外に書いてあるので、ファイルが読み込まれた時点で実行されます。関数にはgetpos( )という名前を付けました。getpos( )関数が呼び出されると、posに1が加算されます。ROW要素を処理するたびに、このスクリプトを呼び出せば、posの値が「今何番目の処理をしているか」になるわけです。

 ただ数えるだけでは使いものになりません。何番目なのかによって処理を分ける(表示するのかしないのか)必要があります。そこで上のスクリプトにさらに手を加えます。

今、何番目を処理しているかを数えて、処理を分けるJavaScript
pos = 0;
function getpos(spos){
                  var epos = spos + 4;
                  pos = pos + 1;
                  if(pos >= spos && pos <= epos){
                        return true;
                      }else{
                        return false;
                      }
                 }

 「もし(posの値がspos以上かつepos以下){ならばtrueを返す}違うなら{falseを返す};」という命令を挿入しました。この関数が呼び出されるたびにposの値が1ずつ増えて、posがspos〜eposならtureを返すし、それ以外ならfalseを返します。ここで、sposとは関数を実行する時に一緒に送られてくる数値で、eposはsposに4を足した数です。

<xsl:if expr="getpos(1)" language="javascript">でスクリプトを呼び出して、結果を評価する

 あとは、ROW要素を処理するたびにgetpos( )関数を呼び出して、trueが返ってきたらその行を表示する、falseなら表示しない、とすればいいのです。では、この関数を呼び出す部分を作ります。XSLの<xsl:template match="ROW">〜</xsl:template>が、ROW要素を処理しているテンプレートです。ROW要素ごとに、このテンプレートが繰返し適用されて(適用の順番は、apply-templatesのorder-by属性によって決まっている)、結果として複数行のテーブルができあがるわけです。ここで、適用のたびに関数を呼び出して、その返り値によって実際にその行を処理するかどうかを決めればいいわけです。

スクリプトを呼び出して、その結果を評価する
<xsl:template match="ROW">
	<xsl:if expr="getpos(1)">
		<tr><xsl:apply-templates select="COL" /></tr>
	</xsl:if>
</xsl:template>

 ポイントは<xsl:if expr="getpos(1)">です。このXSL要素は「getpos( )関数を呼び出して、その結果がtrueなら</xsl:if>までの部分を実行する」という意味です。ROW要素を処理するたびに、getpos( )関数が呼び出されて、posの値がカウントアップしていきます。getpos( )関数は、実行時に「1」を一緒に受け取っているので、posの値が1〜5ならtureを返します。xsl:if要素は、getpos( )関数からtrueが返ってきたときだけ、<tr>〜</tr>の処理を実行して、行を作ります。結果として、order-by属性でソートして、その1〜5番目までの結果が表示されることになります。

 とりあえずここまでのXSLをまとめてみましょう。

動的ソート+1〜5番目を表示する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:script language="javascript">
<![CDATA[
pos = 0;
function getpos(spos){
	var epos = spos + 4;
	pos = pos + 1;
	if(pos >= spos && pos <= epos){
			return true;
		}else{
			return false;
		}
	}
]]>
	</xsl:script>
	<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">
		<xsl:if expr="getpos(1)">
		<tr>
			<xsl:apply-templates select="COL" />
		</tr>
		</xsl:if>
	</xsl:template>

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

 getpos( )関数を書いている場所に注意が必要です。動的ソートのために作ったJavaScriptとは別の場所です。これは2つのJavaScriptの役割の違いからきます。動的ソートに使うJavaScriptは、「完成したHTML内で動作する」スクリプトなので、普通にHTMLでJavaScriptを書くのと同じ場所に同じ方法で書きます。それに対して、ROW要素の1〜5番目を抽出するために使うJavaScriptは、「XSL処理時に動作する」スクリプトなので、XSLが利用する場所に書きます。XSL用のスクリプトを記述するのが、xsl:script要素です。 <xsl:script>〜</xsl:script>の間にXSLで利用するスクリプトを記述します。>>