for文

JSTL Xタグと、XSLT変換の比較2回目は、sort処理です。
題材は、前回の for文 で HTML の table を作りましたが、それを 昇順にソートして表示する改造とします。

結論

圧倒的に XSLT変換が簡単
この後、両者のソースを比較しますが、JSTL Xタグは、何とか達成したという感じで、非常に複雑です。

ソースのダウンロード

JSP-XML-2007-09-26.zipをダウンロードしてください。
いつものように、Maven2 でビルドして、Tomcatにデプロイして、http://localhost:8080/JSP-XML/を開きます。
トップページのドロップダウンリストに追加されている「sort文比較」を選んで、「JSTL Xタグで変換」または
「XSLT で変換」のボタンを押してください。

結果は、JSTL Xタグでも、XSLTでも、下図のように表示されます。
ソートする値は、「パック価格」を「個数」で割った値、つまり、「1個あたり価格」を使います。
XMLのデータ構造で言えば、各 /fruits/item の price/unit の値がソートする値ということです。

JSTL:Xタグのポイント

ポイントになるソースは、当然ながら/jsp/jstl/sort.jspです。
以下に、sort.jspの全文を掲載します。

  1. 前処理
  2. 最初に、TreeMapの sortMapという変数を準備します。この中には、x:forEachの中で、
    sortMap に各/fruits/item の ( 1個単価, 出現位置 ) を格納していきます。

    「1個単価」 → number($data/price div $data/unit)
    「出現位置」 → "${count + 1}"

    x:set や c:set で格納した変数は、<% と %> で囲まれる スクリプトレット内で、
    pageContext.getAttribute() で取得、pageCntext.setAttribute()で設定できるところがミソです。

  3. テーブルの行作成
  4. 次に、各テーブルの <tr> 行を生成する箇所です。for文は、実は x:forEach ではなく、
    c:forEach を使って、sortMap の各 Map.Entry オブジェクトでループを回しています。

    <c:forEach var="entry" items="${sortMap}"> では、sortMap.entrySet().iterator() と同等で、
    entry という変数に、sortMap 内の 1組の( 1個単価, 出現位置 ) を格納して、個数分だけループします。

    ${entry.value} では、entryが指す( 1個単価, 出現位置 ) の「出現位置」が取得できます。
    ( ${entry.key} と書けば、「1個単価」を取得できます。)

    最終的に、<x:set var="data" select="$domXML/fruits/item[ $position ]"/>と記述することで
    data という変数に、${entry.value} が指していた「出現位置」に相当する /fruits/item が格納されます。

  5. ソートのカラクリ
  6. sortMapという変数は、TreeMap クラスでしたので、c:forEach で entry変数を取り出すときに、
    「1個単価」でソートした順番で取り出せているので、その「出現位置」をピンポイントで指定すれば
    ソート順番で XML を取り出すことができるわけです。

    注意点として、「1個単価」を登録する際に、number($data/price div $data/unit)" と数値型にしている点です。
    もし、number() 関数でくくっていない場合は、文字列比較となり、意図せぬ順番でソートされてしまいます。

XSLのポイント

次に、XSLTでの記述です。ポイントになるソースは、/jsp/xslt/xsl/sort.xslです。
前回の for文の for.xsl を理解しているという前提のもとに、ポイントのみを示します。

キーポイントは、<xsl:sort select="price div unit" data-type="number"/>の1行だけです。
このおまじないを入れると、ループする際に、select="/fruits/item" で、
ソート指定した順番にループが回ります。

data-type="number" を省略すると、数値型としてソート比較を行います。
デフォルトでは文字列比較になってしまうので、注意してください。

  1. 応用知識 : ソート順
  2. デフォルトでは、昇順でソートしますが、以下のように書けば降順になります。
    <xsl:sort select="price div unit" data-type="number" order="descending"/>

  3. 応用知識 : 多段ソート
  4. <xsl:sort/> タグは、複数並べて記述すると、複数のソートキー指定ができます。
    下のように 2つ並べて記述した例で説明します。

    <xsl:sort select="price div unit" data-type="number"/>
    <xsl:sort select="name"/>
    この指定は、基本( 第1優先度 )は、「1個あたり単価」で昇順ソートするが、もしも「1個あたり単価」が
    同一のものが複数あった場合は、それらの順番は「name」で昇順ソートする、という意味になります。

まとめ

sort処理は、XSLTで行うと、たった1行で書けるのに、JSTL Xタグでは、「何でこんなに面倒なの?」
と言いたくなるような記述になってしまいます。

来週は、JSTL のこの面倒さを、逆に利点にして、XSLT変換ではかなり無理がある 集計処理 で
機能比較をやってみようと思います。