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