選択肢毎のエントリ件数を表示したりする方法を説明します。
この方法はXSLTのかなり高度な使用方法になっており、職業プログラマでないと
理解は難しいかもしれません。
なるべくデザイナーでもサンプルをコピーして使えるよう、説明したつもりですが、
この内容はTIPSというよりHackのレベルですので、よく分からなくて普通だと思います。
また、CMS Designerにも精通している必要があります。
そもそもデザイナーさんにプログラマの真似事をして頂く事を想定してはおりませんので、
よく分からない場合は申し訳有りませんがこのサンプルの利用を断念して下さい。m(__)m
今後、もっと簡単な方法で実現できる機能をCMSDに追加することを検討致します。
-----------------------------------------------------------------------
スキーマでメニュー(menu)項目を使った場合に面倒なのが、デザイン定義での
<xsl:if>による振り分けです。
例えば
コード: 全て選択
<data name="shopkind" type="menu" caption="お店種別" >
<menuitem id="1">中華</menuitem>
<menuitem id="2">ラーメン</menuitem>
<menuitem id="3">和食</menuitem>
<menuitem id="4">洋食</menuitem>
<menuitem id="5">スイーツ</menuitem>
</data>
コード: 全て選択
<xsl:value-of select="shopkind" />
コード: 全て選択
4
これは、エントリデータ上では選択肢の表示情報ではなく、idのみしか格納
されていない為です。
なぜこのような仕様になっているかというと、「中華」や「洋食」という情報は
見た目の情報、つまりデザインであって、コンテンツではないという考え方からです。
このようにコンテンツとデザインが分離されている為、メニュー項目の選択値に
対して「和食」ではなく「japanese food」のように英語で表示したり、文字ではなく
画像を表示したり、または何かを表示する/しないを切り替えたり、など様々な
処理を行う事が可能になっています。
しかし、このような仕様になっている為、普通に「中華」「ラーメン」のように
表示したい場合、次のようなデザイン定義を行う必要があり、面倒です。
コード: 全て選択
<xsl:if test="shopkind='1'">中華</xsl:if>
<xsl:if test="shopkind='2'">ラーメン</xsl:if>
<xsl:if test="shopkind='3'">和食</xsl:if>
<xsl:if test="shopkind='4'">洋食</xsl:if>
<xsl:if test="shopkind='5'">スイーツ</xsl:if>
一緒に追加する必要があります。これは非常に面倒ですし、例えば次のような
「都道府県」のメニュー項目だった場合は、デザイン定義自体が長大なものに
なってしまいます。
コード: 全て選択
<data name="pref" type="menu" caption="都道府県" group="True">
<menuitem id="01">北海道</menuitem>
<menuitem id="02">青森県</menuitem>
<menuitem id="03">岩手県</menuitem>
<menuitem id="04">宮城県</menuitem>
<menuitem id="05">秋田県</menuitem>
<menuitem id="06">山形県</menuitem>
<menuitem id="07">福島県</menuitem>
<menuitem id="08">茨城県</menuitem>
<menuitem id="09">栃木県</menuitem>
<menuitem id="10">群馬県</menuitem>
<menuitem id="11">埼玉県</menuitem>
<menuitem id="12">千葉県</menuitem>
<menuitem id="13">東京都</menuitem>
<menuitem id="14">神奈川県</menuitem>
<menuitem id="15">新潟県</menuitem>
<menuitem id="16">富山県</menuitem>
<menuitem id="17">石川県</menuitem>
<menuitem id="18">福井県</menuitem>
<menuitem id="19">山梨県</menuitem>
<menuitem id="20">長野県</menuitem>
<menuitem id="21">岐阜県</menuitem>
<menuitem id="22">静岡県</menuitem>
<menuitem id="23">愛知県</menuitem>
<menuitem id="24">三重県</menuitem>
<menuitem id="25">滋賀県</menuitem>
<menuitem id="26">京都府</menuitem>
<menuitem id="27">大阪府</menuitem>
<menuitem id="28">兵庫県</menuitem>
<menuitem id="29">奈良県</menuitem>
<menuitem id="30">和歌山県</menuitem>
<menuitem id="31">鳥取県</menuitem>
<menuitem id="32">島根県</menuitem>
<menuitem id="33">岡山県</menuitem>
<menuitem id="34">広島県</menuitem>
<menuitem id="35">山口県</menuitem>
<menuitem id="36">徳島県</menuitem>
<menuitem id="37">香川県</menuitem>
<menuitem id="38">愛媛県</menuitem>
<menuitem id="39">高知県</menuitem>
<menuitem id="40">福岡県</menuitem>
<menuitem id="41">佐賀県</menuitem>
<menuitem id="42">長崎県</menuitem>
<menuitem id="43">熊本県</menuitem>
<menuitem id="44">大分県</menuitem>
<menuitem id="45">宮崎県</menuitem>
<menuitem id="46">鹿児島県</menuitem>
<menuitem id="47">沖縄県</menuitem>
<menuitem id="80">海外</menuitem>
</data>
デザイン定義側で再利用できないものでしょうか。
つまり、エントリデータに"01"と入っていたら、スキーマのmenuitemを読み込んで、
対応する"北海道"という文字列に変換して出力できないか、ということです。
実は、多少難解な方法なのですが、XSLTにはそれを実現する方法が用意
されています。
今から順を追ってそれを説明します。
最初に、最終的なデザイン定義の全体を示します。前提とするスキーマは
先ほどの都道府県のスキーマです。
スキーマファイル名を prefsample.schema.xml とします。
デザイン定義のファイル名は prefsample.list.default.xsl とします。
コード: 全て選択
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="EUC-JP" omit-xml-declaration="yes" />
<!-- スキーマファイルから都道府県リストを読み込み、$preflist という変数に格納する -->
<xsl:variable name="preflist" select="document('prefsample.schema.xml')/schema/data[@name='pref']/menuitem" />
<!-- エントリ一覧のテンプレート開始 -->
<xsl:template match="/entrylist">
<!-- エントリ一覧表示ループ -->
<xsl:for-each select="entry">
<!-- pref項目の値を変数$prefに格納 -->
<xsl:variable name="pref" select="pref/text()" />
<!-- 都道府県リストから、このエントリのprefに一致するtext()を取得して表示する。 -->
<xsl:value-of select="$preflist[@id=$pref]/text()" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
コード: 全て選択
<!-- スキーマファイルから都道府県リストを読み込み、$preflist という変数に格納する -->
<xsl:variable name="preflist" select="document('prefsample.schema.xml')/schema/data[@name='pref']/menuitem" />
読み込んでいます。
<xsl:variable>とは、独自のデータを定義するXSLTの命令で、例えば
コード: 全て選択
<xsl:variable name="myname" select="'○○○会社'" />
コード: 全て選択
<xsl:value-of select="$myname" />
という文字列を利用することができるようになります。
そしてこの都道府県のサンプルでは、select属性に「document」という命令が
記述されています。
これは、外部のXMLファイルからデータを読み込んでこい、という命令です。
コード: 全て選択
document('prefsample.schema.xml')
コード: 全て選択
document('prefsample.schema.xml')/schema/data[@name='pref']
いきます。
この例では、schema要素中のdata要素を選択し、そのdata要素のうちname属性が
'pref'のもの(つまり都道府県menu項目)のみに絞り込んでいます。
(要素名の後ろに[]をつけて条件式を書くと、その条件式に合致する要素のみ
を選択しろ、という命令になります)
今回欲しいのはメニュー項目の選択肢のみなので、スキーマのdata要素内の
menuitem要素だけをさらに選択します。
コード: 全て選択
document('prefsample.schema.xml')/schema/data[@name='pref']/menuitem
コード: 全て選択
<menuitem id="01">北海道</menuitem>
<menuitem id="02">青森県</menuitem>
<menuitem id="03">岩手県</menuitem>
<menuitem id="04">宮城県</menuitem>
:
<menuitem id="47">沖縄県</menuitem>
<menuitem id="80">海外</menuitem>
難しいと思ったら細部まで理解しなくて結構です。この行でだいたいどういう事を
行っているのかだけ、理解できればOKです。
ともかく、$preflistに対して、prefsample.schema.xmlのメニュー項目prefの選択肢
を読み込んだ、ということです。
この$preflistを利用するにはどのようにすれば良いでしょうか。
$preflistは現在、menuitem要素のリストになっているので、for-each命令を
使ってループさせることで、全ての選択肢を出力させることができます。
コード: 全て選択
<xsl:for-each select="$preflist">
<xsl:value-of select="text()" /><br />
</xsl:for-each>
コード: 全て選択
北海道
青森県
岩手県
宮城県
:
沖縄県
海外
話を元に戻します。
スキーマに記述された都道府県のリストを$preflistに格納するところまで説明しました。
元々の要望は、エントリデータに格納されたメニュー項目のidに対応する
選択肢を表示したい("01"なら"北海道"と表示したい)、というものです。
エントリデータに格納されたメニュー項目のidとは、ここでは pref の事です。
コード: 全て選択
<xsl:value-of select="pref" />
今からやりたいのは、$preflistのid属性の中から、prefの値に一致するmenuitem要素を
見つけてその内容(「宮城県」、や「千葉県」など)を取得する、ということです。
エントリ一覧表示ループの中を見ると、
コード: 全て選択
<!-- pref項目の値を変数$prefに格納 -->
<xsl:variable name="pref" select="pref/text()" />
<!-- 都道府県リストから、このエントリのprefに一致するtext()を取得して表示する。 -->
<xsl:value-of select="$preflist[@id=$pref]/text()" />
先に2つめの行を見ると、<xsl:value-of>を使って、$preflist[@id=$pref]/text()
を出力しています。
つまり、$preflistの選択肢の中で、id属性が$prefと一致するものを探し、
その内容を出力しているという意味になります。
上の行で$prefには現在のエントリのpref要素の内容をデータとして設定しています。
既に説明した通り、pref要素にはメニュー項目のidが格納されています。
つまり、$pref(pref)に一致するid属性を持った$preflist(menuitem)
の内容を出力せよ、という命令です。
これで、prefが"04"なら"宮城県"が出力されます。
非常にややこしいと思いますが、何度も繰り返し読んで理解してみて下さい。
よく分からなければ、コピーして使用してくださって結構です。
ちなみに、なぜわざわざprefを$prefにコピーしているかというと、
2つめの行の[]内ではprefが直接参照できないからです。
以上、スキーマのメニュー項目選択肢をデザイン定義で読み込んで使う方法の
ご紹介でした。
-----------------------------------------------------------------------------------
もう一つ、メニュー項目を「カテゴリ」と見なして、そのカテゴリに何件のエントリが
登録されているかを出力する方法をご紹介します。
上の方法の延長線になります。
コード: 全て選択
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xhtml" encoding="EUC-JP" omit-xml-declaration="yes" />
<!-- スキーマファイルから都道府県リストを読み込み、$preflist という変数に格納する -->
<xsl:variable name="preflist" select="document('prefsample.schema.xml')/schema/data[@name='pref']/menuitem" />
<!-- エントリ一覧のテンプレート開始 -->
<xsl:template match="/entrylist">
<!-- エントリのpref項目のみを$entryprefsに格納 -->
<xsl:variable name="entryprefs" select="entry/pref" />
<!-- 都道府県のリストを出力 -->
<xsl:for-each select="$preflist">
<xsl:variable name="prefid" select="@id" />
<xsl:value-of select="text()" />
(<xsl:value-of select="count($entryprefs[text()=$prefid])" />)<br />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
コード: 全て選択
(<xsl:value-of select="count($entryprefs[text()=$prefid])" />)<br />
count()命令は、()内の要素が何件あるかを返すXSLTの命令です。
$entryprefsには全エントリの都道府県項目のみが抽出して格納されているので、
コード: 全て選択
count($entryprefs)
[]内の条件で絞り込んでいます。その条件とは、「内容が$prefidと一致するもの」
です。
つまり、$prefidが"01"なら、エントリデータが北海道のものだけを抽出せよ、
ということです。そのcountを取っているのが先ほどのサンプルです。
$prefidは、$preflistのfor-eachループの中で"01"→"02"→"03"…と変わって
いくので、全都道府県分の件数が出力されることになります。
出力は、例えば
コード: 全て選択
北海道(2)
青森県(0)
岩手県(5)
宮城県(13)
:
以上、駆け足でしたがテクニックのご紹介でした。
動作確認済のサンプルからの抜粋の為、ひょっとしたら抜粋ミスをしている箇所が
あるかもしれません。その場合はご連絡頂ければ幸いです。