    001/*
    002 * Copyright (c) 2009 The openGion Project.
    003 *
    004 * Licensed under the Apache License, Version 2.0 (the "License");
    005 * you may not use this file except in compliance with the License.
    006 * You may obtain a copy of the License at
    007 *
    008 *     http://www.apache.org/licenses/LICENSE-2.0
    009 *
    010 * Unless required by applicable law or agreed to in writing, software
    011 * distributed under the License is distributed on an "AS IS" BASIS,
    012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
    013 * either express or implied. See the License for the specific language
    014 * governing permissions and limitations under the License.
    015 */
    016package org.opengion.fukurou.util;
    017
    018/**
    019 * TagBuffer.java は、共通的に使用される 簡易タグ作成クラスです。
    020 * タグヘッダーは、オブジェクト作成時に登録する為、後の変更は出来ません。
    021 * BODY部や、属性は、一度登録すると書き換えできません。
    022 * また、同一属性チェックは行いません。登録した属性のキーや、値を取り出すことも出来ません。
    023 * あくまで、タグ文字列をストレートに作成することに特化したクラスです。
    024 * これらの高度な機能が必要であれば、{@link org.opengion.fukurou.util.Attributes } をご参照ください。
    025 *
    026 * makeTag() メソッドを呼び出した時点で、内部にタグ文字列をキャッシュします。
    027 * それ以降の変更は、出来ません。
    028 *
    029 * 内部的には、構造化されていません。あくまで、文字列連結(StringBuilder)の
    030 * 簡易クラスとして、使用してください。
    031 *
    032 * @og.group ユーティリティ
    033 *
    034 * @version  4.0
    035 * @author       Kazuhiko Hasegawa
    036 * @since    JDK5.0,
    037 */
    038public final class TagBuffer {
    039        private final StringBuilder buf = new StringBuilder(100);
    040        private final String tagName ;
    041        private       String tagBody     = null;
    042        private       String cacheTag = null;
    043
    044        /**
    045         * デフォルトコンストラクター
    046         * このコンストラクターを使用すると、タグ名を指定できないため、
    047         * 完成形のタグは、作成できません。属性リスト(key="value")の
    048         * 連結形式を得る場合にのみ、使用して下さい。
    049         *
    050         */
    051        public TagBuffer() {
    052                this.tagName = null;
    053        }
    054
    055        /**
    056         * コンストラクター
    057         * タグ名に null を指定すると、デフォルトコンストラクターと同様に、
    058         * 完成形のタグは、作成できません。属性リスト(key="value")の
    059         * 連結形式を得る場合にのみ、タグ名 にnull を指定して下さい。
    060         *
    061         * @param       tagName  タグ名称
    062         */
    063        public TagBuffer( final String tagName ) {
    064                this.tagName = tagName;
    065                if( tagName != null ) {
    066                        buf.append( "<" ).append( tagName ).append( " " );
    067                }
    068        }
    069
    070        /**
    071         * タグの BODY部を登録します。
    072         * 登録しない場合は、BODY部のないタグ(空要素タグ)を生成します。
    073         * BODY部を指定すると、&lt;tagName key="val" ･･･ &gt;body&lt;/tagName&gt; 形式になります。
    074         * BODY部が、null の場合は、 &lt;tagName key="val" ･･･ /&gt; 形式になります。
    075         * このメソッドは、makeTag() が呼ばれた後は、登録できなくなります。
    076         *
    077         *      @deprecated {@link TagBuffer#addBody(String)}
    078         * @param       body     タグのBODY部
    079         */
    080        public void setBody( final String body ) {
    081                if( cacheTag != null ) {
    082                        String errMsg = "makeTag() 実行後に、BODY部の値を書き換えることは出来ません。" ;
    083                        throw new RuntimeException( errMsg );
    084                }
    085
    086                this.tagBody = body;
    087        }
    088
    089        /**
    090         * タグの BODY部を追加登録します。
    091         *
    092         * すでに、登録済みの場合は、その値に、追記します。
    093         * そうでない場合(初めての場合)は、その値をセットします。
    094         * null を登録した場合は、何もしません。
    095         * ※ 従来あった #setBody(String)の様に、null を登録した場合、Body を
    096         * リセットする機能はありません。新しいオブジェクトを作成してください。
    097         *
    098         * このメソッドは、makeTag() が呼ばれた後は、登録できなくなります。
    099         *
    100         * @og.rev 5.8.4.1 (2015/02/20) 6.1.1.0逆移植 #setBody(String) の代替えメソッドとして、新規追加
    101         *
    102         * @param       body     タグのBODY部に追加する文字列
    103         *
    104         * @return      自分自身
    105         * @og.rtnNotNull
    106         */
    107        public TagBuffer addBody( final String body ) {
    108                return addBody( body,true );
    109        }
    110
    111        /**
    112         * タグの BODY部を追加登録します。
    113         *
    114         * すでに、#setBody(String) で、登録済みの場合は、その値に、追記します。
    115         * そうでない場合は、#setBody(String) と同じ動作になります。
    116         * null を登録した場合は、何もしません。
    117         *
    118         * flag に、false を指定すると、追加登録しません。これは、if( flag ) { tagBuffer.addBody( body ); }
    119         * の様な判定処理を、tagBuffer.body( body,flag ); に簡素化するために使用できます。
    120         * TagBuffer は、StringBuilderの様に、メソッドの戻り値は、自分自身のオブジェクトなので、
    121         * 上記の flag を使用して、切れ目なく連結させることが可能になります。
    122         *
    123         * このメソッドは、makeTag() が呼ばれた後は、登録できなくなります。
    124         *
    125         * @og.rev 5.8.4.1 (2015/02/20) 6.1.1.0逆移植 戻り値に、自分自身を返すようにします。
    126         *
    127         * @param       body    タグのBODY部に追加する文字列
    128         * @param       flag    タグのBODY部に追加かどうかを決めるフラグ(true:追加する/false:何もしない)
    129         *
    130         * @return      自分自身
    131         * @og.rtnNotNull
    132         */
    133        public TagBuffer addBody( final String body,final boolean flag ) {
    134                if( cacheTag != null ) {
    135                        final String errMsg = "makeTag() 実行後に、BODY部の値を書き換えることは出来ません。" ;
    136                        throw new RuntimeException( errMsg );
    137                }
    138
    139                if( flag && body != null ) {
    140                        if( tagBody !=null ) { tagBody += body; }
    141                        else                             { tagBody =  body; }
    142                }
    143
    144                return this ;
    145        }
    146
    147        /**
    148         * タグの 属性(key="value")を登録します。
    149         * 属性は、key="value" の文字列を作成します。key か、value のどちらかが null
    150         * の場合は、登録しません。
    151         * value に、ダブルコーテーション(")が含まれている場合は、属性値をシングルコーテーション
    152         * でくくります。
    153         * 両方含まれている場合は、シングルコーテーションをエスケープ文字に変換します。
    154         * このメソッドは、makeTag() が呼ばれた後は、登録できなくなります。
    155         *
    156         * @og.rev 3.8.6.1 (2006/10/20) シングルとダブルが混在する場合は、シングルをエスケープする
    157         *
    158         * @param       key      属性キー (null の場合は、なにもしない)
    159         * @param       val      属性値 (null の場合は、なにもしない)
    160         */
    161        public void add( final String key,final String val ) {
    162                if( cacheTag != null ) {
    163                        String errMsg = "makeTag() 実行後に、属性を追加することは出来ません。" ;
    164                        throw new RuntimeException( errMsg );
    165                }
    166
    167                if( key != null && val != null ) {
    168                        if( val.indexOf( '\"' ) >= 0 ) {
    169                                String temp = val ;
    170                                if( val.indexOf( "'" ) >= 0 ) { temp = val.replaceAll( "'","&#39;" ); }
    171                                buf.append( key ).append( "='" ).append( temp ).append( "' " );
    172                        }
    173                        else {
    174                                buf.append( key ).append( "=\"" ).append( val ).append( "\" " );
    175                        }
    176                }
    177        }
    178
    179        /**
    180         * タグの属性に、追加登録します。
    181         * 文字列として、key="value" の形式データを与えてください。連結時は、後ろに
    182         * スペースを一つ挟みますので、与える引数自体に連結用スペースを追加しておく
    183         * 必要はありません。
    184         * 通常は、tagName なしで作成した、Tagbuffer オブジェクトの makeTag() メソッドの
    185         * 返り値を渡しますが、Attributes.getAttribute() の返り値でも使用できます。
    186         * 引数が null の場合は、なにもしません。
    187         * このメソッドは、makeTag() が呼ばれた後は、登録できなくなります。
    188         *
    189         * @param       str     タグバッファーを追加します。
    190         * @see         #makeTag()
    191         * @see         Attributes#getAttribute()
    192         */
    193        public void add( final String str ) {
    194                if( cacheTag != null ) {
    195                        String errMsg = "makeTag() 実行後に、属性を追加することは出来ません。" ;
    196                        throw new RuntimeException( errMsg );
    197                }
    198
    199                if( str != null ) {
    200                        buf.append( str ).append( " " );
    201                }
    202        }
    203
    204        /**
    205         * タグの 整形された文字列を 作成します。
    206         * このメソッドは、tagName,body,属性より タグの完成形の文字列を作成します。
    207         * 作成された文字列は、内部でキャッシュされます。
    208         * BODY部を指定すると、&lt;tagName key="val" ･･･ &gt;body&lt;/tagName&gt; 形式になります。
    209         * BODY部が、null の場合は、 &lt;tagName key="val" ･･･ /&gt; 形式になります。
    210         * タグ名を指定しない(null)と、完成形のタグは、作成できません。
    211         * 属性リスト(key="value")の連結形式を返します。
    212         *
    213         * このメソッドの呼び出し以降では、setBody() も add() も実行できません。
    214         *
    215         * @return      整形された タグ文字列
    216         */
    217        public String makeTag() {
    218                if( cacheTag == null ) {
    219                        if( tagName != null ) {
    220                                if( tagBody == null ) {
    221                                        buf.append( "/>" );
    222                                }
    223                                else {
    224                                        buf.append( ">" ).append( tagBody );
    225                                        buf.append( "</" ).append( tagName ).append( ">" );
    226                                }
    227                        }
    228                        cacheTag = buf.toString();
    229                }
    230
    231                return cacheTag;
    232        }
    233
    234        /**
    235         * 行番号付きのタグの 整形された文字列を 作成します。
    236         * このメソッドは、makeTag() の結果より、[I] 文字列を引数の行番号と変換します。
    237         * これにより、動的に行番号つきの情報を属性に付与することが可能になります。
    238         * 内部にキャッシュされる値は、[I] 記号を変換していない状態の文字列です。
    239         * よって、このメソッドは、rowNo を変えて、何度でも呼び出すことは可能ですが、
    240         * setBody() や add() は実行できません。
    241         *
    242         * @param       rowNo   行番号([I] 文字列を変換します。)
    243         * @param       val     設定値([V] 文字列を変換します。)
    244         *
    245         * @return      整形された タグ文字列
    246         */
    247        public String makeTag( final int rowNo,final String val ) {
    248                String tag = makeTag();
    249                tag = StringUtil.replace( tag,"[I]",String.valueOf( rowNo ) );
    250                tag = StringUtil.replace( tag,"[V]",val );
    251
    252                return tag ;
    253        }
    254}