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


フィールド名の自動配置(XSLの汎用化)

項目名も自動配置

 検索結果のXMLで、COL要素(フィールド)の順番は、該当するレイアウト上のフィールドの位置で決まります。試しにファイルメーカーProのレイアウト上でフィールドの位置関係を変えて、検索してみましょう。XML中のCOL要素の順番が変化します。元のデータベースファイルのレイアウト次第で、結果の表を変えることができるのは便利です。ところが困った問題も生じます。検索結果の表の1行目(タイトル行)と2行目以下の項目の関係が崩れてしまいます。タイトル行を固定で書いているからです。フィールド名は、XMLのMETADATA要素の下のFIELD要素のNAME属性に入っています。これを使って1行目を作るようにすれば、レイアウトの変化に応じて、結果のタイトル行もデータ行も変化してくれます。ファイルメーカーでフィールド名を変えれば、ブラウザ上に表示される項目名も変化します。どうでしょう、一気に汎用性が高まります。極論をいえば、どんなデータベースにも、これ1ファイルで対応できるのです。

 では、METADATA要素を使って項目行を作るようにXSLを改造しましょう。

項目行も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){
	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 gonextp(spos) {
	var key = document.XSLDocument.selectSingleNode("*/xsl:template[@match='ROW']/xsl:if/@expr");
	key.value = "getpos(" + spos + ")";
	var d = document.XMLDocument.selectSingleNode("FMPXMLRESULT/RESULTSET");
	content.innerHTML = d.transformNode(document.XSLDocument);
	var s = document.XMLDocument.selectSingleNode("FMPXMLRESULT/RESULTSET/@FOUND").value;
	spos = spos + 5;
	nextp.href = "javascript:gonextp(" + spos + ")";
	if(spos >= s){nextp.style.display = "none";}
	spos = spos - 10;
	prevp.href = "javascript:goprevp(" + spos + ")";
	prevp.style.display = "inline";
}

function goprevp(spos) {
	var key = document.XSLDocument.selectSingleNode("*/xsl:template[@match='ROW']/xsl:if/@expr");
	key.value = "getpos(" + spos + ")";
	var d = document.XMLDocument.selectSingleNode("FMPXMLRESULT/RESULTSET");
	content.innerHTML = d.transformNode(document.XSLDocument);
	spos = spos + 10;
	nextp.href = "javascript:gonextp(" + spos + ")";
	nextp.style.display = "inline";
	spos = spos - 15;
	prevp.href = "javascript:goprevp(" + spos + ")";
	if(spos <= 0){prevp.style.display = "none";}
}

function sort(sortfld) {
	sortfld = sortfld - 1;
	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);
}

]]></xsl:comment>
			</script>

			</head>
			<body>
				<span id="content"><xsl:apply-templates select="RESULTSET" /></span>
				<table border="1">
					<tr>
						<td width="100"><a id="prevp" href="javascript:goprevp(-4)">prevPage</a></td>
						<td width="100"><a id="nextp" href="javascript:gonextp(6)">nextPage</a></td>
					</tr>
				</table>
			</body>
		</html>
	</xsl:template>

	<xsl:template match="RESULTSET">
		<table border="1">
			<xsl:apply-templates select="../METADATA" />
			<xsl:apply-templates select="ROW" order-by="COL[0]/DATA" />
		</table>
	</xsl:template>

	<xsl:template match="METADATA">
		<tr><xsl:apply-templates select="FIELD" /></tr>
	</xsl:template>

	<xsl:template match="FIELD">
		<th><a><xsl:attribute name="href">javascript:sort(<xsl:eval>formatIndex(childNumber(this),"1")</xsl:eval>)</xsl:attribute><xsl:value-of select="@NAME" /></a></th>
	</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>

 1行目を生成していた部分(RESULTSET要素を処理しているテンプレートアクション内)に、METADATA要素を処理するテンプレート<xsl:apply-templates select="../METADATA" />を置きます。

 <xsl:template match="METADATA">で、METADATA要素の変換処理を行います。これは行を生成するためにtr要素を置いて、その中にFIELD要素へのテンプレートを配置します。FIELD要素から各項目を生成します。その各項目を生成する<xsl:template match="FIELD">は、少々複雑です。取り出して見やすいように改行を入れてみます

フィールド名を生成する部分

<th>
	<a>
		<xsl:attribute name="href">
			javascript:sort(<xsl:eval>formatIndex(childNumber(this),"1")</xsl:eval>)
		</xsl:attribute>
		<xsl:value-of select="@NAME" />
	</a>
</th>

 作りたいのは「<th><a href="javascript:sort(0)">フィールド名</th>」で、0やフィールド名の部分が項目ごとに適切になるようにしておきたいわけです。

 xsl:attribute要素は、直前の要素(この場合は、a要素)に対して、name属性で指定した属性(この場合は、href属性)に希望の値を埋め込むXSL要素です。
xsl:attribute要素の構文
<xsl:attribute name="属性名">属性値</xsl:attribute>
href属性に埋め込まれるのはjavascript:sort(<xsl:eval>formatIndex(childNumber(this),"1")</xsl:eval>)です。<xsl:eval>formatIndex(childNumber(this),"1")</xsl:eval>


関連ページ XSL Methods(formatIndex(childNumber(this), "I"))