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