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 018import org.opengion.fukurou.system.OgRuntimeException ; // 6.4.2.0 (2016/01/29) 019import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE; // 6.1.0.0 (2014/12/26) refactoring 020 021/** 022 * TagBuffer.java は、共通的に使用される 簡易タグ作成クラスです。 023 * タグヘッダーは、オブジェクト作成時に登録する為、後の変更は出来ません。 024 * BODY部や、属性は、一度登録すると書き換えできません。 025 * また、同一属性チェックは行いません。登録した属性のキーや、値を取り出すことも出来ません。 026 * あくまで、タグ文字列をストレートに作成することに特化したクラスです。 027 * これらの高度な機能が必要であれば、{@link org.opengion.fukurou.util.Attributes } をご参照ください。 028 * 029 * makeTag() メソッドを呼び出した時点で、内部にタグ文字列をキャッシュします。 030 * それ以降の変更は、出来ません。 031 * 032 * 内部的には、構造化されていません。あくまで、文字列連結(StringBuilder)の 033 * 簡易クラスとして、使用してください。 034 * 035 * ※ 6.1.1.0 (2015/01/17) 036 * StringBuilder と同様、add メソッドの戻り値に、自分自身を戻します。 037 * これにより、連結処理できるようにします。 038 * 039 * @og.group ユーティリティ 040 * 041 * @version 4.0 042 * @author Kazuhiko Hasegawa 043 * @since JDK5.0, 044 */ 045public final class TagBuffer { 046 private final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); 047 private final String tagName ; 048 private String tagBody ; 049 private String cacheTag ; 050 051 /** 052 * デフォルトコンストラクター 053 * このコンストラクターを使用すると、タグ名を指定できないため、 054 * 完成形のタグは、作成できません。属性リスト(key="value")の 055 * 連結形式を得る場合にのみ、使用して下さい。 056 * 057 */ 058 public TagBuffer() { 059 this( null ); // 6.1.1.0 (2015/01/17) メソッドの集約 060 } 061 062 /** 063 * コンストラクター 064 * タグ名に null を指定すると、デフォルトコンストラクターと同様に、 065 * 完成形のタグは、作成できません。属性リスト(key="value")の 066 * 連結形式を得る場合にのみ、タグ名 にnull を指定して下さい。 067 * 068 * @param tagName タグ名称 069 */ 070 public TagBuffer( final String tagName ) { 071 this.tagName = tagName; 072 if( tagName != null ) { 073 buf.append( '<' ).append( tagName ).append( ' ' ); // 6.0.2.5 (2014/10/31) char を append する。 074 } 075 } 076 077 /** 078 * タグの BODY部を追加登録します。 079 * 080 * すでに、登録済みの場合は、その値に、追記します。 081 * そうでない場合(初めての場合)は、その値をセットします。 082 * null を登録した場合は、何もしません。 083 * ※ 従来あった #setBody(String)の様に、null を登録した場合、Body を 084 * リセットする機能はありません。新しいオブジェクトを作成してください。 085 * 086 * このメソッドは、makeTag() が呼ばれた後は、登録できなくなります。 087 * 088 * @og.rev 6.1.1.0 (2015/01/17) #setBody(String) の代替えメソッドとして、新規追加 089 * 090 * @param body タグのBODY部に追加する文字列 091 * 092 * @return 自分自身 093 * @og.rtnNotNull 094 */ 095 public TagBuffer addBody( final String body ) { 096 return addBody( body,true ); 097 } 098 099 /** 100 * タグの BODY部を追加登録します。 101 * 102 * すでに、#setBody(String) で、登録済みの場合は、その値に、追記します。 103 * そうでない場合は、#setBody(String) と同じ動作になります。 104 * null を登録した場合は、何もしません。 105 * 106 * flag に、false を指定すると、追加登録しません。これは、if( flag ) { tagBuffer.addBody( body ); } 107 * の様な判定処理を、tagBuffer.body( body,flag ); に簡素化するために使用できます。 108 * TagBuffer は、StringBuilderの様に、メソッドの戻り値は、自分自身のオブジェクトなので、 109 * 上記の flag を使用して、切れ目なく連結させることが可能になります。 110 * 111 * このメソッドは、makeTag() が呼ばれた後は、登録できなくなります。 112 * 113 * @og.rev 6.1.1.0 (2015/01/17) 戻り値に、自分自身を返すようにします。 114 * 115 * @param body タグのBODY部に追加する文字列 116 * @param flag タグのBODY部に追加かどうかを決めるフラグ(true:追加する/false:何もしない) 117 * 118 * @return 自分自身 119 * @og.rtnNotNull 120 */ 121 public TagBuffer addBody( final String body,final boolean flag ) { 122 if( cacheTag != null ) { 123 final String errMsg = "makeTag() 実行後に、BODY部の値を書き換えることは出来ません。" ; 124 throw new OgRuntimeException( errMsg ); 125 } 126 127 if( flag && body != null ) { 128 // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..; 129 tagBody = tagBody == null ? body : tagBody + body; 130 } 131 132 return this ; 133 } 134 135 /** 136 * タグの属性に、追加登録します。 137 * 文字列として、key="value" の形式データを与えてください。連結時は、後ろに 138 * スペースを一つ挟みますので、与える引数自体に連結用スペースを追加しておく 139 * 必要はありません。 140 * 通常は、tagName なしで作成した、Tagbuffer オブジェクトの makeTag() メソッドの 141 * 返り値を渡しますが、Attributes.getAttribute() の返り値でも使用できます。 142 * 引数が null の場合は、なにもしません。 143 * このメソッドは、makeTag() が呼ばれた後は、登録できなくなります。 144 * 145 * @og.rev 6.1.1.0 (2015/01/17) 戻り値に、自分自身を返すようにします。 146 * 147 * @param str タグバッファーを追加します。 148 * 149 * @return 自分自身 150 * @og.rtnNotNull 151 * @see #makeTag() 152 * @see Attributes#getAttribute() 153 */ 154 public TagBuffer add( final String str ) { 155 return add( null,str,true ); // 6.1.1.0 (2015/01/17) メソッドの集約 156 157 } 158 159 /** 160 * タグの 属性(key="value")を登録します。 161 * 属性は、key="value" の文字列を作成します。 162 * key が null の場合は、値だけをそのまま連結します。 163 * val が null の場合は、登録しません。 164 * 165 * value に、ダブルコーテーション(")が含まれている場合は、属性値をシングルコーテーション 166 * でくくります。 167 * 両方含まれている場合は、シングルコーテーションをエスケープ文字(&#39;)に変換します。 168 * このメソッドは、makeTag() が呼ばれた後は、登録できなくなります。 169 * 170 * @og.rev 3.8.6.1 (2006/10/20) シングルとダブルが混在する場合は、シングルをエスケープする 171 * @og.rev 6.1.1.0 (2015/01/17) 戻り値に、自分自身を返すようにします。 172 * 173 * @param key 属性キー (null の場合は、val属性値 をそのまま追加する) 174 * @param val 属性値 (null の場合は、なにもしない) 175 * 176 * @return 自分自身 177 * @og.rtnNotNull 178 */ 179 public TagBuffer add( final String key,final String val ) { 180 return add( key,val,true ); // 6.1.1.0 (2015/01/17) メソッドの集約 181 } 182 183 /** 184 * タグの 属性(key="value")を登録します。 185 * 属性は、key="value" の文字列を作成します。 186 * key が null の場合は、値だけをそのまま連結します。 187 * val が null の場合は、登録しません。 188 * 189 * flag に、false を指定すると、属性は追加しません。これは、if( flag ) { tagBuffer.add( key,val ); } 190 * の様な判定処理を、tagBuffer.add( key,val,flag ); に簡素化するために使用できます。 191 * TagBuffer は、StringBuilderの様に、メソッドの戻り値は、自分自身のオブジェクトなので、 192 * 上記の flag を使用して、切れ目なく連結させることが可能になります。 193 * 194 * value に、ダブルコーテーション(")が含まれている場合は、属性値をシングルコーテーション 195 * でくくります。 196 * 両方含まれている場合は、シングルコーテーションをエスケープ文字に変換します。 197 * このメソッドは、makeTag() が呼ばれた後は、登録できなくなります。 198 * 199 * @og.rev 6.1.1.0 (2015/01/17) 戻り値に、自分自身を返すようにします。 200 * 201 * @param key 属性キー (null の場合は、val属性値 をそのまま追加する) 202 * @param val 属性値 (null の場合は、なにもしない) 203 * @param flag 属性を追加かどうかを決めるフラグ(true:追加する/false:何もしない) 204 * 205 * @return 自分自身 206 * @og.rtnNotNull 207 */ 208 public TagBuffer add( final String key,final String val,final boolean flag ) { 209 if( cacheTag != null ) { 210 final String errMsg = "makeTag() 実行後に、属性を追加することは出来ません。" ; 211 throw new OgRuntimeException( errMsg ); 212 } 213 214 // 6.1.1.0 (2015/01/17) ロジックを見直します。 215 if( flag && val != null ) { 216 // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..; 217 // 6.1.1.0 (2015/01/17) 元 add( String ) メソッドの処理 218 if( key == null ) { 219 buf.append( val ).append( ' ' ); 220 } 221 else { 222 buf.append( key ); 223 // ダブルコーテーションがある場合は、シングルコーテーションで囲う。 224 if( val.indexOf( '"' ) >= 0 ) { 225 // ただし、シングルコーテーションを含む場合は、エスケープ文字に置き換える。 226 buf.append( "='" ) 227 .append( val.indexOf( '\'' ) >= 0 ? val.replaceAll( "'","'" ) : val ) 228 .append( "' " ); 229 } 230 else { 231 buf.append( "=\"" ).append( val ).append( "\" " ); 232 } 233 } 234 } 235 236 return this ; // 6.1.1.0 (2015/01/17) 戻り値に、自分自身を返す 237 } 238 239 /** 240 * タグの 整形された文字列を 作成します。 241 * このメソッドは、tagName,body,属性より タグの完成形の文字列を作成します。 242 * 作成された文字列は、内部でキャッシュされます。 243 * BODY部を指定すると、<tagName key="val" ・・・ >body</tagName> 形式になります。 244 * BODY部が、null の場合は、 <tagName key="val" ・・・ /> 形式になります。 245 * タグ名を指定しない(null)と、完成形のタグは、作成できません。 246 * 属性リスト(key="value")の連結形式を返します。 247 * 248 * このメソッドの呼び出し以降では、setBody() も add() も実行できません。 249 * 250 * @return 整形された タグ文字列 251 */ 252 public String makeTag() { 253 if( cacheTag == null ) { 254 if( tagName != null ) { 255 if( tagBody == null ) { 256 buf.append( "/>" ); 257 } 258 else { 259 buf.append( '>' ).append( tagBody ) // 6.0.2.5 (2014/10/31) char を append する。 260 .append( "</" ).append( tagName ).append( '>' ); // 6.0.2.5 (2014/10/31) char を append する。 261 } 262 } 263 cacheTag = buf.toString(); 264 } 265 266 return cacheTag; 267 } 268 269 /** 270 * 行番号付きのタグの 整形された文字列を 作成します。 271 * このメソッドは、makeTag() の結果より、[I] 文字列を引数の行番号と変換します。 272 * これにより、動的に行番号つきの情報を属性に付与することが可能になります。 273 * 内部にキャッシュされる値は、[I] 記号を変換していない状態の文字列です。 274 * よって、このメソッドは、rowNo を変えて、何度でも呼び出すことは可能ですが、 275 * setBody() や add() は実行できません。 276 * 277 * @param rowNo 行番号([I] 文字列を変換します。) 278 * @param val 設定値([V] 文字列を変換します。) 279 * 280 * @return 整形された タグ文字列 281 */ 282 public String makeTag( final int rowNo,final String val ) { 283 String tag = makeTag(); 284 tag = StringUtil.replace( tag,"[I]",String.valueOf( rowNo ) ); 285 tag = StringUtil.replace( tag,"[V]",val ); 286 287 return tag ; 288 } 289}