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