ファイヤープロジェクト
カスタムタグのネスト
2004-06-08T22:00+09:00   matsu
カスタムタグをネストすることもでき,親タグから情報を取得することもできる.
カスタムタグをネストした場合,子タグ(内側のタグ)を評価,すなわち今までのようにdoStartTagやdoEndTagなどのタグハンドラによる処理をJSPコンテナにやらせるには,一点注意が必要である.それは,tldファイルにおいて,親タグ(外側のタグ)のbody-contentをJSPにしておくことである(※).これを例えばtagdependentにした場合,内側のタグのハンドラは呼ばれず,単にタグの内容が出力される.これを確認するためのサンプルを以下にしめす.まず親タグのハンドラ.
そして子タグのハンドラ
これを以下のJSPで表示してみる.
カスタムタグindentについてはまとめて後述する.今の問題はカスタムタグinner,outer,outer2にある.outerとouter2のハンドラはどちらもOuterTagである.ただしtldファイルにおけるbody-conentが異なる.tldファイルを以下に示す.
今回も例によって,今までのsample.tldに要素tagを追加した.body-contentはouterはJSP,outer2はtagdependentである.出力を以下に示す.
この出力から,outer2で囲まれたinnerは評価されず,単に内容である"INNER"が出力されるだけであることがわかる.
※ body-content要素は任意で,省略した場合のデフォルトはJSPである.
先述のカスタムタグouterで囲まれた部分の出力のうち,"==="で始まる部分を以下に抜きだしてみる.
=== out of InnerTag : org.apache.jasper.runtime.BodyContentImpl@159d510
=== bodyContent of InnerTag : org.apache.jasper.runtime.BodyContentImpl@b31b77
=== out of OuterTag : org.apache.jasper.runtime.JspWriterImpl@d0357a
=== bodyContent of OuterTag : org.apache.jasper.runtime.BodyContentImpl@159d510
outerのbodyContentがinnerのpageContext.getOut()の返り値のオブジェクトと一致することがわかるだろうか.親タグのdoStartTagで
EVAL_BODY_BUFFERED
を返すと,JSPコンテナはpageContextに対してpushBodyメソッドを呼ぶことは以前に記述した.これによって,親タグにおいてはdoEndTagが呼ばれるまで,pageContext.getOut()は(親タグの)bodyContentとなるが,この間に子タグが評価されるので,子タグでは最初からpageContext.getOut()が(親タグの)bodyContentだったように見える.そして子タグのdoStartTagでEVAL_BODY_BUFFEREDが返るとJSPコンテナはpageContextに対してさらにpushBodyして(子タグの)bodyContentをpageContext().getOut()となるように設定する.この仕組みによって,親タグでは子タグが評価された結果の出力も親タグのdoEndTagで拾うことができ,親タグとして出力するかしないかなどを制御できる.少し乱暴に言えば,子タグは親タグに対して出力し,親タグはさらなる親タグに対して子タグの出力+自分の出力を出力していく.
上記のサンプルのJSP,tldファイル,そして出力結果には,indentというカスタムタグに関するものがあった.これは本頁のもう一つのサンプルである.ハンドラを以下に示す.
このタグは必須属性indentNumの値分タグの内容の先頭に を付加して出力する.indentタグは入れ子にすることができ,その場合は親のindentNum+自分のindentNum分 を付加して自分の内容を出力する.このような処理をするためには,親のハンドラオブジェクトを取得する必要がある.親タグのハンドラオブジェクトはJSPコンテナによりsetParentされ,タグハンドラ内ではgetParentで取得できる.
Tag getParent()
このメソッドはTagインタフェースで定義されている.サンプルでは,indentタグ同士の入れ子の間にindentタグ以外が混ざっても動作するようにしてみた.
    private IndentTag getParentIndentTag () {
	String myClassName = "sample.IndentTag";
	Object parentIndentTag = null;
	do {
	    parentIndentTag = getParent();
	} while (parentIndentTag != null
		 && ! parentIndentTag.getClass().getName().equals(myClassName));
	if (parentIndentTag == null) {
	    return null;
	}
	else {
	    return (IndentTag)parentIndentTag;
	}
    }
getParent()の返り値オブジェクトのクラスが自分自身のクラスと一致するまで親の親をgetParentで辿って行く.出力を見ると,子タグは親のインデント数+自分のインデント数分インデントしていることが分かる.親タグのハンドラオブジェクトを取得する方法がわかれば,あとは親のハンドラでgetterやsetterなどを作成すれば,何でもできる.
matsu(C)
Since 2002
Mail to matsu