    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         * &lt;button type="形式" name="名前" value="送信文字" オプション･･･ &gt;ラベル&lt;/button&gt;
    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>文字セット中の１文字：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>文字セット中の１文字：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       １行のテキストフィールド
    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>文字セット中の１文字：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       １行のテキストフィールド
    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>文字セット中の１文字：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="ＵＲＬ" 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>文字セット中の１文字：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="送信文字１"&gt;コメント&lt;/option&gt;
    683         *   &lt;option value="送信文字２"&gt;コメント&lt;/option&gt;
    684         *   &lt;option value="送信文字３" 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="送信文字１"&gt;コメント&lt;/option&gt;
    727         *   &lt;option value="送信文字２"&gt;コメント&lt;/option&gt;
    728         *   &lt;option value="送信文字３" 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         * エンコードすべき文字列が無い場合は, ０ストリング("") を返します。
    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         * エンコードすべき文字列が無い場合は, ０ストリング("") を返します。
    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         * エンコードすべき文字列が無い場合は, ０ストリング("") を返します。
    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         * エンコードすべき文字列が無い場合は, ０ストリング("") を返します。
    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>送信されたフォームデータを処理するプログラムＵＲＩ</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}