| MAP | PageMixer ドキュメント > チュートリアル > PageMixer の利用 > 部分シーケンスの反復 | << | >> |
本節では、
PageMixer における
HTML ページの一部を反復する方法に関して説明します。
説明のため、
本節では "買い物篭" 例と、
HTML の
"<tr>" および対応する
"</tr>"
に挟まれた部分を繰り返しつつデータをはめ込むフィルタを用います。
<table class="basket"> <tr class="Shop-Basket-Entry"> <td> <span class="Shop-Basket-EntryName">(名前)</span> </td> <td> <span class="Shop-Basket-EntryPrice">(価格)</span> </td> <td> <input type="text" class="Shop-Basket-EntryCount" name="xxx" value="0"> </td> <td> <span class="Shop-Basket-EntryTotal">(小計)</span> </td> </tr> </tabl>
<table class="basket"> <tr class="Shop-Basket-Entry"> <td> <span class="Shop-Basket-EntryName">バナナ</span> </td> <td> <span class="Shop-Basket-EntryPrice">120</span> </td> <td> <input type="text" class="Shop-Basket-EntryCount" name="Shop.Basket.Entry.ID:i0001" value="1"> </td> <td> <span class="Shop-Basket-EntryTotal">120</span> </td> </tr> <tr class="Shop-Basket-Entry"> <td> <span class="Shop-Basket-EntryName">ブロッコリ</span> </td> <td> <span class="Shop-Basket-EntryPrice">165</span> </td> <td> <input type="text" class="Shop-Basket-EntryCount" name="Shop.Basket.Entry.ID:i0002" value="2"> </td> <td> <span class="Shop-Basket-EntryTotal">330</span> </td> </tr> : : </table>
本節におけるクラス図を以下に示します。
色づけされているのが本節で定義するクラスで、 それ以外は PageMixer において定義済みです。
本節におけるオブジェクト図を以下に示します。
本節におけるシーケンス図を以下に示します。
最初の図は、 繰り返し対象となる部分シーケンスの先頭を、 フィルタが検知するまでのシーケンスです。
次の図は、
DataProvider から反復子を取得してからのシーケンスです。
本チュートリアルでは、 クラスは全てクラス名のみで表記されています。 完全な名称は以下の通りです。
| 表記 | 完全名 |
|---|---|
| ConsumerContext | jp.ne.dti.lares.foozy.pagemixer.mixer.ConsumerContext |
| DataProvider | jp.ne.dti.lares.foozy.pagemixer.mixer.DataProvider |
| HTMLSymbolSet | jp.ne.dti.lares.foozy.pagemixer.HTMLSymbolSet |
| ListDataProvider | jp.ne.dti.lares.foozy.pagemixer.mixer.ListDataProvider |
| SequenceDataIterationFilter | jp.ne.dti.lares.foozy.pagemixer.mixer.SequenceDataIterationFilter |
| SequenceWatcher | jp.ne.dti.lares.foozy.pagemixer.mixer.SequenceWatcher |
| 表記 | 完全名 |
|---|---|
| BasketEntry | common.BasketEntry |
| BasketEntryIterationFilter | pagemixer.filter.BasketEntryIterationFilter |
| Bootstrap | pagemixer.filter.Bootstrap |
| EntryCountAttr | pagemixer.filter.BasketEntryIterationFilter.EntryCountAttr |
| EntryNameText | pagemixer.filter.BasketEntryIterationFilter.EntryNameText |
| EntryPriceText | pagemixer.filter.BasketEntryIterationFilter.EntryPriceText |
| EntryTotalText | pagemixer.filter.BasketEntryIterationFilter.EntryTotalText |
本節では、 HTML ページの一部を、 以下のクラスオブジェクトの集合のために繰り返します。
public class BasketEntry
{
// "ShoppingItem" には ID, 名前, 価格が格納されています
final
private ShoppingItem item_;
private int count_;
////////////////////////////////////////
public BasketEntry(ShoppingItem item, int count){
item_ = item;
count_ = count;
}
////////////////////////////////////////
public String getID(){ return item_.getID(); }
public String getName(){ return item_.getName(); }
public String getName(Locale locale){
return item_.getName(locale);
}
public int getPrice(){ return item_.getPrice(); }
public void setCount(int count){ count_ = count; }
public int getCount(){ return count_; }
}
DataProvider の生成HTML ページの一部を繰り返すためには、 データ集合の供給が必要です。 与えられたデータ集合によって、 繰り返しの回数や、 どのようなデータをはめ込むのかを知ることが出来ます。
PageMixer フレームワークは、
データ集合の供給を行う主体を、
"DataProvider" として一般化しています。
このインタフェースは、
データ保持の実現を隠蔽します。
このインタフェースは、以下のように、 1つのメソッドだけを定義しています。
public interface DataProvider
{
public java.util.Iterator provide();
}
DataProvider"provide()" メソッドは、
データ集合を取り出すための
java.util.Iterator を返します。
必要な時に、
DataProvider#provide を起動することで、
常にデータ集合を取り出すための
Iterator を取得することが出来ます。
本節での例の場合、
BasketEntry 集合を提供する
DataProvider は、
以下のようにして生成することが出来ます。
// jav.util.List 型の "entryList" は
// "BasketEntry" を格納しています
ListDataProvider provider =
new ListDataProvider(entryList);
DataProvider の生成"ListDataProvider" は、
java.util.List による
DataProvider 実装クラスです。
勿論、
BasketEntry オブジェクト群を保持する
"買い物篭" クラスを定義し、
それに DataProvider
を実装させることも可能です。
備考:
SequenceDataIterationFilter クラスの
getIterator(Object) をオーバライドするのであれば、
DataProvider を生成する必要はありません。
このオーバライドにより、
利用者固有のオブジェクトから直接
Iterator を取得できるようになります。
DataProvider の識別子の定義DataProvider およびはめ込むデータを識別するために、
SequenceDataIterationFilter は、
以下のような2つの鍵を必要とします。
Object providerKey = "Shop.Basket.BasketEntryProvider"; Object dataKey = "Shop.Basket.BasketEntry";
DataProvider の識別子"providerKey" は
DataProvider を、
"dataKey" ははめ込み対象データ
(BasketEntryのことです)を識別します。
本節では、
"SequenceDataIterationFilter" を主フィルタとして用いますが、
Token 部分シーケンスを繰り返すことだけが
SequenceDataIterationFilter が
Token シーケンスに直接的に及ぼす唯一の影響です。
このフィルタ自身は、
反復された Token 部分シーケンスにデータをはめ込むことはしません。
データはめ込みを行う代わりに、
このフィルタはその責務を連携フィルタ群に委譲します。
この分離によって
SequenceDataIterationFilter
を単純で、且つ再利用性が高いものにできます。
SequenceDataIterationFilter#push(Filter)
は連携フィルタ群を登録するのに使用され、
登録されたフィルタは、
反復された部分シーケンスにデータをはめ込むためだけに使用されます。
"買い物篭" の例の場合、 以下のようなフィルタが必要でしょう。
<input>" への商品個数のはめ込み
実のところ、 これらのフィルタはこの節のサンプルフィルタの内部クラスとして、 既に定義されています。 それぞれのフィルタは、 これまでの節での知識で十分理解できる程度の、 非常に単純で簡単なものですので、 本節ではこれらの説明を省略します。 詳細は、ソースファイルを直接参照してください。
SequenceWatcher の生成前述のように、
本節では、
HTML の
"<tr>" および対応する
"</tr>" にはさまれた部分を、
繰り返しつつデータをはめ込むフィルタを作成します。
しかし、
与えられた HTML ページの該当する部分全ての位置にはめ込むのは、
得策ではありません。
そこで、対象となる部分シーケンスに以下の条件を定めます。
tr" 開始/終了タグの間で、
class" 属性を持っており、
Shop-Basket-Entry" であること
このような場合、
"SequenceWatcher" としては
"SequenceWatcher.NameAttr" が利用されます。
これは "最初の Token の名前と属性で監視しているシーケンス監視クラス"
のことです。
new SequenceWatcher.NameAttr(HTMLSymbolSet.SET.TR, HTMLSymbolSet.SET.CLASS, "Shop-Basket-Entry")
tr" の間を繰り返すための
SequenceWatcherSequenceDataIterationFilter からの派生本節のサンプルフィルタクラスは、 以下のように実装されます。
public class BasketEntryIterationFilter
extends SequenceDataIterationFilter
{
final static
private HTMLSymbolSet SET = HTMLSymbolSet.SET;
final static
private String VALUE = "Shop-Basket-Entry";
////////////////////////////////////////
public BasketEntryIterationFilter(Object providerKey,
Object dataKey)
{
super(new SequenceWatcher.NameAttr(SET.TR,
SET.CLASS,
VALUE),
providerKey,
dataKey);
push(new EntryNameText(dataKey));
push(new EntryPriceText(dataKey));
push(new EntryCountAttr(dataKey));
push(new EntryTotalText(dataKey));
}
}
SequenceDataIterationFilter
からの派生コンストラクタで push されているインスタンスが、
連携フィルタ群です。
以上で必要なものが全て揃いました。 実行コードは以下のようになります (詳細は BasketEntryIterationFilter を参照してください)。
try{
// DataProvider の設定/取得用のキー
final Object providerkey =
"Shop.Basket.BasketEntryProvider";
// 反復ごとのデータ設定/取得用のキー
final Object dataKey =
"Shop.Basket.BasketEntry";
Bootstrap bootstrap =
new Bootstrap.Default(filename)
{
protected void prepare(ConsumerContext context)
{
List entryList = BasketEntry.getEntryList();
ListDataProvider provider =
new ListDataProvider(entryList);
// DataProvider をコンテキストに設定
context.setValue(providerKey, provider);
}
};
BasketEntryIterationFilter filter =
new BasketEntryIterationFilter(providerKey, dataKey);
// フィルタの適用
bootstrap.execute(filter);
}
catch(Exception e){
e.printStackTrace(System.err);
}
入力用のサンプル HTML ファイルは、
配布物中の "src/demo/servlet/war/WEB-INF/page/demosite"
配下にある
"basket.ja.html" です。
上記実行コードが生成する HTML ファイルには、 "商品籠" の中に幾つか(乱数で決定)のの商品が列挙されます。
| MAP | PageMixer ドキュメント > チュートリアル > PageMixer の利用 > 部分シーケンスの反復 | << | >> |