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 java.util.Locale; 019import java.util.Set; 020import java.util.HashSet; 021import java.util.Arrays; 022 023import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE; 024 025/** 026 * TagBuffer.java は、共通的に使用される 簡易タグ作成クラスです。 027 * 028 * ここでは、4つの形式(TAG , CSS , JSON , ARRAY )をサポートします。 029 * TAG形式: 030 * BODYなし <tag key1="val1" key2="val2" ・・・/> 031 * BODYあり <tag key1="val1" key2="val2" ・・・>body</tag> 032 * 033 * CSS形式: 034 * { key1:val1; key2:val2; ・・・ } 035 * 036 * JSON形式: 037 * 文字 { "key1":"val1", "key2":"val2", ・・・ } 038 * 数値 { "key1":num1 , "key2":num2 , ・・・ } 039 * 040 * ARRAY形式: 041 * 文字 [ "val1", "val2", ・・・ ] 042 * 数値 [ num1 , num2 , ・・・ ] 043 * 044 * これらの形式は、#startTag( String ) , #startCss( String ) , #startJson() , #startArray() 045 * メソッドで始まり、#make() で、完了します。 046 * 完了とは、内部の StringBuilder に書き込まれることを意味しますので、再び、 047 * startXXX()メソッドから始めることが可能です。 048 * つまり、一つのインスタンスに、TAGやCSSをまとめて追記していくことが出来ます。 049 * 最後に、#toString() メソッドで、内部の StringBuilder を文字列として返します。 050 * 051 * TagBuffer クラスの中身を全面的に見直しています。また、過去のTagBufferと互換性を取るための 052 * メソッドも残していますが、順次、削除していく予定です。 053 * 054 * もっと高度な機能が必要であれば、{@link org.opengion.fukurou.util.Attributes } をご参照ください。 055 * 056 * @og.rev 7.0.1.0 (2018/10/15) 新規作成 057 * @og.group ユーティリティ 058 * 059 * @version 7.0 060 * @author Kazuhiko Hasegawa 061 * @since JDK8.0, 062 */ 063public final class TagBuffer { 064 private static enum DTYPE { // 処理中のデータ形式 065 /* TAG形式 */ TAG , 066 /* CSS形式 */ CSS , 067 /* JSON形式 */ JSON , 068 /* ARRAY形式 */ ARY ; 069 } 070 071 // 空要素となるタグ名 072 private static final Set<String> YOSO_SET = new HashSet<>( Arrays.asList( "area","base","br","col","command","embed","hr","img","input" 073 ,"keygen","link","meta","param","source","track","wbr" ) ); 074 075 private final StringBuilder tagBuf = new StringBuilder( BUFFER_MIDDLE ); // タグ構築用のバッファ(makeでクリア) 076 private final StringBuilder bodyBuf = new StringBuilder( BUFFER_MIDDLE ); // タグ構築用のバッファ(makeでクリア) 077 private final StringBuilder makeBuf = new StringBuilder( BUFFER_MIDDLE ); // make実行時のバッファ(makeでappend) 078 079 private DTYPE dType = DTYPE.TAG ; // データ形式(初期値は、タグ) 080 private String name ; // タグ名か、セレクター 081 private char kvsep ; // key-val 分離文字( '=' か、':' ) 082 private String endStr ; // 終端連結時文字( " " か、"; " か、", " など) 083 084 private String cacheTag ; // TagBufferと互換性を取るための、makeTag 実行時のキャッシュ 085 private boolean isKaraTag ; // 空要素のタグ名かどうかの識別フラグです。 086 087 /** 088 * デフォルトコンストラクター 089 * 090 */ 091 public TagBuffer() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 092 093 /** 094 * タグ名を指定した、タグ構築用のコンストラクター 095 * 096 * これは、TagBuffer クラスとの互換性の為に用意されたコンストラクターです。 097 * 098 * @param name タグの名前 099 */ 100 public TagBuffer( final String name ) { 101 startTag( name ); 102 } 103 104 /** 105 * TAG形式のデータ作成を宣言します。 106 * 107 * TAG形式: 108 * BODYなし <tag key1="val1" key2="val2" ・・・/> 109 * BODYあり <tag key1="val1" key2="val2" ・・・>body</tag> 110 * 111 * @param name タグの名前 112 * @return 自分自身 113 * @og.rtnNotNull 114 */ 115 public TagBuffer startTag( final String name ) { 116 return start( DTYPE.TAG , name , '='," " ); 117 } 118 119 /** 120 * CSS形式のデータ作成を宣言します。 121 * 122 * CSS形式: 123 * { key1:val1; key2:val2; ・・・ } 124 * 125 * @param name CSSのセレクター 126 * @return 自分自身 127 * @og.rtnNotNull 128 */ 129 public TagBuffer startCss( final String name ) { 130 return start( DTYPE.CSS , name , ':' , "; " ); 131 } 132 133 /** 134 * JSON形式のデータ作成を宣言します。 135 * 136 * JSON形式: 137 * 文字 { "key1":"val1", "key2":"val2", ・・・ } 138 * 数値 { "key1":num1 , "key2":num2 , ・・・ } 139 * 140 * @return 自分自身 141 * @og.rtnNotNull 142 */ 143 public TagBuffer startJson() { 144 return start( DTYPE.JSON , null , ':' , ", " ); //name は使いません。 145 } 146 147 /** 148 * ARRAY形式のデータ作成を宣言します。 149 * 150 * ARRAY形式: 151 * 文字 [ "val1", "val2", ・・・ ] 152 * 数値 [ num1 , num2 , ・・・ ] 153 * 154 * @return 自分自身 155 * @og.rtnNotNull 156 */ 157 public TagBuffer startArray() { 158 return start( DTYPE.ARY , null , ' ' , ", " ); // name , kvsep は使いません。 159 } 160 161 /** 162 * 指定のデータ形式の開始を宣言します。 163 * 164 * このメソッドは、#startTag( String ) , #startCss( String ) , #startJson() , #startArray() から 165 * 呼ばれる集約メソッドです。 166 * 各処理に必要な情報は、呼び出し元で設定しています。 167 * 168 * @param type タグの種類を示す enum DTYPE { TAG , CSS , JSON , ARY ; } 169 * @param name タグの名前か、CSSのセレクター 170 * @param kvsep key-val 分離文字( '=' か、':' ) 171 * @param endStr 終端連結時文字( " " か、"; " か、", " など) 172 * @return 自分自身 173 * @og.rtnNotNull 174 */ 175 private TagBuffer start( final DTYPE type , final String name , final char kvsep , final String endStr ) { 176 this.dType = type; 177 this.name = name; 178 this.kvsep = kvsep; 179 this.endStr = endStr; 180 181 // 空要素かどうかを判定します。 182 isKaraTag = name != null && YOSO_SET.contains( name.toLowerCase( Locale.JAPAN ) ); 183 184 return this; 185 } 186 187 /** 188 * データ本体のバッファに直接値を追加します。 189 * 190 * 指定の可変長文字列は、何の加工も無く、' '(スペース)で区切られて、直接追加されます。 191 * データ形式以外の文字列を前後、間に追記したい場合に、都度呼びます。 192 * 193 * 引数が null や、空文字列の場合は、何もしません。 194 * 195 * @param vals データ本体のバッファに直接追加する可変長文字列 196 * @return 自分自身 197 * @see #addBuffer( String , boolean ) 198 * @og.rtnNotNull 199 */ 200 public TagBuffer addBuffer( final String... vals ) { 201 if( vals != null ) { 202 for( final String val : vals ) { 203 if( StringUtil.isNotNull( val ) ) { 204 makeBuf.append( val ).append( ' ' ); 205 } 206 } 207 } 208 209 return this ; 210 } 211 212 /** 213 * データ本体のバッファに直接値を追加します。 214 * 215 * 指定の文字列は、何の加工も無く、' '(スペース)で区切られて、直接追加されます。 216 * データ形式以外の文字列を前後、間に追記したい場合に、都度呼びます。 217 * 218 * 引数が null や、空文字列の場合は、何もしません。 219 * 220 * @param val データ本体のバッファに直接追加する文字列 221 * @param isUse 追加処理を行うかどうかの判定(true:処理する/false:処理しない) 222 * @return 自分自身 223 * @see #addBuffer( String... ) 224 * @og.rtnNotNull 225 */ 226 public TagBuffer addBuffer( final String val , final boolean isUse ) { 227 return isUse ? addBuffer( val ) : this ; 228 } 229 230// /** 231// * データ本体のバッファに直接値を追加します。 232// * 233// * 指定の可変長文字列は、何の加工も無く、' '(スペース)で区切られて、直接追加されます。 234// * データ形式以外の文字列を前後、間に追記したい場合に、都度呼びます。 235// * 236// * 引数が null や、空文字列の場合は、何もしません。 237// * 238// * @param vals データ本体のバッファに直接追加する文字列配列 239// * @param isUse 追加処理を行うかどうかの判定(true:処理する/false:処理しない) 240// * @return 自分自身 241// * @see #addBuffer( String... ) 242// * @og.rtnNotNull 243// */ 244// public TagBuffer addBuffer( final String[] vals , final boolean isUse ) { 245// if( isUse && vals != null ) { 246// for( final String val : vals ) { 247// if( StringUtil.isNotNull( val ) ) { 248// makeBuf.append( val ).append( ' ' ); 249// } 250// } 251// } 252// 253// return this ; 254// } 255 256 /** 257 * データの登録エリアのバッファに直接値を追加します。 258 * 259 * これは、TagBuffer クラスとの互換性の為に用意されたメソッドです。 260 * 近い将来、削除します。 261 * 262 * @param val データの登録エリアのバッファに直接追加する文字列 263 * @return 自分自身 264 * @see #addBody( String... ) 265 * @og.rtnNotNull 266 */ 267 public TagBuffer add( final String val ) { 268 return addOptions( val ); 269 } 270 271 /** 272 * データの登録エリアのバッファに直接値を追加します。 273 * 274 * 指定の可変長文字列は、何の加工も無く、' '(スペース)で区切られて、直接追加されます。 275 * これは、データ生成中のバッファに対して、追加を行います。 276 * 例えば、外部で、タグやCSSのデータ形式を作成済みで、その文字列を追記するなどです。 277 * 278 * 引数が null や、空文字列の場合は、何もしません。 279 * 280 * @param vals データの登録エリアのバッファに直接追加する可変長文字列 281 * @return 自分自身 282 * @see #addOptions( String... ) 283 * @og.rtnNotNull 284 */ 285 public TagBuffer addOptions( final String... vals ) { 286 if( vals != null ) { 287 for( final String val : vals ) { 288 if( StringUtil.isNotNull( val ) ) { 289 tagBuf.append( val ).append( ' ' ); 290 } 291 } 292 } 293 294 return this ; 295 } 296 297 /** 298 * データの登録エリアのバッファに直接値を追加します。 299 * 300 * 指定の文字列は、何の加工も無く、' '(スペース)で区切られて、直接追加されます。 301 * これは、データ生成中のバッファに対して、追加を行います。 302 * 例えば、外部で、タグやCSSのデータ形式を作成済みで、その文字列を追記するなどです。 303 * 304 * 引数が null や、空文字列の場合は、何もしません。 305 * 306 * @param val データの登録エリアのバッファに直接追加する文字列 307 * @param isUse 追加処理を行うかどうかの判定(true:処理する/false:処理しない) 308 * @return 自分自身 309 * @see #addOptions( String... ) 310 * @og.rtnNotNull 311 */ 312 public TagBuffer addOptions( final String val , final boolean isUse ) { 313 return isUse ? addOptions( val ) : this ; 314 } 315 316// /** 317// * データの登録エリアのバッファに直接値を追加します。 318// * 319// * 指定の可変長文字列は、何の加工も無く、' '(スペース)で区切られて、直接追加されます。 320// * これは、データ生成中のバッファに対して、追加を行います。 321// * 例えば、外部で、タグやCSSのデータ形式を作成済みで、その文字列を追記するなどです。 322// * 323// * 引数が null や、空文字列の場合は、何もしません。 324// * 325// * @param vals データの登録エリアのバッファに直接追加する文字列配列 326// * @param isUse 追加処理を行うかどうかの判定(true:処理する/false:処理しない) 327// * @return 自分自身 328// * @see #addOptions( String... ) 329// * @og.rtnNotNull 330// */ 331// public TagBuffer addOptions( final String[] vals , final boolean isUse ) { 332// if( isUse && vals != null ) { 333// for( final String val : vals ) { 334// if( StringUtil.isNotNull( val ) ) { 335// tagBuf.append( val ).append( ' ' ); 336// } 337// } 338// } 339// 340// return this ; 341// } 342 343 /** 344 * データの BODY部のバッファに直接値を追加します(データ形式 TAGのみ有効)。 345 * 346 * 指定の可変長文字列は、何の加工も無く、' '(スペース)で区切られて、直接追加されます。 347 * これは、データの BODY部のバッファに対して、追加を行います。 348 * BODY部は、タグのbody として使用されているデータで、BODY有り無しの判定は、 349 * このデータが登録されたかどうかで判定しています。 350 * 351 * 引数が null の場合は、何もしません。 352 * 353 * @param vals データのBODY部のバッファに直接追加する可変長文字列 354 * @return 自分自身 355 * @see #addOptions( String... ) 356 * @og.rtnNotNull 357 */ 358 public TagBuffer addBody( final String... vals ) { 359 if( dType == DTYPE.TAG && vals != null ) { 360 bodyBuf.append( String.join( " ",vals ) ); 361 362 // for( final String val : vals ) { 363 // if( val != null ) { 364 // bodyBuf.append( val ).append( ' ' ); 365 // } 366 // } 367 } 368 369 return this ; 370 } 371 372 /** 373 * データの BODY部のバッファに直接値を追加します(データ形式 TAGのみ有効)。 374 * 375 * 指定の文字列は、何の加工も無く、' '(スペース)で区切られて、直接追加されます。 376 * これは、データの BODY部のバッファに対して、追加を行います。 377 * BODY部は、タグのbody として使用されているデータで、BODY有り無しの判定は、 378 * このデータが登録されたかどうかで判定しています。 379 * 380 * 引数が null や、空文字列の場合は、何もしません。 381 * 382 * @param val データのBODY部のバッファに直接追加する文字列 383 * @param isUse 追加処理を行うかどうかの判定(true:処理する/false:処理しない) 384 * @return 自分自身 385 * @see #addOptions( String... ) 386 * @og.rtnNotNull 387 */ 388 public TagBuffer addBody( final String val , final boolean isUse ) { 389 return isUse ? addBody( val ) : this ; 390 } 391 392// /** 393// * データの BODY部のバッファに直接値を追加します(データ形式 TAGのみ有効)。 394// * 395// * 指定の可変長文字列は、何の加工も無く、' '(スペース)で区切られて、直接追加されます。 396// * これは、データの BODY部のバッファに対して、追加を行います。 397// * BODY部は、タグのbody として使用されているデータで、BODY有り無しの判定は、 398// * このデータが登録されたかどうかで判定しています。 399// * 400// * 引数が null や、空文字列の場合は、何もしません。 401// * 402// * @param vals データのBODY部のバッファに直接追加する文字列配列 403// * @param isUse 追加処理を行うかどうかの判定(true:処理する/false:処理しない) 404// * @return 自分自身 405// * @see #addOptions( String... ) 406// * @og.rtnNotNull 407// */ 408// public TagBuffer addBody( final String[] vals , final boolean isUse ) { 409// if( isUse && dType == DTYPE.TAG && vals != null ) { 410// for( final String val : vals ) { 411// if( StringUtil.isNotNull( val ) ) { 412// bodyBuf.append( val ).append( ' ' ); 413// } 414// } 415// } 416// 417// return this ; 418// } 419 420 /** 421 * データの登録エリアに、数値型として値を追加します(データ形式 ARRAYのみ有効)。 422 * 423 * データが、数値型の場合、ダブルコーテーションは付けません。 424 * 指定の可変長文字列は、何の加工も無く、endStr(終端連結時文字)で区切られて、追加されます。 425 * ARRAY形式のみ有効なので、endStrは、',' になります。 426 * データが、null の場合、endStr(終端連結時文字)のみが、追加されますので、 427 * データの個数は、変わりません。 428 * 最後に必ず、endStr(終端連結時文字)が付きます。 429 * 430 * @param vals データの登録エリアに、数値型として追加する可変長文字列 431 * @return 自分自身 432 * @see #addNum( String,boolean ) 433 * @og.rtnNotNull 434 */ 435 public TagBuffer addNum( final String... vals ) { 436 if( dType == DTYPE.ARY && vals != null ) { 437 for( final String val : vals ) { 438 if( val == null ) { 439 tagBuf.append( endStr ); 440 } 441 else { 442 tagBuf.append( val ).append( endStr ); 443 } 444 } 445 } 446 447 return this ; 448 } 449 450 /** 451 * データの登録エリアに、数値型として値を追加します(データ形式 ARRAYのみ有効)。 452 * 453 * データが、数値型の場合、ダブルコーテーションは付けません。 454 * 指定の文字列は、何の加工も無く、endStr(終端連結時文字)で区切られて、追加されます。 455 * ARRAY形式のみ有効なので、endStrは、',' になります。 456 * データが、null の場合、endStr(終端連結時文字)のみが、追加されます。 457 * 最後に必ず、endStr(終端連結時文字)が付きます。 458 * 459 * @param val データの登録エリアに、数値型として追加する文字列 460 * @param isUse 追加処理を行うかどうかの判定(true:処理する/false:処理しない) 461 * @return 自分自身 462 * @see #addNum( String... ) 463 * @og.rtnNotNull 464 */ 465 public TagBuffer addNum( final String val , final boolean isUse ) { 466 return isUse ? addNum( val ) : this ; 467 } 468 469// /** 470// * データの登録エリアに、数値型として値を追加します(データ形式 ARRAYのみ有効)。 471// * 472// * データが、数値型の場合、ダブルコーテーションは付けません。 473// * 指定の可変長文字列は、何の加工も無く、endStr(終端連結時文字)で区切られて、追加されます。 474// * ARRAY形式のみ有効なので、endStrは、',' になります。 475// * データが、null の場合、endStr(終端連結時文字)のみが、追加されますので、 476// * データの個数は、変わりません。 477// * 最後に必ず、endStr(終端連結時文字)が付きます。 478// * 479// * @param vals データの登録エリアに、数値型として追加する文字列配列 480// * @param isUse 追加処理を行うかどうかの判定(true:処理する/false:処理しない) 481// * @return 自分自身 482// * @see #addNum( String... ) 483// * @og.rtnNotNull 484// */ 485// public TagBuffer addNum( final String[] vals , final boolean isUse ) { 486// if( isUse && dType == DTYPE.ARY && vals != null ) { 487// for( final String val : vals ) { 488// if( val == null ) { 489// tagBuf.append( endStr ); 490// } 491// else { 492// tagBuf.append( val ).append( endStr ); 493// } 494// } 495// } 496// 497// return this ; 498// } 499 500 /** 501 * データの登録エリアに、文字型として値を追加します(データ形式 ARRAYのみ有効)。 502 * 503 * データが、文字型の場合、ダブルコーテーションを付けて登録します。 504 * 指定の可変長文字列は、何の加工も無く、endStr(終端連結時文字)で区切られて、追加されます。 505 * ARRAY形式のみ有効なので、endStrは、',' になります。 506 * データが、null の場合、""(空文字列)と、endStr(終端連結時文字)が、追加されますので、 507 * データの個数は、変わりません。 508 * 最後に必ず、endStr(終端連結時文字)が付きます。 509 * 510 * @param vals データの登録エリアに、文字型として追加する可変長文字列 511 * @return 自分自身 512 * @see #addStr( String,boolean ) 513 * @og.rtnNotNull 514 */ 515 public TagBuffer addStr( final String... vals ) { 516 if( dType == DTYPE.ARY && vals != null ) { 517 for( final String val : vals ) { 518 if( val == null ) { 519 tagBuf.append( "\"\"" ).append( endStr ); 520 } 521 else { 522 tagBuf.append( '"' ).append( val ).append( '"' ).append( endStr ); 523 } 524 } 525 } 526 527 return this ; 528 } 529 530 /** 531 * データの登録エリアに、文字型として値を追加します(データ形式 ARRAYのみ有効)。 532 * 533 * データが、文字型の場合、ダブルコーテーションを付けて登録します。 534 * 指定の文字列は、何の加工も無く、endStr(終端連結時文字)で区切られて、追加されます。 535 * ARRAY形式のみ有効なので、endStrは、',' になります。 536 * データが、null の場合、""(空文字列)と、endStr(終端連結時文字)が、追加されます。 537 * 最後に必ず、endStr(終端連結時文字)が付きます。 538 * 539 * @param val データの登録エリアに、文字型として追加する文字列 540 * @param isUse 追加処理を行うかどうかの判定(true:処理する/false:処理しない) 541 * @return 自分自身 542 * @see #addStr( String... ) 543 * @og.rtnNotNull 544 */ 545 public TagBuffer addStr( final String val , final boolean isUse ) { 546 return isUse ? addStr( val ) : this ; 547 } 548 549// /** 550// * データの登録エリアに、文字型として値を追加します(データ形式 ARRAYのみ有効)。 551// * 552// * データが、文字型の場合、ダブルコーテーションを付けて登録します。 553// * 指定の可変長文字列は、何の加工も無く、endStr(終端連結時文字)で区切られて、追加されます。 554// * ARRAY形式のみ有効なので、endStrは、',' になります。 555// * データが、null の場合、""(空文字列)と、endStr(終端連結時文字)が、追加されますので、 556// * データの個数は、変わりません。 557// * 最後に必ず、endStr(終端連結時文字)が付きます。 558// * 559// * @param vals データの登録エリアに、文字型として追加する文字列配列 560// * @param isUse 追加処理を行うかどうかの判定(true:処理する/false:処理しない) 561// * @return 自分自身 562// * @see #addStr( String... ) 563// * @og.rtnNotNull 564// */ 565// public TagBuffer addStr( final String[] vals , final boolean isUse ) { 566// if( isUse && dType == DTYPE.ARY && vals != null ) { 567// for( final String val : vals ) { 568// if( val == null ) { 569// tagBuf.append( "\"\"" ).append( endStr ); 570// } 571// else { 572// tagBuf.append( '"' ).append( val ).append( '"' ).append( endStr ); 573// } 574// } 575// } 576// 577// return this ; 578// } 579 580 /** 581 * キーと値のセットを、追加します。 582 * 583 * key が nullか、ゼロ文字列の場合は、なにもしません。 584 * val が null の場合は、なにもしません。 585 * val が、ゼロ文字列の場合は、追加します 586 * 587 * val に、ダブルコーテーション(")が含まれている場合は、属性値をシングルコーテーション 588 * でくくります。 589 * 両方含まれている場合は、シングルコーテーションをエスケープ文字(&#39;)に変換します。 590 * 591 * @param key 属性キー(nullか、ゼロ文字列の場合は、なにもしません) 592 * @param val 属性値 (null の場合は、なにもしない) 593 * 594 * @return 自分自身 595 * @see #add( String , String , boolean ) 596 * @og.rtnNotNull 597 */ 598 public TagBuffer add( final String key,final String val ) { 599 return add( key,val,true ); 600 } 601 602 /** 603 * キー配列と値配列のセットを、追加します。 604 * 605 * これは、配列の数だけ、#add( boolean , String , String ) を呼び出して処理を行います。 606 * 個々の配列内のkey,valは、先のメソッドの規約に従います。 607 * キー配列と値配列のサイズが異なる場合や、配列が null の場合は、何もしません。 608 * (エラーではなく何もしないのでご注意ください。) 609 * 610 * @param keys 属性キー配列 611 * @param vals 属性値配列 612 * 613 * @return 自分自身 614 * @see #add( String , String , boolean ) 615 * @og.rtnNotNull 616 */ 617 public TagBuffer add( final String[] keys,final String[] vals ) { 618 if( keys != null && vals != null && keys.length == vals.length ) { 619 for( int i=0; i<keys.length; i++ ) { 620 add( keys[i] , vals[i] , true ); 621 } 622 } 623 624 return this ; 625 } 626 627 /** 628 * キーと値のセットを、追加します(データ形式 ARRAY以外有効)。 629 * 630 * key が nullか、ゼロ文字列の場合は、なにもしません。 631 * val が null の場合は、なにもしません。 632 * val が、ゼロ文字列の場合は、追加します 633 * isUse が、false の場合は、なにもしません。 634 * 635 * val に、ダブルコーテーション(")が含まれている場合は、属性値をシングルコーテーション 636 * でくくります。 637 * 両方含まれている場合は、シングルコーテーションをエスケープ文字(&#39;)に変換します。 638 * 639 * isUse に、false を指定すると、属性は追加しません。これは、if( isUse ) { tagBuf.add( key,val ); } 640 * の様な判定処理を、tagBuf.add( key,val,isUse ); とすることで、StringBuilderの様に、連結して使用できます。 641 * 642 * 値 に、ダブルコーテーション(")が含まれている場合は、属性値をシングルコーテーション 643 * でくくります。 644 * 両方含まれている場合は、シングルコーテーションをエスケープ文字に変換します。 645 * 646 * @param key 属性キー(nullか、ゼロ文字列の場合は、なにもしません) 647 * @param val 属性値 (null の場合は、なにもしない) 648 * @param isUse 属性を追加かどうかを決めるフラグ(true:追加する/false:何もしない) 649 * 650 * @return 自分自身 651 * @see #add( String , String ) 652 * @og.rtnNotNull 653 */ 654 public TagBuffer add( final String key , final String val , final boolean isUse ) { 655 if( isUse && dType != DTYPE.ARY && StringUtil.isNotNull( key ) && val != null ) { 656 if( dType == DTYPE.JSON ) { // JSON の場合は、keyにダブルクオートを付けます。 657 tagBuf.append( '"' ).append( key ).append( '"' ).append( kvsep ); 658 } 659 else { 660 tagBuf.append( key ).append( kvsep ); // TAG,CSS 661 } 662 663 if( dType == DTYPE.CSS ) { // CSS の場合は、属性にダブルクオートは付けません。 664 tagBuf.append( val ); 665 } 666 else { 667 // ダブルコーテーションがある場合は、シングルコーテーションで囲う。 668 if( val.indexOf( '"' ) >= 0 ) { 669 // ただし、シングルコーテーションを含む場合は、エスケープ文字に置き換える。 670 tagBuf.append( '\'' ) 671 .append( val.indexOf( '\'' ) >= 0 ? val.replaceAll( "'","'" ) : val ) 672 .append( '\'' ); 673 } 674 else { 675 tagBuf.append( '"' ).append( val ).append( '"' ); 676 } 677 } 678 tagBuf.append( endStr ); 679 } 680 681 return this ; 682 } 683 684 /** 685 * 整形されたデータ文字列を 作成します。 686 * このメソッドは、startXXX で開始さえたデータ形式に応じて、データ本体のバッファに追記します。 687 * 一連のデータ作成処理は、この、#make() メソッドで終了します。 688 * 689 * その後、startXXX を呼び出すことで、新しいデータ形式の作成を開始できます。 690 * 691 * @return 自分自身 692 * @og.rtnNotNull 693 */ 694 public TagBuffer make() { 695 if( dType == DTYPE.TAG ) { // TAG の場合 696 if( name == null ) { 697 makeBuf.append( tagBuf ); 698 } 699 else { 700 makeBuf.append( '<' ).append( name ).append( ' ' ).append( tagBuf ); 701 702 if( isKaraTag ) { // 空要素の場合 703 // if( bodyBuf.length() == 0 ) { // BODY がない 704 // makeBuf.append( "/>" ); 705 makeBuf.append( '>' ); // XHTML 以外の文法 706 } 707 else { 708 makeBuf.append( '>' ) 709 .append( bodyBuf ) 710 .append( "</" ).append( name ).append( '>' ); 711 } 712 } 713 } 714 else if( dType == DTYPE.CSS ) { // CSS の場合 715 if( name == null ) { 716 makeBuf.append( tagBuf ); 717 } 718 else { 719 makeBuf.append( name ).append( " { " ).append( tagBuf ).append( " } " ); 720 } 721 } 722 else if( dType == DTYPE.JSON ) { // JSON の場合 723 makeBuf.append( " { " ).append( tagBuf ).append( " }, " ); 724 } 725 else if( dType == DTYPE.ARY ) { // ARY の場合 726 makeBuf.append( " [ " ).append( tagBuf ).append( " ], " ); 727 } 728 729 tagBuf.setLength( 0 ); // StringBuilder のクリア 730 bodyBuf.setLength( 0 ); // StringBuilder のクリア 731 732 return this ; 733 } 734 735 /** 736 * TAG形式のデータの、要素部分(BODYの直前まで)の文字列を作成して返します。 737 * 738 * これは、TAG形式で、BODY部分が、別途処理が必要な場合、要素部分まで作成したい場合に使用します。 739 * また、TAG形式以外の場合は、データの登録エリアのバッファをそのまま文字列にして返します。 740 * 741 * この処理を実行すると、内部のすべてのバッファがクリアされます。 742 * 唯一、nameや、区切り文字情報は残っていますので、続きから、BODY の登録や、次のタグの登録が可能です。 743 * 最後は、#toAfter() メソッドを実行すれば、タグとしての形式を保つことが可能です。 744 * 745 * @return 要素部分(BODYの直前まで)の文字列 746 * @see #toAfter() 747 * @og.rtnNotNull 748 */ 749 public String toBefore() { 750 if( dType == DTYPE.TAG && name != null ) { 751 makeBuf.append( '<' ).append( name ).append( ' ' ).append( tagBuf ).append( '>' ); 752 } 753 else { 754 makeBuf.append( tagBuf ); 755 } 756 757 final String rtn = makeBuf.toString(); 758 759 clear(); // すべての内部情報をクリアします。 760 761 return rtn; 762 } 763 764 /** 765 * TAG形式のデータの、BODY+終了タグの文字列を作成して返します。 766 * 767 * 通常は、#toBefore() を呼んだ後に、最後に実行するメソッドです。 768 * この処理を実行すると、内部のすべてのバッファがクリアされます。 769 * 770 * @return 要素部分(BODYの直前まで)の文字列 771 * @see #toBefore() 772 * @og.rtnNotNull 773 */ 774 public String toAfter() { 775 if( dType == DTYPE.TAG && name != null ) { 776 makeBuf.append( bodyBuf ).append( "</" ).append( name ).append( '>' ); 777 } 778 else { 779 makeBuf.append( bodyBuf ); 780 } 781 782 final String rtn = makeBuf.toString(); 783 784 clear(); // すべての内部情報をクリアします。 785 786 return rtn; 787 } 788 789 /** 790 * 内部データのバッファをすべてクリアします。 791 * 792 * 内部データには、データ登録バッファ、データBODY部バッファ、データ本体バッファと 793 * 3種類のバッファを持っています。 794 * 795 * この、3種類のバッファすべてをクリアします。 796 * 797 * @return 自分自身 798 * @og.rtnNotNull 799 */ 800 public TagBuffer clear() { 801 tagBuf.setLength( 0 ); // StringBuilder のクリア 802 bodyBuf.setLength( 0 ); // StringBuilder のクリア 803 makeBuf.setLength( 0 ); // StringBuilder のクリア 804 805 return this ; 806 } 807 808 /** 809 * 内部データの文字列を返します。 810 * 811 * データ本体のバッファを文字列に変換して返します。 812 * これは、#make() か、#tagBefore() を実行後に行います。そうしないと、 813 * データが設定されていません。 814 * この処理を行っても、データはクリアされないため、再び処理を行うことが可能です。 815 * 中間のデータを確認する場合や、最後にデータを取り出す場合に利用します。 816 * 817 * @return データ本体の文字列 818 */ 819 @Override 820 public String toString() { 821 return makeBuf.toString(); 822 } 823 824 /** 825 * 内部データの文字列を返します。 826 * 827 * return tagBuf.make().toString(); と同じ結果を返します。 828 * 829 * これは、TagBuffer クラスとの互換性の為に用意されたメソッドです。 830 * 内部にキャッシュとして持つため、最初に一度実行すると、以降、同じ値しか返されません。 831 * 832 * @return データ本体の文字列 833 */ 834 public String makeTag() { 835 if( cacheTag == null ) { 836 cacheTag = make().toString(); 837 } 838 839 return cacheTag; 840 } 841 842 /** 843 * 行番号付きのタグの 整形された文字列を 作成します。 844 * 845 * 内部データから生成された文字列に含まれる、[I] に、行番号を、 846 * [V] に、設定値を埋め込みます。 847 * 848 * これは、TagBuffer クラスとの互換性の為に用意されたメソッドです。 849 * 内部にキャッシュとして持つため、最初に一度実行すると、以降、同じ値しか返されません。 850 * 851 * 逆に、何度実行しても、内部変数は書き換えられませんので、 852 * 行番号と、設定値を替えて、連続で呼ぶことが可能です。 853 * 854 * @param rowNo 行番号([I] 文字列を変換します) 855 * @param val 設定値([V] 文字列を変換します) 856 * 857 * @return 行番号と設定値が置き換えられた文字列 858 */ 859 public String makeTag( final int rowNo,final String val ) { 860 if( cacheTag == null ) { 861 cacheTag = make().toString(); 862 } 863 864 return cacheTag.replace( "[I]",String.valueOf( rowNo ) ).replace( "[V]",val ); 865 866 // String tag = makeBuf.toString(); 867 // tag = StringUtil.replace( tag,"[I]",String.valueOf( rowNo ) ); 868 // tag = StringUtil.replace( tag,"[V]",val ); 869 870 // return tag ; 871 } 872}