OSDN Git Service

Ver8.5.2.0
[opengion/opengionV8.git] / uap / webapps / gf / src / org / opengion / fukurou / util / XHTMLTag.java
1 /*
2  * Copyright (c) 2009 The openGion Project.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific language
14  * governing permissions and limitations under the License.
15  */
16 package org.opengion.fukurou.util;
17
18 import org.opengion.fukurou.system.OgRuntimeException ;         // 6.4.2.0 (2016/01/29)
19 import org.opengion.fukurou.security.HybsCryptography;
20 import static org.opengion.fukurou.system.HybsConst.CR;                         // 6.1.0.0 (2014/12/26) refactoring
21 import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;      // 6.1.0.0 (2014/12/26) refactoring
22
23 /**
24  * XHTMLTag.java は、共通的に使用されるHTMLタグの生成メソッドを集約したクラスです。
25  *
26  * 全変数/メソッドは、public static final 宣言されています。
27  *
28  * @version  4.0
29  * @author   Kazuhiko Hasegawa
30  * @since    JDK5.0,
31  */
32 public final class XHTMLTag {
33
34         /** URLチェックキー発行用 4.3.7.1 (2009/06/08) */
35         private static final HybsCryptography HYBS_CRYPTOGRAPHY = new HybsCryptography(); // 4.3.7.0 (2009/06/01)
36
37         /**
38          * BUTTON タグの属性リストです。
39          *
40          * @og.rev 5.7.1.0 (2013/12/06) HTML5関連の属性を追加
41          */
42         private static final String[]
43                 BUTTON_KEY =  { "type","name","value","onClick"
44                                                 ,"id","class","lang","dir","title","style","xml:lang"
45                                                 ,"disabled","tabindex","accesskey"
46                                                 ,"onBlur","onFocus","ondblClick","onMouseDown","onMouseUp"
47                                                 ,"onMouseMove","onMouseOut","onMouseOver"
48                                                 // 5.7.1.0 (2013/12/06) HTML5関連の属性
49                                                 ,"autofocus"
50                                         };
51
52         /**
53          * INPUT タグの属性リストです。
54          *
55          * なお、name と value は、この属性リストに含めていません。
56          * これは、#inputAttri( Attributes ) メソッドで、name 属性や value 属性など、
57          * 一般に都度変更されるフィールド以外を、固定値として作成しておくためです。
58          *
59          * @og.rev 5.7.1.0 (2013/12/06) HTML5関連の属性を追加
60          */
61         private static final String[]
62                 INPUT_KEY = { "type","size","maxlength","checked","src"
63                                                 ,"alt","accept","usemap","ismap"
64                                                 ,"id","class","lang","dir","title","style","xml:lang"
65                                                 ,"readonly","disabled","tabindex","accesskey","onClick","onChange"
66                                                 ,"onBlur","onFocus","ondblClick","onMouseDown","onMouseUp"
67                                                 ,"onMouseMove","onMouseOut","onMouseOver"
68                                                 ,"onSelect","onKeydown","onKeypress","onKeyup"
69                                                 // 5.7.1.0 (2013/12/06) HTML5関連の属性
70                                                 ,"autocomplete","autofocus","pattern","placeholder","list","min","max","step","required"
71                                         };
72
73         /**
74          * TEXTAREA タグの属性リストです。
75          *
76          * @og.rev 5.7.1.0 (2013/12/06) HTML5関連の属性を追加
77          */
78         private static final String[]
79                 TEXTAREA_KEY = { "name","rows","cols"
80                                                 ,"id","class","lang","dir","title","style","xml:lang"
81                                                 ,"readonly","disabled","tabindex","accesskey","onClick"
82                                                 ,"onBlur","onFocus","ondblClick","onMouseDown","onMouseUp"
83                                                 ,"onMouseMove","onMouseOut","onMouseOver"
84                                                 ,"onSelect","onKeydown","onKeypress","onKeyup"
85                                                 // 5.7.1.0 (2013/12/06) HTML5関連の属性
86                                                 ,"autofocus","placeholder"
87                                         };
88
89         /**
90          * LINK タグの属性リストです。
91          *
92          * href属性は定義されていません。
93          * これは、UrlEncode 等行う必要がある為、別に処理する必要がある為です。
94          */
95         private static final String[]
96                 LINK_KEY = { "type","name","hreflang","rel","rev","charset"
97                                                 ,"target","shape","coords","onClick"
98                                                 ,"id","class","lang","dir","title","style","xml:lang"
99                                                 ,"tabindex","accesskey"
100                                                 ,"onBlur","onFocus","ondblClick","onMouseDown","onMouseUp"
101                                                 ,"onMouseMove","onMouseOut","onMouseOver"
102                                         };
103
104         /**
105          * SELECT タグの属性リストです。
106          *
107          * name 属性が無いのは、input と同様、name 属性のみ入れ替える事がある為。
108          *
109          * @og.rev 5.7.1.0 (2013/12/06) HTML5関連の属性を追加
110          */
111         private static final String[]
112                 SELECT_KEY = { "size","multiple",
113                                                 "id","class","lang","dir","title","style","xml:lang"
114                                                 ,"disabled","tabindex","onClick","onChange"
115                                                 ,"onBlur","onFocus","ondblClick","onMouseDown","onMouseUp"
116                                                 ,"onMouseMove","onMouseOut","onMouseOver"
117                                                 ,"onSelect","onKeydown","onKeypress","onKeyup"
118                                                 // 5.7.1.0 (2013/12/06) HTML5関連の属性
119                                                 ,"autofocus"
120                                         };
121
122         /**
123          * OPTION タグの属性リストです。
124          *
125          */
126         private static final String[]
127                 OPTION_KEY = { "value","label","selected"
128                                                 ,"id","class","lang","dir","title","style","xml:lang"
129                                                 ,"disabled"
130                                         };
131
132         /**
133          * FRAME タグの属性リストです。
134          *
135          */
136         private static final String[]
137                 FRAME_KEY = { "name","longdesc","marginwidth","marginheight","noresize"
138                                                 ,"scrolling","frameborder"
139                                                 ,"id","class","title","style"
140                                         };
141
142         /**
143          * IFRAME タグの属性リストです。
144          *
145          * @og.rev 5.9.1.2 (2015/10/23) 新規追加
146          */
147         private static final String[]
148                 IFRAME_KEY = { "name","srcdoc","seamless","sandbox","width","height"
149                                                 ,"marginwidth","marginheight","noresize","scrolling","frameborder"
150                                                 ,"id","class","title","style"
151                                         };
152
153         /**
154          * IMAGE タグの属性リストです。
155          *
156          */
157         private static final String[]
158                 IMAGE_KEY = { "src","alt","longdesc","width","height","usemap","ismap","name","onClick"
159                                                 ,"align","border","hspace","vspace"              // この行は非推奨属性です。
160                                                 ,"id","class","title","style","lang","dir","xml:lang"
161                                                 ,"onBlur","onFocus","ondblClick","onMouseDown","onMouseUp"
162                                                 ,"onMouseMove","onMouseOut","onMouseOver"
163                                         };
164
165         /**
166          * FORM タグの属性リストです。
167          *
168          */
169         private static final String[]
170                 FORM_KEY = { "action","method","enctype","accept-charset","accept","name","target"
171                                                 ,"id","class","title","style","lang","dir","xml:lang"
172                                         };
173
174         /**
175          * SPAN タグの属性リストです。
176          *
177          * @og.rev 7.0.3.0 (2019/05/13) SPANの属性リストにonClick等の属性追加
178          */
179         private static final String[]
180                 SPAN_KEY = { "id","class","title","style","lang","dir","xml:lang"
181                                                 ,"tabindex","onClick"                                                                   // 7.0.3.0 (2019/05/13)
182                                                 ,"onFocus","ondblClick","onMouseDown","onMouseUp"               // 7.0.3.0 (2019/05/13)
183                                                 ,"onMouseMove","onMouseOut","onMouseOver"                               // 7.0.3.0 (2019/05/13)
184                                                 ,"autofocus"                                                                                    // 7.0.3.0 (2019/05/13)
185                                         };
186
187         /**
188          * PRE タグの属性リストです。
189          *
190          */
191         private static final String[]
192                 PRE_KEY = { "id","class","title","style","lang","dir","xml:lang" };
193
194         /**
195          *  デフォルトコンストラクターをprivateにして、
196          *  オブジェクトの生成をさせないようにする。
197          *
198          */
199         private XHTMLTag() { }
200
201         /**
202          * ボタンを作成します。
203          *
204          * <button type="形式" name="名前" value="送信文字" オプション・・・ >ラベル</button>
205          *
206          * <table class="plain">
207          *   <caption>Attributes に設定できる属性</caption>
208          *   <tr><td>name="名前"</td><td>オプション</td><td>LabelResource.properties のキー</td></tr>
209          *   <tr><td>type="形式"</td><td>必須</td><td>submit/reset/button</td></tr>
210          *   <tr><td>value="値"</td><td>オプション</td><td>name属性と共に送信される値</td></tr>
211          *   <tr><td>disabled="disabled"</td><td>オプション</td><td>ボタンを利用できない状態にする場合に指定</td></tr>
212          *   <tr><td>tabindex="Tab移動順"</td><td>オプション</td><td>0~32767の範囲で数字で指定(小さい順に移動)</td></tr>
213          *   <tr><td>accesskey="ショートカットキー"</td><td>オプション</td><td>文字セット中の1文字:WindowsであればAltキーと同時使用</td></tr>
214          *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
215          *   <tr><td>body="表示するタグ文字列"</td><td>オリジナル</td><td>画像や文字などボタン上に表示させたいタグの文字列</td></tr>
216          * </table>
217          *
218          * 設定できる属性
219          * 形式は、
220          *  submit  送信(サブミット)
221          *  reset   リセット
222          *  button  汎用ボタン
223          * を指定します。
224          *
225          * ラベルに、HTMLテキスト(強調文字など)をはめ込むことが出来ます。
226          * また、イメージ &lt;img ・・・・&gt; を指定することも可能です。
227          * disabled="disabled" のとき、このボタンのデータはサーバーに送信されません。
228          * 属性群は、タグの中にCSS等で使用できる class="XXX" などの
229          * 汎用属性を自由に登録する事が出来ます。
230          *
231          * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
232          *
233          * @param   attri 属性群
234          *
235          * @return  ボタンタグ文字列
236          * @og.rtnNotNull
237          */
238         public static String button( final Attributes attri ) {
239                 final String checkedType = "|submit|reset|button|";
240
241                 final String type  = attri.get( "type" );
242                 if( checkedType.indexOf( "|" + type + "|" ) < 0 ) {
243                         final String errMsg = "button タイプ設定エラー [" + type + "]";
244                         throw new OgRuntimeException( errMsg );
245                 }
246
247                 String body = attri.get( "body" );
248                 if( body == null ) { body = "" ; }
249
250                 // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
251                 return new TagBuffer( "button" )
252                                         .add(     attri.getAttribute( BUTTON_KEY ) )
253                                         .addBody( body )
254                                         .makeTag();
255         }
256
257         /**
258          * 入力フォームを作成します。
259          *
260          * &lt;input type="text" name="名前" value="送信文字" ....&gt;
261          *
262          * <table class="plain">
263          *   <caption>Attributes に設定できる属性</caption>
264          *   <tr><td>name="名前"</td><td>オプション</td><td>LabelResource.properties のキー</td></tr>
265          *   <tr><td>type="形式"</td><td>必須</td><td>text/password/checkbox/radio/submit/reset/button/image/file/hidden</td></tr>
266          *   <tr><td>value="値"</td><td>オプション</td><td>name属性と共に送信される値</td></tr>
267          *   <tr><td>size="30"</td><td>オプション</td><td>inputタグの大きさ</td></tr>
268          *   <tr><td>maxlength="50"</td><td>オプション</td><td>type属性が「text」,「password」 のときの最大文字数</td></tr>
269          *   <tr><td>checked="checked"</td><td>オプション</td><td>type属性が「checkbox」,「radio」 の場合に選択されている状態にする。</td></tr>
270          *   <tr><td>disabled="disabled"</td><td>オプション</td><td>選択や変更の操作をできない状態にする場合に指定</td></tr>
271          *   <tr><td>accept="MIMEタイプ"</td><td>オプション</td><td>type属性が「file」の場合に処理可能なMIMEタイプを指定</td></tr>
272          *   <tr><td>tabindex="Tab移動順"</td><td>オプション</td><td>0~32767の範囲で数字で指定(小さい順に移動)</td></tr>
273          *   <tr><td>accesskey="ショートカットキー"</td><td>オプション</td><td>文字セット中の1文字:WindowsであればAltキーと同時使用</td></tr>
274          *   <tr><td>src="URL"</td><td>オプション</td><td>type属性が「image」の場合送信ボタンの画像URLを指定</td></tr>
275          *   <tr><td>alt="代替文字列"</td><td>オプション</td><td>type属性が「image」の場合、画像が表示できないときの代替文字列を指定</td></tr>
276          *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
277          *   <tr><td>body="表示するタグ文字列"</td><td>オリジナル</td><td>画像や文字などボタン上に表示させたいタグの文字列</td></tr>
278          *   <tr><td>サポート外</td><td>未実装</td><td>readonly属性、usemap属性、ismap属性、align属性</td></tr>
279          * </table>
280          *
281          * 設定できるtype属性
282          *  text       1行のテキストフィールド
283          *  password   パスワード用テキストフィールド
284          *  checkbox   チェックボックス(複数選択可)
285          *  radio      ラジオボタン(複数選択不可)
286          *  file       送信ファイルの選択
287          *  hidden     表示せずにサーバーに送信する。
288          *  submit     送信(サブミット)
289          *  reset      リセット
290          *  button     汎用ボタン
291          *  image      イメージによる画像ボタン
292          *
293          * HTML5 より、以下のtypeが指定可能になりました。(ブラウザによってサポート状況は異なります。)
294          *  search     検索テキストの入力欄を作成する
295          *  tel        電話番号の入力欄を作成する
296          *  url        URLの入力欄を作成する
297          *  email      メールアドレスの入力欄を作成する
298          *  datetime   UTC(協定世界時)による日時の入力欄を作成する
299          *  date       日付の入力欄を作成する
300          *  month      月の入力欄を作成する
301          *  week       週の入力欄を作成する
302          *  time       時間の入力欄を作成する
303          *  datetime-local    UTC(協定世界時)によらないローカル日時の入力欄を作成する
304          *  number     数値の入力欄を作成する
305          *  range      レンジの入力欄を作成する
306          *  color      色の入力欄を作成する
307          *
308          * ラジオボタン/チェックボックスであらかじめ、チェックをして
309          * おきたい場合は、checked 属性に "checked" を登録します。
310          * ファイルダイアログの場合は、attributesの accept 属性に "MIMEタイプ"
311          * を登録します。
312          * 属性群は、タグの中にCSS等で使用できる class="XXX" などの
313          * 文字を自由に登録する事が出来ます。
314          * CSSでクラスを対応 class="XXXX"
315          * タブで移動順を指定する tabindex="タブ順"
316          * ショートカットキーを割り当てる accesskey="ショートカットキー"
317          *
318          * @param   attri 属性群
319          *
320          * @return  入力フォームタグ文字列
321          * @og.rtnNotNull
322          * @see     #input( Attributes attri,String name,String value,String optAtt )
323          */
324         public static String input( final Attributes attri ) {
325                 final String name     = attri.get( "name" );
326                 final String value    = attri.get( "value" );
327                 final String optAttri = attri.get( "optionAttributes" );
328
329                 return input( attri,name,value,optAttri );
330         }
331
332         /**
333          * 入力フォームを作成します。
334          *
335          * &lt;input type="text" name="名前" value="送信文字" ....&gt;
336          *
337          * <table class="plain">
338          *   <caption>Attributes に設定できる属性</caption>
339          *   <tr><td>name="名前"</td><td>オプション</td><td>LabelResource.properties のキー</td></tr>
340          *   <tr><td>type="形式"</td><td>必須</td><td>text/password/checkbox/radio/submit/reset/button/image/file/hidden</td></tr>
341          *   <tr><td>value="値"</td><td>オプション</td><td>name属性と共に送信される値</td></tr>
342          *   <tr><td>size="30"</td><td>オプション</td><td>inputタグの大きさ</td></tr>
343          *   <tr><td>maxlength="50"</td><td>オプション</td><td>type属性が「text」,「password」 のときの最大文字数</td></tr>
344          *   <tr><td>checked="checked"</td><td>オプション</td><td>type属性が「checkbox」,「radio」 の場合に選択されている状態にする。</td></tr>
345          *   <tr><td>disabled="disabled"</td><td>オプション</td><td>選択や変更の操作をできない状態にする場合に指定</td></tr>
346          *   <tr><td>accept="MIMEタイプ"</td><td>オプション</td><td>type属性が「file」の場合に処理可能なMIMEタイプを指定</td></tr>
347          *   <tr><td>tabindex="Tab移動順"</td><td>オプション</td><td>0~32767の範囲で数字で指定(小さい順に移動)</td></tr>
348          *   <tr><td>accesskey="ショートカットキー"</td><td>オプション</td><td>文字セット中の1文字:WindowsであればAltキーと同時使用</td></tr>
349          *   <tr><td>src="URL"</td><td>オプション</td><td>type属性が「image」の場合送信ボタンの画像URLを指定</td></tr>
350          *   <tr><td>alt="代替文字列"</td><td>オプション</td><td>type属性が「image」の場合、画像が表示できないときの代替文字列を指定</td></tr>
351          *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
352          *   <tr><td>body="表示するタグ文字列"</td><td>オリジナル</td><td>画像や文字などボタン上に表示させたいタグの文字列</td></tr>
353          *   <tr><td>サポート外</td><td>未実装</td><td>readonly属性、usemap属性、ismap属性、align属性</td></tr>
354          * </table>
355          *
356          * 設定できるtype属性
357          *  text       1行のテキストフィールド
358          *  password   パスワード用テキストフィールド
359          *  checkbox   チェックボックス(複数選択可)
360          *  radio      ラジオボタン(複数選択不可)
361          *  file       送信ファイルの選択
362          *  hidden     表示せずにサーバーに送信する。
363          *  submit     送信(サブミット)
364          *  reset      リセット
365          *  button     汎用ボタン
366          *  image      イメージによる画像ボタン
367          *
368          * HTML5 より、以下のtypeが指定可能になりました。(ブラウザによってサポート状況は異なります。)
369          *  search     検索テキストの入力欄を作成する
370          *  tel        電話番号の入力欄を作成する
371          *  url        URLの入力欄を作成する
372          *  email      メールアドレスの入力欄を作成する
373          *  datetime   UTC(協定世界時)による日時の入力欄を作成する
374          *  date       日付の入力欄を作成する
375          *  month      月の入力欄を作成する
376          *  week       週の入力欄を作成する
377          *  time       時間の入力欄を作成する
378          *  datetime-local    UTC(協定世界時)によらないローカル日時の入力欄を作成する
379          *  number     数値の入力欄を作成する
380          *  range      レンジの入力欄を作成する
381          *  color      色の入力欄を作成する
382          *
383          * ラジオボタン/チェックボックスであらかじめ、チェックをして
384          * おきたい場合は、checked 属性に "checked" を登録します。
385          * ファイルダイアログの場合は、attributesの accept 属性に "MIMEタイプ"
386          * を登録します。
387          * 属性群は、タグの中にCSS等で使用できる class="XXX" などの
388          * 文字を自由に登録する事が出来ます。
389          * CSSでクラスを対応 class="XXXX"
390          * タブで移動順を指定する tabindex="タブ順"
391          * ショートカットキーを割り当てる accesskey="ショートカットキー"
392          *
393          * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
394          * @og.rev 6.2.2.2 (2015/04/03) NO_MAXLEN キーの値が、"true" の場合、maxlength を強制削除する。
395          *
396          * @param   attri  属性群
397          * @param   name   名前
398          * @param   value  値
399          * @param   optAttri オプション文字列(タグ属性定義されていない属性の登録用文字列)
400          *
401          * @return  入力フォームタグ文字列
402          * @og.rtnNotNull
403          */
404         public static String input( final Attributes attri,final String name,final String value,final String optAttri ) {
405
406                 // 6.2.2.2 (2015/04/03) NO_MAXLEN キーの値が、"true" の場合、maxlength を強制削除する。
407                 if( "true".equalsIgnoreCase( attri.get( "NO_MAXLEN" ) ) ) {
408                         attri.remove( "maxlength" );
409                 }
410
411                 // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
412                 return new TagBuffer( "input" )
413                                         .add(   "name"  , name  )
414                                         .add(   "value" , value )
415                                         .add(   attri.getAttribute( INPUT_KEY ) )
416                                         .add(   optAttri )
417                                         .makeTag();
418         }
419
420         /**
421          * 入力フォームの属性情報のみの文字列を作成します。
422          * これは、name 属性や value 属性など、一般に都度変更されるフィールド
423          * 以外の固定的な属性情報を、先に作成しておく場合に、使用します。
424          *
425          * @og.rev 6.2.2.2 (2015/04/03) NO_MAXLEN キーの値が、"true" の場合、maxlength を強制削除する。
426          *
427          * @param   attri       属性リスト
428          *
429          * @return  入力フォームタグの属性情報文字列
430          * @og.rtnNotNull
431          */
432         public static String inputAttri( final Attributes attri ) {
433                 // 6.2.2.2 (2015/04/03) NO_MAXLEN キーの値が、"true" の場合、maxlength を強制削除する。
434                 if( "true".equalsIgnoreCase( attri.get( "NO_MAXLEN" ) ) ) {
435                         attri.remove( "maxlength" );
436                 }
437                 return attri.getAttribute( INPUT_KEY );
438         }
439
440         /**
441          * テキストエリアの属性情報のみの文字列を作成します。
442          * これは、name 属性や value 属性など、一般に都度変更されるフィールド
443          * 以外の固定的な属性情報を、先に作成しておく場合に、使用します。
444          *
445          * @param   attri       属性リスト
446          *
447          * @return  テキストエリアの属性情報文字列
448          * @og.rtnNotNull
449          */
450         public static String textareaAttri( final Attributes attri ) {
451                 return attri.getAttribute( TEXTAREA_KEY );
452         }
453
454         /**
455          * プルダウン等のメニューの属性情報のみの文字列を作成します。
456          * これは、name 属性や value 属性など、一般に都度変更されるフィールド
457          * 以外の固定的な属性情報を、先に作成しておく場合に、使用します。
458          *
459          * @param   attri       属性リスト
460          *
461          * @return  プルダウン等のメニューの属性情報文字列
462          * @og.rtnNotNull
463          */
464         public static String selectAttri( final Attributes attri ) {
465                 return attri.getAttribute( SELECT_KEY );
466         }
467
468         /**
469          * HIDDEN フォームを作成します。
470          *
471          * id属性に、name と同じ値が設定されます。
472          *
473          * @og.rev 5.5.4.0 (2012/07/02) ID属性追加
474          *
475          * @param   name  フォームの名前
476          * @param   value 値
477          *
478          * @return  HIDDENフォームタグ文字列
479          * @og.rtnNotNull
480          */
481         public static String hidden( final String name,final String value ) {
482                 return hidden( name,value,name );
483         }
484
485         /**
486          * HIDDEN フォームを作成します。
487          *
488          * @og.rev 5.5.4.0 (2012/07/02) ID属性追加
489          * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
490          *
491          * @param   name  フォームの名前
492          * @param   value 値
493          * @param   id    フォームのID
494          *
495          * @return  HIDDENフォームタグ文字列
496          * @og.rtnNotNull
497          */
498         public static String hidden( final String name, final String value, final String id ) {
499
500                 // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
501                 return new TagBuffer( "input" )
502                                         .add(     "type"  , "hidden"  )
503                                         .add(     "name"  , name  )
504                                         .add(     "value" , value )
505                                         .add(     "id"    , id    )
506                                         .makeTag();
507         }
508
509         /**
510          * テキストエリアを作成します。
511          *
512          * &lt;textarea name="名前" rows="4" cols="40"  ....&gt;送信文字列 &lt;/textarea&gt;
513          *
514          * <table class="plain">
515          *   <caption>Attributes に設定できる属性</caption>
516          *   <tr><td>name="名前"</td><td>オプション</td><td>LabelResource.properties のキー</td></tr>
517          *   <tr><td>rows="行数"</td><td>オプション</td><td>入力フィールドの表示行数</td></tr>
518          *   <tr><td>cols="幅"</td><td>オプション</td><td>入力フィールドの表示幅(文字数)</td></tr>
519          *   <tr><td>disabled="disabled"</td><td>オプション</td><td>選択や変更の操作をできない状態にする場合に指定</td></tr>
520          *   <tr><td>tabindex="Tab移動順"</td><td>オプション</td><td>0~32767の範囲で数字で指定(小さい順に移動)</td></tr>
521          *   <tr><td>accesskey="ショートカットキー"</td><td>オプション</td><td>文字セット中の1文字:WindowsであればAltキーと同時使用</td></tr>
522          *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
523          *   <tr><td>value="値"</td><td>オリジナル</td><td>name属性と共に送信される値</td></tr>
524          *   <tr><td>body="表示するタグ文字列"</td><td>オリジナル</td><td>画像や文字などボタン上に表示させたいタグの文字列</td></tr>
525          *   <tr><td>サポート外</td><td>未実装</td><td>readonly属性</td></tr>
526          * </table>
527          *
528          * 設定できる属性
529          *
530          * 属性群は、タグの中にCSS等で使用できる class="XXX" などの
531          * 文字を自由に登録する事が出来ます。
532          * CSSでクラスを対応 class="XXXX"
533          * タブで移動順を指定する tabindex="タブ順"
534          * ショートカットキーを割り当てる accesskey="ショートカットキー"
535          *
536          * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
537          * @og.rev 8.0.0.0 (2021/07/31) optionAttributes が設定されなかったので、追加
538          *
539          * @param   attri 属性群
540          *
541          * @return  入力フォームタグ文字列
542          * @og.rtnNotNull
543          */
544         public static String textarea( final Attributes attri ) {
545                 String body   = attri.get( "body" );
546                 if( body == null ) { body = "" ; }
547
548                 // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
549                 return new TagBuffer( "textarea" )
550                                         .add(     attri.getAttribute( TEXTAREA_KEY ) )
551                                         .add(     attri.get( "optionAttributes" ) )             // 8.0.0.0 (2021/07/31)
552                                         .addBody( body )
553                                         .makeTag();
554         }
555
556         /**
557          * ページリンクを作成します。
558          *
559          * &lt;A href="URL" target="ターゲット名"&gt;ラベル&lt;/A&gt;
560          *
561          * <table class="plain">
562          *   <caption>Attributes に設定できる属性</caption>
563          *   <tr><td>href="URL"</td><td>必須</td><td>リンク先のURLを指定します。</td></tr>
564          *   <tr><td>charset="文字セット"</td><td>オプション</td><td>リンク先の文字コードセットを指定します。</td></tr>
565          *   <tr><td>hreflang="言語セット"</td><td>オプション</td><td>リンク先の基本となる言語コードを指定します。</td></tr>
566          *   <tr><td>type="MIMEタイプ"</td><td>オプション</td><td>リンク先のMIMEタイプを指定します。</td></tr>
567          *   <tr><td>name="名前"</td><td>オプション</td><td>この要素をリンクの到達点とするための名前を指定します。</td></tr>
568          *   <tr><td>rel="リンクタイプ"</td><td>オプション</td><td>この文書からみた href 属性で指定されるリンク先との関係</td></tr>
569          *   <tr><td>rev="リンクタイプ"</td><td>オプション</td><td>href 属性で指定されるリンク先からみた、この文書との関係</td></tr>
570          *   <tr><td>tabindex="Tab移動順"</td><td>オプション</td><td>0~32767の範囲で数字で指定(小さい順に移動)</td></tr>
571          *   <tr><td>accesskey="ショートカットキー"</td><td>オプション</td><td>文字セット中の1文字:WindowsであればAltキーと同時使用</td></tr>
572          *   <tr><td>target="フレーム名"</td><td>オプション</td><td>リンク先のフレーム名</td></tr>
573          *   <tr><td>body="表示するタグ文字列"</td><td>オリジナル</td><td>画像や文字などをリンクにできます。</td></tr>
574          *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
575          *   <tr><td>サポート外</td><td>未実装</td><td>shape属性、coords属性</td></tr>
576          * </table>
577          *
578          * 設定できる属性
579          *
580          * ラベルなしの場合、href属性の "URL" そのものを付けます。
581          *
582          * target属性のフレーム名は
583          *
584          *  _top        フレームを解除して、リンク先をフレーム全体に表示する。
585          *  _parent リンク先を親フレームに表示する。
586          *  _self   リンク先を自分自身に表示する。
587          *  _blank  新しいウインドウを開いて表示する。
588          *  その他  フレーム作成時の名前で指定可能。
589          *
590          * を指定します。
591          * なしの場合 _self (自分自身)を指定します。
592          *
593          * リンクメール機能
594          * URLを mailto:メールアドレス で設定すれば、メール送信ダイアログを
595          * 開く事が出来ます。
596          * 画像リンク機能
597          * 画像をクリックするリンクは、ラベルの個所に &lt;img&gt;タグを設定します。
598          *
599          * &lt;a href="books.html"&gt;&lt;img src="banner.gif" width="468px" height="60px" alt="関連書籍紹介" border="0"&gt;&lt;/a&gt;
600          *
601          * 属性群は、タグの中にCSS等で使用できる class="XXX" などの
602          * 文字を自由に登録する事が出来ます。
603          * CSSでクラスを対応 class="XXXX"
604          * タブで移動順を指定する tabindex="タブ順"
605          * ショートカットキーを割り当てる accesskey="ショートカットキー"
606          *
607          * @param   attri 属性群
608          *
609          * @return  ページリンクタグ文字列
610          * @og.rtnNotNull
611          */
612         public static String link( final Attributes attri ) {
613                 return link( attri,"" );
614         }
615
616         /**
617          * ページリンクを作成します。
618          *
619          * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
620          *
621          * @param   attri 属性群
622          * @param   urlEncode 文字列   ( ?key1=val1&amp;・・・・ という文字列 無いときは "" )
623          *
624          * @return  ページリンクタグ文字列
625          * @og.rtnNotNull
626          */
627         public static String link( final Attributes attri, final String urlEncode ) {
628                 final String href = attri.get( "href" );
629                 final String url  = addUrlEncode( href,urlEncode );
630                 final String body = StringUtil.nval( attri.get( "body" ), href );
631
632                 // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
633                 return new TagBuffer( "a" )
634                                         .add(     "href"  , url )
635                                         .add(     attri.getAttribute( LINK_KEY ) )
636                                         .addBody( body )                                                        // body が null の場合、href を代わりに出力
637                                         .makeTag();
638         }
639
640         /**
641          * xlink 形式のページリンクを作成します。
642          *
643          * 基本的には、link と同じです。アドレスの指定も、href で指定してください。
644          * 内部的に、xlink:href に変換します。
645          * また、URL引数を、"&amp;" で結合するのではなく、"&amp;amp;" で結合させます。
646          * これは、xlink そのものが、XML上に記述された場合に、XMLのルールで再度パース
647          * される為です。
648          *
649          * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
650          *
651          * @param   attri 属性群
652          * @param   urlEncode 文字列   ( ?key1=val1&amp;・・・・ という文字列 無いときは "" )
653          *
654          * @return  ページリンクタグ文字列
655          * @og.rtnNotNull
656          */
657         public static String xlink( final Attributes attri, final String urlEncode ) {
658                 final String href = attri.get( "href" );
659                 final String url  = addUrlEncode( href,urlEncode,"&amp;" );
660                 final String body = StringUtil.nval( attri.get( "body" ), href );
661
662                 // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
663                 return new TagBuffer( "a" )
664                                         .add(     "xlink:href"  , url )
665                                         .add(     attri.getAttribute( LINK_KEY ) )
666                                         .addBody( body )                                                        // body が null の場合、href を代わりに出力
667                                         .makeTag();
668         }
669
670         /**
671          * メニューを作成します。
672          *
673          * @param   attri 属性群
674          * @param   opt 選択肢(オプション)
675          *
676          * @return  メニュータグ文字列
677          * @og.rtnNotNull
678          */
679         public static String select( final Attributes attri,final Options opt ) {
680                 final String name     = attri.get( "name" );
681                 final String optAttri = attri.get( "optionAttributes" );
682
683                 return select( attri,opt,name,optAttri );
684         }
685
686         /**
687          * メニューを作成します。
688          *
689          * &lt;select size="行数" name="名前" multiple&gt;
690          *   &lt;option value="送信文字1"&gt;コメント&lt;/option&gt;
691          *   &lt;option value="送信文字2"&gt;コメント&lt;/option&gt;
692          *   &lt;option value="送信文字3" selected="selected"&gt;コメント&lt;/option&gt;
693          * &lt;/select&gt;
694          *
695          * <table class="plain">
696          *   <caption>Attributes に設定できる属性</caption>
697          *   <tr><td>name="名前"</td><td>オプション</td><td>LabelResource.properties のキー</td></tr>
698          *   <tr><td>size="行数"</td><td>オプション</td><td>select要素をリストボックスとして表示する場合の行数</td></tr>
699          *   <tr><td>multiple="multiple"</td><td>オプション</td><td>選択肢の中から複数選択出来るようにする。</td></tr>
700          *   <tr><td>disabled="disabled"</td><td>オプション</td><td>選択や変更の操作をできない状態にする場合に指定</td></tr>
701          *   <tr><td>tabindex="Tab移動順"</td><td>オプション</td><td>0~32767の範囲で数字で指定(小さい順に移動)</td></tr>
702          *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
703          * </table>
704          *
705          * 属性群は、タグの中にCSS等で使用できる class="XXX" などの
706          * 文字を自由に登録する事が出来ます。
707          * CSSでクラスを対応 class="XXXX"
708          *
709          * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
710          *
711          * @param   attri       属性群
712          * @param   opt         選択肢(オプション)
713          * @param   name        名前
714          * @param   optAttri オプション属性
715          *
716          * @return  メニュータグ文字列
717          * @og.rtnNotNull
718          */
719         public static String select( final Attributes attri,final Options opt,final String name,final String optAttri ) {
720
721                 // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
722                 return new TagBuffer( "select" )
723                                         .add(     "name"  , name )
724                                         .add(     attri.getAttribute( SELECT_KEY ) )
725                                         .add(     optAttri )
726                                         .addBody( opt.getOption() )
727                                         .makeTag();
728         }
729
730         /**
731          * オプションを作成します。
732          *
733          * &lt;select size="行数" name="名前" multiple&gt;
734          *   &lt;option value="送信文字1"&gt;コメント&lt;/option&gt;
735          *   &lt;option value="送信文字2"&gt;コメント&lt;/option&gt;
736          *   &lt;option value="送信文字3" selected="selected"&gt;コメント&lt;/option&gt;
737          * &lt;/select&gt;
738          *
739          * <table class="plain">
740          *   <caption>Attributes に設定できる属性</caption>
741          *   <tr><td>value="値"</td><td>オプション</td><td>送信する値</td></tr>
742          *   <tr><td>selected="selected"</td><td>オプション</td><td>選択肢をあらかじめ選択された状態にしておく</td></tr>
743          *   <tr><td>disabled="disabled"</td><td>オプション</td><td>選択や変更の操作をできない状態にする場合に指定</td></tr>
744          *   <tr><td>body="表示するタグ文字列"</td><td>オリジナル</td><td>選択肢に表示させたいタグの文字列</td></tr>
745          *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
746          * </table>
747          *
748          * セレクタとは、リストボックスやメニューなどの option引数にセットする
749          * 複数のデータをoptionタグでくるんだものです。
750          *
751          * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
752          *
753          * @param   attri 属性群
754          *
755          * @return  オプションタグ文字列
756          * @og.rtnNotNull
757          * @see         #option( Attributes,String )
758          */
759         public static String option( final Attributes attri ) {
760                 final String body = StringUtil.nval( attri.get( "body" ), " " );        // "No Label" を止めてスペースにする。
761
762                 // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
763                 return new TagBuffer( "option" )
764                                         .add(     attri.getAttribute( OPTION_KEY ) )
765                                         .addBody( body )
766                                         .makeTag();
767         }
768
769         /**
770          * オプションを作成します。
771          *
772          * これは、addKeyLabel引数を考慮した、オプションタグ文字列の作成処理を行います。
773          * true を指定すると、「強制的に」キー:ラベル形式で表示します。
774          * false の場合は、「強制的に」ラベルのみで表示されます。
775          * 初期値の null の場合、指定のままのラベルで作成します。
776          *
777          * @og.rev 6.0.4.0 (2014/11/28) キー:ラベル形式で表示するかどうか。新規追加
778          *
779          * @param   attri               属性群
780          * @param   addKeyLabel true:キー:ラベル形式/false:ラベルのみ/null:指定通り
781          *
782          * @return  オプションタグ文字列
783          * @og.rtnNotNull
784          * @see         #option( Attributes )
785          */
786         public static String option( final Attributes attri , final String addKeyLabel ) {
787                 if( addKeyLabel != null ) {
788                         final String val = attri.get( "value" );
789                         String lbl = attri.get( "label" );
790                         String lblKey = "label" ;
791                         if( lbl == null ) {             // label がなければ、body が表示されるので。
792                                 lbl = attri.get( "body" );
793                                 lblKey = "body" ;
794                         }
795
796                         if( val != null && lbl != null ) {
797                                 final boolean isKeyLbl = "true".equalsIgnoreCase( addKeyLabel );
798                                 final boolean useKey   = lbl.startsWith( val + ':' ) ;  // すでに、ラベルにキーが付与されている。
799
800                                 // addKeyLabel するが、ラベルが付与されていない。
801                                 if( isKeyLbl && !useKey ) {
802                                         attri.set( lblKey , val + ':' + lbl );
803                                 }
804                                 // addKeyLabel しないが、ラベルが付与されている。
805                                 else if( !isKeyLbl && useKey ) {
806                                         attri.set( lblKey , lbl.substring( (val + ':').length() ) );    // ラベルからキー部分を削除する。
807                                 }
808                         }
809                 }
810
811                 return option( attri );
812         }
813
814         /**
815          * フレームタグを作成します。
816          *
817          * &lt;frame marginheight="2px" marginwidth="2px" src="query.jsp" name="QUERY" /&gt;
818          *
819          * <table class="plain">
820          *   <caption>Attributes に設定できる属性</caption>
821          *   <tr><td>src="URL"</td><td>オプション</td><td>フレームの表示先URLを指定します。</td></tr>
822          *   <tr><td>name="フレーム名"</td><td>オプション</td><td>フレームに付ける名前を指定します。</td></tr>
823          *   <tr><td>longdesc="URI"</td><td>オプション</td><td>フレームの詳しい説明のURI</td></tr>
824          *   <tr><td>marginwidth="左右のマージン"</td><td>オプション</td><td>フレーム内の左右のマージンを指定します。</td></tr>
825          *   <tr><td>marginheight="上下のマージン"</td><td>オプション</td><td>フレーム内の上下のマージンを指定します。</td></tr>
826          *   <tr><td>noresize="noresize"</td><td>オプション</td><td>フレームサイズを変更できないようにします。</td></tr>
827          *   <tr><td>scrolling="スクロールの制御"</td><td>オプション</td><td>yes:スクロールバーを表示 no:表示しない auto:必要に応じて表示(デフォルト)</td></tr>
828          *   <tr><td>frameborder="枠の表示"</td><td>オプション</td><td>0:枠を表示しない  1:枠を表示する。(デフォルト)</td></tr>
829          *   <tr><td>keys="引数にセットするキー"</td><td>オプション</td><td>URI の引数にセットするキーを CSV形式でセットします。</td></tr>
830          *   <tr><td>value="引数にセットする値"</td><td>オプション</td><td>URI の引数にセットする値を CSV形式でセットします。</td></tr>
831          *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style</td></tr>
832          * </table>
833          *
834          * 設定できる属性
835          *
836          * scrolling属性
837          *
838          *  yes:常にスクロールバーを表示
839          *  no:常にスクロールバーを表示しない
840          *  auto:必要に応じてスクロールバーを表示(デフォルト)
841          *
842          * を指定します。
843          *
844          * frameborder属性
845          *
846          *  0:枠を表示しない
847          *  1:枠を表示する。(デフォルト)
848          *
849          * を指定します。
850          *
851          * 属性群は、タグの中にCSS等で使用できる class="XXX" などの
852          * 文字を自由に登録する事が出来ます。
853          * CSSでクラスを対応 class="XXXX"
854          *
855          * @param   attri 属性群
856          *
857          * @return  フレームタグ文字列
858          * @og.rtnNotNull
859          */
860         public static String frame( final Attributes attri ) {
861                 return frame( attri,"" );
862         }
863
864         /**
865          * フレームタグを作成します。
866          *
867          * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
868          *
869          * @param   attri 属性群
870          * @param   urlEncode 文字列   ( ?key1=val1&amp;・・・・ という文字列 無いときは "" )
871          *
872          * @return  フレームタグ文字列
873          * @og.rtnNotNull
874          */
875         public static String frame( final Attributes attri,final String urlEncode ) {
876                 // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
877                 return new TagBuffer( "frame" )
878                                         .add(    "src" , addUrlEncode( attri.get( "src" ),urlEncode ) )
879                                         .add(     attri.getAttribute( FRAME_KEY ) )
880                                         .makeTag();
881         }
882
883         /**
884          * インラインフレームタグを作成します。
885          *
886          * @param   attri 属性群
887          * @param   urlEncode 文字列   ( ?key1=val1&amp;・・・・ という文字列 無いときは "" )
888          *
889          * @og.rev 5.9.1.2 (2015/10/23) 新規追加
890          * @og.rev 6.3.9.0 (2015/11/06) TagBuffer を使用するように変更
891          * @og.rev 6.3.9.0 (2015/11/06) TagBuffer を使用するように変更
892          * @og.rev 7.4.2.0 (2021/05/08) optionAttributes 追加
893          *
894          * @return  インラインフレームタグ文字列
895          */
896         public static String iframe( final Attributes attri,final String urlEncode ) {
897
898                 return new TagBuffer( "iframe" )
899                                         .add(    "src" , addUrlEncode( attri.get( "src" ),urlEncode ) )
900                                         .add(     attri.getAttribute( IFRAME_KEY ) )
901                                         .add(     attri.get( "optionAttributes" ) )                                     // 7.4.2.0 (2021/05/08)
902                                         .addBody( "<!-- -->" )  // iframeは自己終了できない
903                                         .makeTag();
904         }
905
906         /**
907          * URLエンコード文字列を作成します。
908          * エンコードすべき文字列が無い場合は、0ストリング("") を返します。
909          * エンコード文字列がある場合は、"?KEY1=VAL1&amp;KEY2=VAL2&amp;・・・" という文字列を
910          * 返します。
911          * つまり、どちらのケースでも、URI に 連結させればよいことになります。
912          *
913          * @param   keys   URLの引数となるキー群
914          * @param   values URLの引数となる値群
915          *
916          * @return  URLエンコード文字列
917          * @og.rtnNotNull
918          */
919         public static String urlEncode( final String keys,final String values ) {
920                 return urlEncode( keys,values,"&" );
921         }
922
923         /**
924          * URLエンコード文字列を作成します。
925          * エンコードすべき文字列が無い場合は、0ストリング("") を返します。
926          * エンコード文字列がある場合は、"?KEY1=VAL1&amp;KEY2=VAL2&amp;・・・" という文字列を
927          * 返します。
928          * つまり、どちらのケースでも、URI に 連結させればよいことになります。
929          *
930          * @param   keys   URLの引数となるキー群
931          * @param   values URLの引数となる値群
932          * @param   join   URLの引数群を連結させる文字列
933          *
934          * @return  URLエンコード文字列
935          * @og.rtnNotNull
936          */
937         public static String urlEncode( final String keys,final String values,final String join ) {
938                 if( keys == null || values == null ) { return ""; }
939
940                 final String[] key = StringUtil.csv2Array( keys );
941                 final String[] val = StringUtil.csv2Array( values );
942
943                 return urlEncode( key,val,join ) ;
944         }
945
946         /**
947          * URLエンコード文字列を作成します。
948          * エンコードすべき文字列が無い場合は、0ストリング("") を返します。
949          * エンコード文字列がある場合は、"?KEY1=VAL1&amp;KEY2=VAL2&amp;・・・" という文字列を
950          * 返します。
951          * つまり、どちらのケースでも、URI に 連結させればよいことになります。
952          *
953          * @param   key   URLの引数となるキーの配列
954          * @param   val   URLの引数となる値の配列
955          *
956          * @return  URLエンコード文字列
957          * @og.rtnNotNull
958          */
959         public static String urlEncode( final String[] key,final String[] val ) {
960                 return urlEncode( key,val,"&" );
961         }
962
963         /**
964          * URLエンコード文字列を作成します。
965          * エンコードすべき文字列が無い場合は、0ストリング("") を返します。
966          * エンコード文字列がある場合は、"?KEY1=VAL1&amp;KEY2=VAL2&amp;・・・" という文字列を
967          * 返します。
968          * つまり、どちらのケースでも、URI に 連結させればよいことになります。
969          *
970          * @og.rev 5.10.15.3 (2019/09/27) fenc追加対応で作成
971          *
972          * @param   key   URLの引数となるキーの配列
973          * @param   val   URLの引数となる値の配列
974          * @param   join   URLの引数群を連結させる文字列
975          *
976          * @return  URLエンコード文字列
977          */
978         public static String urlEncode( final String[] key,final String[] val,final String join ) {
979                 return urlEncode( key, val, join, false);
980         }
981
982         /**
983          * URLエンコード文字列を作成します。
984          * エンコードすべき文字列が無い場合は、0ストリング("") を返します。
985          * エンコード文字列がある場合は、"?KEY1=VAL1&amp;KEY2=VAL2&amp;・・・" という文字列を
986          * 返します。
987          * つまり、どちらのケースでも、URI に 連結させればよいことになります。
988          *
989          * @og.rev 4.3.3.3 (2008/10/22) valに対して副作用を及ぼさないように修正
990          * @og.rev 5.10.12.4 (2019/06/21) keyのURIエンコードを追加
991          * @og.rev 5.10.15.3 (2019/09/27) fencフラグ追加
992          *
993          * @param   key   URLの引数となるキーの配列
994          * @param   val   URLの引数となる値の配列
995          * @param   join   URLの引数群を連結させる文字列
996          * @param   fenc  先頭が[の場合でも強制エンコードするためのフラグ(初期値false)
997          *
998          * @return  URLエンコード文字列
999          * @og.rtnNotNull
1000          */
1001 //      public static String urlEncode( final String[] key,final String[] val,final String join ) {
1002         public static String urlEncode( final String[] key,final String[] val,final String join, final boolean fenc ) {
1003                 if( key == null || key.length == 0 || val == null || val.length == 0 ) {
1004                         return "";
1005                 }
1006                 else if( key.length != val.length ) {
1007                         final String errMsg = "urlEncode のキーとバリューの個数が異なります。" + CR
1008                                                 + "key.length=[" + key.length + "]  val.length=[" + val.length + "]";
1009                         throw new OgRuntimeException( errMsg );
1010                 }
1011
1012                 // 4.3.3.3 (2008/10/22)
1013                 String[] tval = new String[val.length];
1014
1015                 for( int i=0; i<val.length; i++ ) {
1016                         if( key[i] == null || key[i].isEmpty() ) { return ""; }
1017                         if( val[i] == null || val[i].isEmpty() ) { tval[i] = ""; }
1018 //                      else if( val[i].charAt(0) == '[' ) {            // 暫定対応
1019                         else if( val[i].charAt(0) == '[' && !fenc ) {           // 5.10.15.3 (2019/09/27) fenc追加
1020                                 tval[i] = val[i];
1021                         }
1022                         else {
1023                                 tval[i] = StringUtil.urlEncode( val[i] );
1024                         }
1025                 }
1026
1027                 final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
1028
1029                 // 6.0.2.5 (2014/10/31) char を append する。
1030 //              rtn.append( key[0] ).append( '=' ).append( tval[0] );
1031                 rtn.append( StringUtil.urlEncode( key[0]) ).append( '=' ).append( tval[0] );    // 5.10.12.4 (2019/06/21)
1032                 for( int i=1; i<key.length; i++ ) {
1033                         rtn.append( join );
1034 //                      rtn.append( key[i] ).append( '=' ).append( tval[i] );
1035                         rtn.append( StringUtil.urlEncode(key[i]) ).append( '=' ).append( tval[i] );     // 5.10.12.4 (2019/06/21)
1036                 }
1037                 return rtn.toString();
1038         }
1039
1040         /**
1041          * URL文字列に、URLエンコード文字列を連結します。
1042          *
1043          * URL文字列中にすでに "?" 文字が存在する場合は、URLエンコード側の
1044          * 文字列とは、 "&amp;" で連結します。
1045          * 逆に、"?" が存在しなければ、"?" で連結します。
1046          * URLエンコード文字列が null の場合は、連結しません。
1047          *
1048          * @param   url URL文字列
1049          * @param   encode URLエンコード文字列
1050          *
1051          * @return  連結文字列
1052          * @og.rtnNotNull
1053          */
1054         public static String addUrlEncode( final String url,final String encode ) {
1055                 return addUrlEncode( url,encode,"&" );
1056         }
1057
1058         /**
1059          * URL文字列に、URLエンコード文字列を連結します。
1060          *
1061          * URL文字列中にすでに "?" 文字が存在する場合は、URLエンコード側の
1062          * 文字列とは、 join (例 "&amp;" ) で連結します。
1063          * 逆に、"?" が存在しなければ、"?" で連結します。
1064          * URLエンコード文字列が null の場合は、連結しません。
1065          * 連結する、encode 文字列の先頭が、join 文字列の場合、そのまま連結します。
1066          * 先頭が、そうでない場合は、join 文字列で連結します。
1067          * "?" が存在せず、encode 文字列の先頭が、join 文字列の場合は、
1068          * encode 文字列の先頭を取り除いて、"?" で連結します。
1069          *
1070          * 例:
1071          *    ①. abc.html    key1=val1&amp;key2=val2      ⇒ abc.html?key1=val1&amp;key2=val2
1072          *    ②.abc.html   &amp;key1=val1&amp;key2=val2  ⇒ abc.html?key1=val1&amp;key2=val2
1073          *    ③.abc.html?key1=val1    key2=val2          ⇒ abc.html?key1=val1&amp;key2=val2
1074          *    ④.abc.html?key1=val1   &amp;key2=val2      ⇒ abc.html?key1=val1&amp;key2=val2
1075          *
1076          * @og.rev 5.2.1.0 (2010/10/01) urlがnullの場合に、NullPointerExceptionが発生するバグを修正
1077          *
1078          * @param   url URL文字列
1079          * @param   encode URLエンコード文字列
1080          * @param   join   URLの引数群を連結させる文字列
1081          *
1082          * @return  連結文字列
1083          * @og.rtnNotNull
1084          */
1085         public static String addUrlEncode( final String url,final String encode,final String join ) {
1086                 // 5.2.1.0 (2010/10/01) urlがnullの場合に、NullPointerExceptionが発生するバグを修正
1087                 final String tmpUrl = ( url == null ? "" : url );
1088
1089                 if( encode == null || encode.isEmpty() ) { return tmpUrl; }
1090
1091                 final String rtn ;
1092                 if( tmpUrl.indexOf( '?' ) < 0 ) {
1093                         if( encode.startsWith( join ) ) {
1094                                 rtn = tmpUrl + "?" + encode.substring(join.length());           // ②
1095                         }
1096                         else {
1097                                 rtn = tmpUrl + "?" + encode;                                                            // ①
1098                         }
1099                 }
1100                 else {
1101                         if( encode.startsWith( join ) ) {
1102                                 rtn = tmpUrl + encode;                                          // ④
1103                         }
1104                         else {
1105                                 rtn = tmpUrl + join + encode;                           // ③
1106                         }
1107                 }
1108                 return rtn ;
1109         }
1110
1111         /**
1112          * 指定位置に画像を配置します。
1113          *
1114          * alt属性だけ設定されて、title属性が未設定の場合、title属性にもalt属性と同じ値を設定しておきます。
1115          * 本来は、それぞれに役割があるので、同じ値を設定するのは行儀が悪いのですが、
1116          * ブラウザの互換性など、色々な関係で、このように設定しています。
1117          * alt属性   :「その画像が表している”文脈”」を書く
1118          * title属性 :「画像」の補足説明を書く
1119          *
1120          * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
1121          * @og.rev 6.4.2.0 (2016/01/29) alt属性にtitle属性を追記。
1122          *
1123          * @param   attri 属性群
1124          *
1125          * @return  イメージタグ文字列
1126          * @og.rtnNotNull
1127          */
1128         public static String img( final Attributes attri ) {
1129                 // 6.4.2.0 (2016/01/29) title属性がなければ、alt属性を設定しておく。
1130                 final String title = attri.get( "title" );
1131                 if( title == null ) {
1132                         attri.set( "title" , attri.get( "alt" ) );
1133                 }
1134
1135                 // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
1136                 return new TagBuffer( "img" )
1137                                         .add(     attri.getAttribute( IMAGE_KEY ) )
1138                                         .makeTag();
1139         }
1140
1141         /**
1142          * フォームを作成します。
1143          *
1144          * &lt;form action="URI" method="HTTPメソッド" enctype="MIMEタイプ" target="フレーム名" ・・・ &gt;フォーム等&lt;/form&gt;
1145          *
1146          * <table class="plain">
1147          *   <caption>Attributes に設定できる属性</caption>
1148          *   <tr><td>action="URI"</td><td>必須</td><td>送信されたフォームデータを処理するプログラムURI</td></tr>
1149          *   <tr><td>method="HTTPメソッド"</td><td>オプション</td><td>get/post</td></tr>
1150          *   <tr><td>enctype="MIMEタイプ"</td><td>オプション</td><td>フォームデータ送信時のMIMEタイプ</td></tr>
1151          *   <tr><td>accept-charset="文字セット"</td><td>オプション</td><td>データとして受付可能な文字セットの指定</td></tr>
1152          *   <tr><td>accept="MIMEタイプ"</td><td>オプション</td><td>データとして処理可能なMIMEタイプを指定</td></tr>
1153          *   <tr><td>name="名前"</td><td>オプション</td><td>スクリプト等から参照する場合の名前</td></tr>
1154          *   <tr><td>target="フレーム名"</td><td>オプション</td><td>フォームを送信した結果を表示させるフレーム</td></tr>
1155          *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
1156          *   <tr><td>body="フォーム等の文字列"</td><td>必須</td><td>input 等のフォーム要素</td></tr>
1157          * </table>
1158          *
1159          * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
1160          *
1161          * @param   attri 属性群
1162          *
1163          * @return  フォームタグ文字列
1164          * @og.rtnNotNull
1165          */
1166         public static String form( final Attributes attri ) {
1167                 String body   = attri.get( "body" );
1168                 if( body == null ) { body = "" ; }
1169
1170                 // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
1171                 return new TagBuffer( "form" )
1172                                         .add(     attri.getAttribute( FORM_KEY ) )
1173                                         .addBody( body )
1174                                         .makeTag();
1175         }
1176
1177         /**
1178          * 汎用インライン要素(SPAN)を作成します。
1179          *
1180          * &lt;span class="XXXX" ・・・ &gt;テキスト等&lt;/span&gt;
1181          *
1182          * <table class="plain">
1183          *   <caption>Attributes に設定できる属性</caption>
1184          *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
1185          *   <tr><td>body="テキスト等の文字列"</td><td>オプション</td><td>このテキストを修飾します。</td></tr>
1186          * </table>
1187          *
1188          * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
1189          *
1190          * @param   attri 属性群
1191          *
1192          * @return  SPANタグ文字列
1193          * @og.rtnNotNull
1194          */
1195         public static String span( final Attributes attri ) {
1196                 String body   = attri.get( "body" );
1197                 if( body == null ) { body = "" ; }
1198
1199                 // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
1200                 return new TagBuffer( "span" )
1201                                         .add(     attri.getAttribute( SPAN_KEY ) )
1202                                         .add(     attri.get( "optionAttributes" ) )
1203                                         .addBody( body )
1204                                         .makeTag();
1205         }
1206
1207         /**
1208          * 整形済みテキスト(PRE)を作成します。
1209          *
1210          * &lt;pre class="XXXX" ・・・ &gt;テキスト等&lt;/pre&gt;
1211          *
1212          * <table class="plain">
1213          *   <caption>Attributes に設定できる属性</caption>
1214          *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
1215          *   <tr><td>body="テキスト等の文字列"</td><td>オプション</td><td>このテキストを修飾します。</td></tr>
1216          * </table>
1217          *
1218          * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
1219          *
1220          * @param   attri 属性群
1221          *
1222          * @return  PREタグ文字列
1223          * @og.rtnNotNull
1224          */
1225         public static String pre( final Attributes attri ) {
1226                 String body   = attri.get( "body" );
1227                 if( body == null ) { body = "" ; }
1228
1229                 // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
1230                 return new TagBuffer( "pre" )
1231                                         .add(     attri.getAttribute( PRE_KEY ) )
1232                                         .add(     attri.get( "optionAttributes" ) )
1233                                         .addBody( body )
1234                                         .makeTag();
1235         }
1236
1237         /**
1238          * URLチェック用のキーを返します。
1239          *
1240          * 引数に指定されたhrefに対して、時間とユーザーIDを付加した暗号化文字列を
1241          * 引数に追加します。
1242          *
1243          * 暗号化は、org.opengion.fukurou.security.HybsCryptographyを使用します。
1244          * 暗号化を行う文字列のフォーマットは、[href],time=[checkTime],userid=[loginUser]です。
1245          *
1246          * @og.rev 4.3.7.1 (2009/06/08) 新規追加
1247          * @og.rev 4.3.7.4 (2009/07/01) 循環参照を解消
1248          * @og.rev 5.8.8.0 (2015/06/05) キー指定対応で別メソッドに処理を委譲
1249          *
1250          * @param   href チェック対象のURL
1251          * @param   key チェックキーのパラメーターキー
1252          * @param   userid ユーザーID
1253          * @param   time 有効時間
1254          *
1255          * @return  チェックキー
1256          * @og.rtnNotNull
1257          * @see org.opengion.fukurou.security.HybsCryptography
1258          */
1259         public static String addURLCheckKey( final String href, final String key, final String userid, final long time ) {
1260
1261                 return addURLCheckKey( href, key, userid, time, null );
1262         }
1263
1264         /**
1265          * URLチェック用のキーを返します。
1266          *
1267          * 引数に指定されたhrefに対して、時間とユーザーIDを付加した暗号化文字列を
1268          * 引数に追加します。
1269          *
1270          * 暗号化は、org.opengion.fukurou.util.HybsCryptographyを使用します。
1271          * cryptを渡した場合はそのキーを利用して変換をかけますが、NULLの場合は標準キーで暗号化されます。
1272          * 暗号化を行う文字列のフォーマットは、[href],time=[checkTime],userid=[loginUser]です。
1273          *
1274          * @og.rev 5.8.8.0 (2015/06/05) 新規作成
1275          *
1276          * @param   href チェック対象のURL
1277          * @param   key チェックキーのパラメーターキー
1278          * @param   userid ユーザーID
1279          * @param   time 有効時間
1280          * @param       crypt 暗号化クラス
1281          *
1282          * @return  チェックキー
1283          * @see org.opengion.fukurou.security.HybsCryptography
1284          */
1285         public static String addURLCheckKey( final String href, final String key, final String userid, final long time, final HybsCryptography crypt ) {
1286                 // 6.4.2.1 (2016/02/05) PMD refactoring. Prefer StringBuffer over += for concatenating strings
1287                 final String orgChKey = href + ",time=" + time + ",userid=" + userid;
1288
1289                 final String checkKey = key + "=" +
1290                                                 crypt == null ? HYBS_CRYPTOGRAPHY.encrypt( orgChKey )
1291                                                                           : crypt.encrypt( orgChKey ) ;
1292
1293                 return addUrlEncode( href , checkKey );
1294         }
1295
1296         /**
1297          * Aタグの文字列を解析して、href属性にURLチェック用の暗号化文字列を付加した形で、
1298          * Aタグを再構築し、返します。
1299          *
1300          * @og.rev 4.3.7.1 (2009/06/08) 新規追加
1301          * @og.rev 4.3.7.4 (2009/07/01) 循環参照を解消
1302          * @og.rev 5.8.8.0 (2015/06/05) キー指定対応で別メソッドに処理を委譲
1303          *
1304          * @param   tag Aタグ文字列
1305          * @param   key チェックキーのパラメーターキー
1306          * @param   userid ユーザーID
1307          * @param   time 有効時間
1308          *
1309          * @return  URLチェックキーが付加されたAタグ文字列
1310          * @og.rtnNotNull
1311          */
1312         public static String embedURLCheckKey( final String tag, final String key, final String userid, final long time  ) {
1313                 return embedURLCheckKey( tag, key, userid, time, null  );
1314         }
1315
1316         /**
1317          * Aタグの文字列を解析して、href属性にURLチェック用の暗号化文字列を付加した形で、
1318          * Aタグを再構築し、返します。
1319          *
1320          * @og.rev 5.8.8.0 (2015/06/05) 新規作成
1321          *
1322          * @param   tag Aタグ文字列
1323          * @param   key チェックキーのパラメーターキー
1324          * @param   userid ユーザーID
1325          * @param   time 有効時間
1326          * @param       crypt 暗号化クラス
1327          *
1328          * @return  URLチェックキーが付加されたAタグ文字列
1329          */
1330         public static String embedURLCheckKey( final String tag, final String key, final String userid, final long time, final HybsCryptography crypt ) {
1331                 String rtn = tag;
1332                 final int hrefStr = rtn.indexOf( "href=\"" );
1333                 if( hrefStr >= 0 ) {
1334                         final int hrefEnd = rtn.indexOf( "\"",hrefStr + 6 );
1335                         if( hrefEnd >= 0 ) {
1336                                 String href = rtn.substring( hrefStr + 6, hrefEnd );
1337                                 href = XHTMLTag.addURLCheckKey( href, key, userid, time, crypt );
1338                                 rtn = rtn.substring( 0,  hrefStr ) + "href=\"" + href + rtn.substring( hrefEnd );
1339                         }
1340                 }
1341                 return rtn;
1342         }
1343 }