    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         *
    538         * @param   attri 属性群
    539         *
    540         * @return  入力フォームタグ文字列
    541         * @og.rtnNotNull
    542         */
    543        public static String textarea( final Attributes attri ) {
    544                String body   = attri.get( "body" );
    545                if( body == null ) { body = "" ; }
    546
    547                // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    548                return new TagBuffer( "textarea" )
    549                                        .add(     attri.getAttribute( TEXTAREA_KEY ) )
    550                                        .addBody( body )
    551                                        .makeTag();
    552        }
    553
    554        /**
    555         * ページリンクを作成します。
    556         *
    557         * &lt;A href="ＵＲＬ" target="ターゲット名"&gt;ラベル&lt;/A&gt;
    558         *
    559         * <table class="plain">
    560         *   <caption>Attributes に設定できる属性</caption>
    561         *   <tr><td>href="URL"</td><td>必須</td><td>リンク先のURLを指定します。</td></tr>
    562         *   <tr><td>charset="文字セット"</td><td>オプション</td><td>リンク先の文字コードセットを指定します。</td></tr>
    563         *   <tr><td>hreflang="言語セット"</td><td>オプション</td><td>リンク先の基本となる言語コードを指定します。</td></tr>
    564         *   <tr><td>type="MIMEタイプ"</td><td>オプション</td><td>リンク先のMIMEタイプを指定します。</td></tr>
    565         *   <tr><td>name="名前"</td><td>オプション</td><td>この要素をリンクの到達点とするための名前を指定します。</td></tr>
    566         *   <tr><td>rel="リンクタイプ"</td><td>オプション</td><td>この文書からみた href 属性で指定されるリンク先との関係</td></tr>
    567         *   <tr><td>rev="リンクタイプ"</td><td>オプション</td><td>href 属性で指定されるリンク先からみた、この文書との関係</td></tr>
    568         *   <tr><td>tabindex="Tab移動順"</td><td>オプション</td><td>0～32767の範囲で数字で指定(小さい順に移動)</td></tr>
    569         *   <tr><td>accesskey="ショートカットキー"</td><td>オプション</td><td>文字セット中の１文字：WindowsであればAltキーと同時使用</td></tr>
    570         *   <tr><td>target="フレーム名"</td><td>オプション</td><td>リンク先のフレーム名</td></tr>
    571         *   <tr><td>body="表示するタグ文字列"</td><td>オリジナル</td><td>画像や文字などをリンクにできます。</td></tr>
    572         *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
    573         *   <tr><td>サポート外</td><td>未実装</td><td>shape属性、coords属性</td></tr>
    574         * </table>
    575         *
    576         * 設定できる属性
    577         *
    578         * ラベルなしの場合, href属性の "URL" そのものを付けます。
    579         *
    580         * target属性のフレーム名は
    581         *
    582         *  _top        フレームを解除して,リンク先をフレーム全体に表示する。
    583         *  _parent リンク先を親フレームに表示する。
    584         *  _self   リンク先を自分自身に表示する。
    585         *  _blank  新しいウインドウを開いて，表示する。
    586         *  その他  フレーム作成時の名前で指定可能。
    587         *
    588         * を指定します。
    589         * なしの場合 _self (自分自身)を指定します。
    590         *
    591         * リンクメール機能
    592         * URLを，mailto:メールアドレス で設定すれば,メール送信ダイアログを
    593         * 開く事が出来ます。
    594         * 画像リンク機能
    595         * 画像をクリックするリンクは，ラベルの個所に &lt;img&gt;タグを設定します。
    596         *
    597         * &lt;a href="books.html"&gt;&lt;img src="banner.gif" width="468px" height="60px" alt="関連書籍紹介" border="0"&gt;&lt;/a&gt;
    598         *
    599         * 属性群は,タグの中に,CSS等で使用できる class="XXX" などの
    600         * 文字を自由に登録する事が出来ます。
    601         * CSSでクラスを対応 class="XXXX"
    602         * タブで移動順を指定する tabindex="タブ順"
    603         * ショートカットキーを割り当てる accesskey="ショートカットキー"
    604         *
    605         * @param   attri 属性群
    606         *
    607         * @return  ページリンクタグ文字列
    608         * @og.rtnNotNull
    609         */
    610        public static String link( final Attributes attri ) {
    611                return link( attri,"" );
    612        }
    613
    614        /**
    615         * ページリンクを作成します。
    616         *
    617         * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    618         *
    619         * @param   attri 属性群
    620         * @param   urlEncode 文字列   ( ?key1=val1&amp;････ という文字列 無いときは "" )
    621         *
    622         * @return  ページリンクタグ文字列
    623         * @og.rtnNotNull
    624         */
    625        public static String link( final Attributes attri, final String urlEncode ) {
    626                final String href = attri.get( "href" );
    627                final String url  = addUrlEncode( href,urlEncode );
    628                final String body = StringUtil.nval( attri.get( "body" ), href );
    629
    630                // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    631                return new TagBuffer( "a" )
    632                                        .add(     "href"  , url )
    633                                        .add(     attri.getAttribute( LINK_KEY ) )
    634                                        .addBody( body )                                                        // body が null の場合、href を代わりに出力
    635                                        .makeTag();
    636        }
    637
    638        /**
    639         * xlink 形式のページリンクを作成します。
    640         *
    641         * 基本的には、link と同じです。アドレスの指定も、href で指定してください。
    642         * 内部的に、xlink:href に変換します。
    643         * また、URL引数を、"&amp;" で結合するのではなく、"&amp;amp;" で結合させます。
    644         * これは、xlink そのものが、XML上に記述された場合に、XMLのルールで再度パース
    645         * される為です。
    646         *
    647         * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    648         *
    649         * @param   attri 属性群
    650         * @param   urlEncode 文字列   ( ?key1=val1&amp;････ という文字列 無いときは "" )
    651         *
    652         * @return  ページリンクタグ文字列
    653         * @og.rtnNotNull
    654         */
    655        public static String xlink( final Attributes attri, final String urlEncode ) {
    656                final String href = attri.get( "href" );
    657                final String url  = addUrlEncode( href,urlEncode,"&amp;" );
    658                final String body = StringUtil.nval( attri.get( "body" ), href );
    659
    660                // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    661                return new TagBuffer( "a" )
    662                                        .add(     "xlink:href"  , url )
    663                                        .add(     attri.getAttribute( LINK_KEY ) )
    664                                        .addBody( body )                                                        // body が null の場合、href を代わりに出力
    665                                        .makeTag();
    666        }
    667
    668        /**
    669         * メニューを作成します。
    670         *
    671         * @param   attri 属性群
    672         * @param   opt 選択肢(オプション)
    673         *
    674         * @return  メニュータグ文字列
    675         * @og.rtnNotNull
    676         */
    677        public static String select( final Attributes attri,final Options opt ) {
    678                final String name     = attri.get( "name" );
    679                final String optAttri = attri.get( "optionAttributes" );
    680
    681                return select( attri,opt,name,optAttri );
    682        }
    683
    684        /**
    685         * メニューを作成します。
    686         *
    687         * &lt;select size="行数" name="名前" multiple&gt;
    688         *   &lt;option value="送信文字１"&gt;コメント&lt;/option&gt;
    689         *   &lt;option value="送信文字２"&gt;コメント&lt;/option&gt;
    690         *   &lt;option value="送信文字３" selected="selected"&gt;コメント&lt;/option&gt;
    691         * &lt;/select&gt;
    692         *
    693         * <table class="plain">
    694         *   <caption>Attributes に設定できる属性</caption>
    695         *   <tr><td>name="名前"</td><td>オプション</td><td>LabelResource.properties のキー</td></tr>
    696         *   <tr><td>size="行数"</td><td>オプション</td><td>select要素をリストボックスとして表示する場合の行数</td></tr>
    697         *   <tr><td>multiple="multiple"</td><td>オプション</td><td>選択肢の中から複数選択出来るようにする。</td></tr>
    698         *   <tr><td>disabled="disabled"</td><td>オプション</td><td>選択や変更の操作をできない状態にする場合に指定</td></tr>
    699         *   <tr><td>tabindex="Tab移動順"</td><td>オプション</td><td>0～32767の範囲で数字で指定(小さい順に移動)</td></tr>
    700         *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
    701         * </table>
    702         *
    703         * 属性群は,タグの中に,CSS等で使用できる class="XXX" などの
    704         * 文字を自由に登録する事が出来ます。
    705         * CSSでクラスを対応 class="XXXX"
    706         *
    707         * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    708         *
    709         * @param   attri       属性群
    710         * @param   opt         選択肢(オプション)
    711         * @param   name        名前
    712         * @param   optAttri オプション属性
    713         *
    714         * @return  メニュータグ文字列
    715         * @og.rtnNotNull
    716         */
    717        public static String select( final Attributes attri,final Options opt,final String name,final String optAttri ) {
    718
    719                // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    720                return new TagBuffer( "select" )
    721                                        .add(     "name"  , name )
    722                                        .add(     attri.getAttribute( SELECT_KEY ) )
    723                                        .add(     optAttri )
    724                                        .addBody( opt.getOption() )
    725                                        .makeTag();
    726        }
    727
    728        /**
    729         * オプションを作成します。
    730         *
    731         * &lt;select size="行数" name="名前" multiple&gt;
    732         *   &lt;option value="送信文字１"&gt;コメント&lt;/option&gt;
    733         *   &lt;option value="送信文字２"&gt;コメント&lt;/option&gt;
    734         *   &lt;option value="送信文字３" selected="selected"&gt;コメント&lt;/option&gt;
    735         * &lt;/select&gt;
    736         *
    737         * <table class="plain">
    738         *   <caption>Attributes に設定できる属性</caption>
    739         *   <tr><td>value="値"</td><td>オプション</td><td>送信する値</td></tr>
    740         *   <tr><td>selected="selected"</td><td>オプション</td><td>選択肢をあらかじめ選択された状態にしておく</td></tr>
    741         *   <tr><td>disabled="disabled"</td><td>オプション</td><td>選択や変更の操作をできない状態にする場合に指定</td></tr>
    742         *   <tr><td>body="表示するタグ文字列"</td><td>オリジナル</td><td>選択肢に表示させたいタグの文字列</td></tr>
    743         *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
    744         * </table>
    745         *
    746         * セレクタとは，リストボックスやメニューなどの option引数にセットする
    747         * 複数のデータをoptionタグでくるんだものです。
    748         *
    749         * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    750         *
    751         * @param   attri 属性群
    752         *
    753         * @return  オプションタグ文字列
    754         * @og.rtnNotNull
    755         * @see         #option( Attributes,String )
    756         */
    757        public static String option( final Attributes attri ) {
    758                final String body = StringUtil.nval( attri.get( "body" ), " " );        // "No Label" を止めてスペースにする。
    759
    760                // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    761                return new TagBuffer( "option" )
    762                                        .add(     attri.getAttribute( OPTION_KEY ) )
    763                                        .addBody( body )
    764                                        .makeTag();
    765        }
    766
    767        /**
    768         * オプションを作成します。
    769         *
    770         * これは、addKeyLabel引数を考慮した、オプションタグ文字列の作成処理を行います。
    771         * true を指定すると、「強制的に」キー:ラベル形式で表示します。
    772         * false の場合は、「強制的に」ラベルのみで表示されます。
    773         * 初期値の null の場合、指定のままのラベルで作成します。
    774         *
    775         * @og.rev 6.0.4.0 (2014/11/28) キー:ラベル形式で表示するかどうか。新規追加
    776         *
    777         * @param   attri               属性群
    778         * @param   addKeyLabel true:キー:ラベル形式/false:ラベルのみ/null:指定通り
    779         *
    780         * @return  オプションタグ文字列
    781         * @og.rtnNotNull
    782         * @see         #option( Attributes )
    783         */
    784        public static String option( final Attributes attri , final String addKeyLabel ) {
    785                if( addKeyLabel != null ) {
    786                        final String val = attri.get( "value" );
    787                        String lbl = attri.get( "label" );
    788                        String lblKey = "label" ;
    789                        if( lbl == null ) {             // label がなければ、body が表示されるので。
    790                                lbl = attri.get( "body" );
    791                                lblKey = "body" ;
    792                        }
    793
    794                        if( val != null && lbl != null ) {
    795                                final boolean isKeyLbl = "true".equalsIgnoreCase( addKeyLabel );
    796                                final boolean useKey   = lbl.startsWith( val + ':' ) ;  // すでに、ラベルにキーが付与されている。
    797
    798                                // addKeyLabel するが、ラベルが付与されていない。
    799                                if( isKeyLbl && !useKey ) {
    800                                        attri.set( lblKey , val + ':' + lbl );
    801                                }
    802                                // addKeyLabel しないが、ラベルが付与されている。
    803                                else if( !isKeyLbl && useKey ) {
    804                                        attri.set( lblKey , lbl.substring( (val + ':').length() ) );    // ラベルからキー部分を削除する。
    805                                }
    806                        }
    807                }
    808
    809                return option( attri );
    810        }
    811
    812        /**
    813         * フレームタグを作成します。
    814         *
    815         * &lt;frame marginheight="2px" marginwidth="2px" src="query.jsp" name="QUERY" /&gt;
    816         *
    817         * <table class="plain">
    818         *   <caption>Attributes に設定できる属性</caption>
    819         *   <tr><td>src="URL"</td><td>オプション</td><td>フレームの表示先URLを指定します。</td></tr>
    820         *   <tr><td>name="フレーム名"</td><td>オプション</td><td>フレームに付ける名前を指定します。</td></tr>
    821         *   <tr><td>longdesc="URI"</td><td>オプション</td><td>フレームの詳しい説明のURI</td></tr>
    822         *   <tr><td>marginwidth="左右のマージン"</td><td>オプション</td><td>フレーム内の左右のマージンを指定します。</td></tr>
    823         *   <tr><td>marginheight="上下のマージン"</td><td>オプション</td><td>フレーム内の上下のマージンを指定します。</td></tr>
    824         *   <tr><td>noresize="noresize"</td><td>オプション</td><td>フレームサイズを変更できないようにします。</td></tr>
    825         *   <tr><td>scrolling="スクロールの制御"</td><td>オプション</td><td>yes:スクロールバーを表示 no:表示しない auto:必要に応じて表示(デフォルト)</td></tr>
    826         *   <tr><td>frameborder="枠の表示"</td><td>オプション</td><td>0:枠を表示しない  1:枠を表示する。(デフォルト)</td></tr>
    827         *   <tr><td>keys="引数にセットするキー"</td><td>オプション</td><td>URI の引数にセットするキーを CSV形式でセットします。</td></tr>
    828         *   <tr><td>value="引数にセットする値"</td><td>オプション</td><td>URI の引数にセットする値を CSV形式でセットします。</td></tr>
    829         *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style</td></tr>
    830         * </table>
    831         *
    832         * 設定できる属性
    833         *
    834         * scrolling属性
    835         *
    836         *  yes:常にスクロールバーを表示
    837         *  no:常にスクロールバーを表示しない
    838         *  auto:必要に応じてスクロールバーを表示(デフォルト)
    839         *
    840         * を指定します。
    841         *
    842         * frameborder属性
    843         *
    844         *  0:枠を表示しない
    845         *  1:枠を表示する。(デフォルト)
    846         *
    847         * を指定します。
    848         *
    849         * 属性群は,タグの中に,CSS等で使用できる class="XXX" などの
    850         * 文字を自由に登録する事が出来ます。
    851         * CSSでクラスを対応 class="XXXX"
    852         *
    853         * @param   attri 属性群
    854         *
    855         * @return  フレームタグ文字列
    856         * @og.rtnNotNull
    857         */
    858        public static String frame( final Attributes attri ) {
    859                return frame( attri,"" );
    860        }
    861
    862        /**
    863         * フレームタグを作成します。
    864         *
    865         * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    866         *
    867         * @param   attri 属性群
    868         * @param   urlEncode 文字列   ( ?key1=val1&amp;････ という文字列 無いときは "" )
    869         *
    870         * @return  フレームタグ文字列
    871         * @og.rtnNotNull
    872         */
    873        public static String frame( final Attributes attri,final String urlEncode ) {
    874                // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    875                return new TagBuffer( "frame" )
    876                                        .add(    "src" , addUrlEncode( attri.get( "src" ),urlEncode ) )
    877                                        .add(     attri.getAttribute( FRAME_KEY ) )
    878                                        .makeTag();
    879        }
    880
    881        /**
    882         * インラインフレームタグを作成します。
    883         *
    884         * @param   attri 属性群
    885         * @param   urlEncode 文字列   ( ?key1=val1&amp;････ という文字列 無いときは "" )
    886         *
    887         * @og.rev 5.9.1.2 (2015/10/23) 新規追加
    888         * @og.rev 6.3.9.0 (2015/11/06) TagBuffer を使用するように変更
    889         *
    890         * @return  インラインフレームタグ文字列
    891         */
    892        public static String iframe( final Attributes attri,final String urlEncode ) {
    893
    894                return new TagBuffer( "iframe" )
    895                                        .add(    "src" , addUrlEncode( attri.get( "src" ),urlEncode ) )
    896                                        .add(     attri.getAttribute( IFRAME_KEY ) )
    897                                        .addBody( "<!-- -->" )  // iframeは自己終了できない
    898                                        .makeTag();
    899        }
    900
    901        /**
    902         * URLエンコード文字列を作成します。
    903         * エンコードすべき文字列が無い場合は, ０ストリング("") を返します。
    904         * エンコード文字列がある場合は, "?KEY1=VAL1&amp;KEY2=VAL2&amp;･･･" という文字列を
    905         * 返します。
    906         * つまり、どちらのケースでも、URI に 連結させればよいことになります。
    907         *
    908         * @param   keys   URLの引数となるキー群
    909         * @param   values URLの引数となる値群
    910         *
    911         * @return  URLエンコード文字列
    912         * @og.rtnNotNull
    913         */
    914        public static String urlEncode( final String keys,final String values ) {
    915                return urlEncode( keys,values,"&" );
    916        }
    917
    918        /**
    919         * URLエンコード文字列を作成します。
    920         * エンコードすべき文字列が無い場合は, ０ストリング("") を返します。
    921         * エンコード文字列がある場合は, "?KEY1=VAL1&amp;KEY2=VAL2&amp;･･･" という文字列を
    922         * 返します。
    923         * つまり、どちらのケースでも、URI に 連結させればよいことになります。
    924         *
    925         * @param   keys   URLの引数となるキー群
    926         * @param   values URLの引数となる値群
    927         * @param   join   URLの引数群を連結させる文字列
    928         *
    929         * @return  URLエンコード文字列
    930         * @og.rtnNotNull
    931         */
    932        public static String urlEncode( final String keys,final String values,final String join ) {
    933                if( keys == null || values == null ) { return ""; }
    934
    935                final String[] key = StringUtil.csv2Array( keys );
    936                final String[] val = StringUtil.csv2Array( values );
    937
    938                return urlEncode( key,val,join ) ;
    939        }
    940
    941        /**
    942         * URLエンコード文字列を作成します。
    943         * エンコードすべき文字列が無い場合は, ０ストリング("") を返します。
    944         * エンコード文字列がある場合は, "?KEY1=VAL1&amp;KEY2=VAL2&amp;･･･" という文字列を
    945         * 返します。
    946         * つまり、どちらのケースでも、URI に 連結させればよいことになります。
    947         *
    948         * @param   key   URLの引数となるキーの配列
    949         * @param   val   URLの引数となる値の配列
    950         *
    951         * @return  URLエンコード文字列
    952         * @og.rtnNotNull
    953         */
    954        public static String urlEncode( final String[] key,final String[] val ) {
    955                return urlEncode( key,val,"&" );
    956        }
    957
    958        /**
    959         * URLエンコード文字列を作成します。
    960         * エンコードすべき文字列が無い場合は, ０ストリング("") を返します。
    961         * エンコード文字列がある場合は, "?KEY1=VAL1&amp;KEY2=VAL2&amp;･･･" という文字列を
    962         * 返します。
    963         * つまり、どちらのケースでも、URI に 連結させればよいことになります。
    964         *
    965         * @og.rev 5.10.15.3 (2019/09/27) fenc追加対応で作成
    966         *
    967         * @param   key   URLの引数となるキーの配列
    968         * @param   val   URLの引数となる値の配列
    969         * @param   join   URLの引数群を連結させる文字列
    970         *
    971         * @return  URLエンコード文字列
    972         */
    973        public static String urlEncode( final String[] key,final String[] val,final String join ) {
    974                return urlEncode( key, val, join, false);
    975        }
    976
    977        /**
    978         * URLエンコード文字列を作成します。
    979         * エンコードすべき文字列が無い場合は, ０ストリング("") を返します。
    980         * エンコード文字列がある場合は, "?KEY1=VAL1&amp;KEY2=VAL2&amp;･･･" という文字列を
    981         * 返します。
    982         * つまり、どちらのケースでも、URI に 連結させればよいことになります。
    983         *
    984         * @og.rev 4.3.3.3 (2008/10/22) valに対して副作用を及ぼさないように修正
    985         * @og.rev 5.10.12.4 (2019/06/21) keyのURIエンコードを追加
    986         * @og.rev 5.10.15.3 (2019/09/27) fencフラグ追加
    987         *
    988         * @param   key   URLの引数となるキーの配列
    989         * @param   val   URLの引数となる値の配列
    990         * @param   join   URLの引数群を連結させる文字列
    991         * @param   fenc  先頭が[の場合でも強制エンコードするためのフラグ(初期値false)
    992         *
    993         * @return  URLエンコード文字列
    994         * @og.rtnNotNull
    995         */
    996//      public static String urlEncode( final String[] key,final String[] val,final String join ) {
    997        public static String urlEncode( final String[] key,final String[] val,final String join, final boolean fenc ) {
    998                if( key == null || key.length == 0 || val == null || val.length == 0 ) {
    999                        return "";
    1000                }
    1001                else if( key.length != val.length ) {
    1002                        final String errMsg = "urlEncode のキーとバリューの個数が異なります。" + CR
    1003                                                + "key.length=[" + key.length + "]  val.length=[" + val.length + "]";
    1004                        throw new OgRuntimeException( errMsg );
    1005                }
    1006
    1007                // 4.3.3.3 (2008/10/22)
    1008                String[] tval = new String[val.length];
    1009
    1010                for( int i=0; i<val.length; i++ ) {
    1011                        if( key[i] == null || key[i].isEmpty() ) { return ""; }
    1012                        if( val[i] == null || val[i].isEmpty() ) { tval[i] = ""; }
    1013//                      else if( val[i].charAt(0) == '[' ) {            // 暫定対応
    1014                        else if( val[i].charAt(0) == '[' && !fenc ) {           // 5.10.15.3 (2019/09/27) fenc追加
    1015                                tval[i] = val[i];
    1016                        }
    1017                        else {
    1018                                tval[i] = StringUtil.urlEncode( val[i] );
    1019                        }
    1020                }
    1021
    1022                final StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
    1023
    1024                // 6.0.2.5 (2014/10/31) char を append する。
    1025//              rtn.append( key[0] ).append( '=' ).append( tval[0] );
    1026                rtn.append( StringUtil.urlEncode( key[0]) ).append( '=' ).append( tval[0] );    // 5.10.12.4 (2019/06/21)
    1027                for( int i=1; i<key.length; i++ ) {
    1028                        rtn.append( join );
    1029//                      rtn.append( key[i] ).append( '=' ).append( tval[i] );
    1030                        rtn.append( StringUtil.urlEncode(key[i]) ).append( '=' ).append( tval[i] );     // 5.10.12.4 (2019/06/21)
    1031                }
    1032                return rtn.toString();
    1033        }
    1034
    1035        /**
    1036         * URL文字列に、URLエンコード文字列を連結します。
    1037         *
    1038         * URL文字列中にすでに "?" 文字が存在する場合は、URLエンコード側の
    1039         * 文字列とは、 "&amp;" で連結します。
    1040         * 逆に、"?" が存在しなければ、"?" で連結します。
    1041         * URLエンコード文字列が null の場合は、連結しません。
    1042         *
    1043         * @param   url URL文字列
    1044         * @param   encode URLエンコード文字列
    1045         *
    1046         * @return  連結文字列
    1047         * @og.rtnNotNull
    1048         */
    1049        public static String addUrlEncode( final String url,final String encode ) {
    1050                return addUrlEncode( url,encode,"&" );
    1051        }
    1052
    1053        /**
    1054         * URL文字列に、URLエンコード文字列を連結します。
    1055         *
    1056         * URL文字列中にすでに "?" 文字が存在する場合は、URLエンコード側の
    1057         * 文字列とは、 join (例 "&amp;" ) で連結します。
    1058         * 逆に、"?" が存在しなければ、"?" で連結します。
    1059         * URLエンコード文字列が null の場合は、連結しません。
    1060         * 連結する、encode 文字列の先頭が、join 文字列の場合、そのまま連結します。
    1061         * 先頭が、そうでない場合は、join 文字列で連結します。
    1062         * "?" が存在せず、encode 文字列の先頭が、join 文字列の場合は、、
    1063         * encode 文字列の先頭を取り除いて、"?" で連結します。
    1064         *
    1065         * 例：
    1066         *    ①. abc.html    key1=val1&amp;key2=val2      ⇒ abc.html?key1=val1&amp;key2=val2
    1067         *    ②．abc.html   &amp;key1=val1&amp;key2=val2  ⇒ abc.html?key1=val1&amp;key2=val2
    1068         *    ③．abc.html?key1=val1    key2=val2          ⇒ abc.html?key1=val1&amp;key2=val2
    1069         *    ④．abc.html?key1=val1   &amp;key2=val2      ⇒ abc.html?key1=val1&amp;key2=val2
    1070         *
    1071         * @og.rev 5.2.1.0 (2010/10/01) urlがnullの場合に、NullPointerExceptionが発生するバグを修正
    1072         *
    1073         * @param   url URL文字列
    1074         * @param   encode URLエンコード文字列
    1075         * @param   join   URLの引数群を連結させる文字列
    1076         *
    1077         * @return  連結文字列
    1078         * @og.rtnNotNull
    1079         */
    1080        public static String addUrlEncode( final String url,final String encode,final String join ) {
    1081                // 5.2.1.0 (2010/10/01) urlがnullの場合に、NullPointerExceptionが発生するバグを修正
    1082                final String tmpUrl = ( url == null ? "" : url );
    1083
    1084                if( encode == null || encode.isEmpty() ) { return tmpUrl; }
    1085
    1086                final String rtn ;
    1087                if( tmpUrl.indexOf( '?' ) < 0 ) {
    1088                        if( encode.startsWith( join ) ) {
    1089                                rtn = tmpUrl + "?" + encode.substring(join.length());           // ②
    1090                        }
    1091                        else {
    1092                                rtn = tmpUrl + "?" + encode;                                                            // ①
    1093                        }
    1094                }
    1095                else {
    1096                        if( encode.startsWith( join ) ) {
    1097                                rtn = tmpUrl + encode;                                          // ④
    1098                        }
    1099                        else {
    1100                                rtn = tmpUrl + join + encode;                           // ③
    1101                        }
    1102                }
    1103                return rtn ;
    1104        }
    1105
    1106        /**
    1107         * 指定位置に画像を配置します。
    1108         *
    1109         * alt属性だけ設定されて、title属性が未設定の場合、title属性にもalt属性と同じ値を設定しておきます。
    1110         * 本来は、それぞれに役割があるので、同じ値を設定するのは行儀が悪いのですが、
    1111         * ブラウザの互換性など、色々な関係で、このように設定しています。
    1112         * alt属性   ：「その画像が表している”文脈”」を書く
    1113         * title属性 ：「画像」の補足説明を書く
    1114         *
    1115         * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    1116         * @og.rev 6.4.2.0 (2016/01/29) alt属性にtitle属性を追記。
    1117         *
    1118         * @param   attri 属性群
    1119         *
    1120         * @return  イメージタグ文字列
    1121         * @og.rtnNotNull
    1122         */
    1123        public static String img( final Attributes attri ) {
    1124                // 6.4.2.0 (2016/01/29) title属性がなければ、alt属性を設定しておく。
    1125                final String title = attri.get( "title" );
    1126                if( title == null ) {
    1127                        attri.set( "title" , attri.get( "alt" ) );
    1128                }
    1129
    1130                // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    1131                return new TagBuffer( "img" )
    1132                                        .add(     attri.getAttribute( IMAGE_KEY ) )
    1133                                        .makeTag();
    1134        }
    1135
    1136        /**
    1137         * フォームを作成します。
    1138         *
    1139         * &lt;form action="URI" method="HTTPメソッド" enctype="MIMEタイプ" target="フレーム名" ･･･ &gt;フォーム等&lt;/form&gt;
    1140         *
    1141         * <table class="plain">
    1142         *   <caption>Attributes に設定できる属性</caption>
    1143         *   <tr><td>action="URI"</td><td>必須</td><td>送信されたフォームデータを処理するプログラムＵＲＩ</td></tr>
    1144         *   <tr><td>method="HTTPメソッド"</td><td>オプション</td><td>get/post</td></tr>
    1145         *   <tr><td>enctype="MIMEタイプ"</td><td>オプション</td><td>フォームデータ送信時のMIMEタイプ</td></tr>
    1146         *   <tr><td>accept-charset="文字セット"</td><td>オプション</td><td>データとして受付可能な文字セットの指定</td></tr>
    1147         *   <tr><td>accept="MIMEタイプ"</td><td>オプション</td><td>データとして処理可能なMIMEタイプを指定</td></tr>
    1148         *   <tr><td>name="名前"</td><td>オプション</td><td>スクリプト等から参照する場合の名前</td></tr>
    1149         *   <tr><td>target="フレーム名"</td><td>オプション</td><td>フォームを送信した結果を表示させるフレーム</td></tr>
    1150         *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
    1151         *   <tr><td>body="フォーム等の文字列"</td><td>必須</td><td>input 等のフォーム要素</td></tr>
    1152         * </table>
    1153         *
    1154         * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    1155         *
    1156         * @param   attri 属性群
    1157         *
    1158         * @return  フォームタグ文字列
    1159         * @og.rtnNotNull
    1160         */
    1161        public static String form( final Attributes attri ) {
    1162                String body   = attri.get( "body" );
    1163                if( body == null ) { body = "" ; }
    1164
    1165                // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    1166                return new TagBuffer( "form" )
    1167                                        .add(     attri.getAttribute( FORM_KEY ) )
    1168                                        .addBody( body )
    1169                                        .makeTag();
    1170        }
    1171
    1172        /**
    1173         * 汎用インライン要素(SPAN)を作成します。
    1174         *
    1175         * &lt;span class="XXXX" ･･･ &gt;テキスト等&lt;/span&gt;
    1176         *
    1177         * <table class="plain">
    1178         *   <caption>Attributes に設定できる属性</caption>
    1179         *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
    1180         *   <tr><td>body="テキスト等の文字列"</td><td>オプション</td><td>このテキストを修飾します。</td></tr>
    1181         * </table>
    1182         *
    1183         * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    1184         *
    1185         * @param   attri 属性群
    1186         *
    1187         * @return  SPANタグ文字列
    1188         * @og.rtnNotNull
    1189         */
    1190        public static String span( final Attributes attri ) {
    1191                String body   = attri.get( "body" );
    1192                if( body == null ) { body = "" ; }
    1193
    1194                // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    1195                return new TagBuffer( "span" )
    1196                                        .add(     attri.getAttribute( SPAN_KEY ) )
    1197                                        .add(     attri.get( "optionAttributes" ) )
    1198                                        .addBody( body )
    1199                                        .makeTag();
    1200        }
    1201
    1202        /**
    1203         * 整形済みテキスト(PRE)を作成します。
    1204         *
    1205         * &lt;pre class="XXXX" ･･･ &gt;テキスト等&lt;/pre&gt;
    1206         *
    1207         * <table class="plain">
    1208         *   <caption>Attributes に設定できる属性</caption>
    1209         *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
    1210         *   <tr><td>body="テキスト等の文字列"</td><td>オプション</td><td>このテキストを修飾します。</td></tr>
    1211         * </table>
    1212         *
    1213         * @og.rev 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    1214         *
    1215         * @param   attri 属性群
    1216         *
    1217         * @return  PREタグ文字列
    1218         * @og.rtnNotNull
    1219         */
    1220        public static String pre( final Attributes attri ) {
    1221                String body   = attri.get( "body" );
    1222                if( body == null ) { body = "" ; }
    1223
    1224                // 6.2.0.0 (2015/02/27) TagBuffer を使用するように変更。
    1225                return new TagBuffer( "pre" )
    1226                                        .add(     attri.getAttribute( PRE_KEY ) )
    1227                                        .add(     attri.get( "optionAttributes" ) )
    1228                                        .addBody( body )
    1229                                        .makeTag();
    1230        }
    1231
    1232        /**
    1233         * URLチェック用のキーを返します。
    1234         *
    1235         * 引数に指定されたhrefに対して、時間とユーザーIDを付加した暗号化文字列を
    1236         * 引数に追加します。
    1237         *
    1238         * 暗号化は、org.opengion.fukurou.security.HybsCryptographyを使用します。
    1239         * 暗号化を行う文字列のフォーマットは、[href],time=[checkTime],userid=[loginUser]です。
    1240         *
    1241         * @og.rev 4.3.7.1 (2009/06/08) 新規追加
    1242         * @og.rev 4.3.7.4 (2009/07/01) 循環参照を解消
    1243         * @og.rev 5.8.8.0 (2015/06/05) キー指定対応で別メソッドに処理を委譲
    1244         *
    1245         * @param   href チェック対象のURL
    1246         * @param   key チェックキーのパラメーターキー
    1247         * @param   userid ユーザーID
    1248         * @param   time 有効時間
    1249         *
    1250         * @return  チェックキー
    1251         * @og.rtnNotNull
    1252         * @see org.opengion.fukurou.security.HybsCryptography
    1253         */
    1254        public static String addURLCheckKey( final String href, final String key, final String userid, final long time ) {
    1255
    1256                return addURLCheckKey( href, key, userid, time, null );
    1257        }
    1258
    1259        /**
    1260         * URLチェック用のキーを返します。
    1261         *
    1262         * 引数に指定されたhrefに対して、時間とユーザーIDを付加した暗号化文字列を
    1263         * 引数に追加します。
    1264         *
    1265         * 暗号化は、org.opengion.fukurou.util.HybsCryptographyを使用します。
    1266         * cryptを渡した場合はそのキーを利用して変換をかけますが、NULLの場合は標準キーで暗号化されます。
    1267         * 暗号化を行う文字列のフォーマットは、[href],time=[checkTime],userid=[loginUser]です。
    1268         *
    1269         * @og.rev 5.8.8.0 (2015/06/05) 新規作成
    1270         *
    1271         * @param   href チェック対象のURL
    1272         * @param   key チェックキーのパラメーターキー
    1273         * @param   userid ユーザーID
    1274         * @param   time 有効時間
    1275         * @param       crypt 暗号化クラス
    1276         *
    1277         * @return  チェックキー
    1278         * @see org.opengion.fukurou.security.HybsCryptography
    1279         */
    1280        public static String addURLCheckKey( final String href, final String key, final String userid, final long time, final HybsCryptography crypt ) {
    1281                // 6.4.2.1 (2016/02/05) PMD refactoring. Prefer StringBuffer over += for concatenating strings
    1282                final String orgChKey = href + ",time=" + time + ",userid=" + userid;
    1283
    1284                final String checkKey = key + "=" +
    1285                                                crypt == null ? HYBS_CRYPTOGRAPHY.encrypt( orgChKey )
    1286                                                                          : crypt.encrypt( orgChKey ) ;
    1287
    1288                return addUrlEncode( href , checkKey );
    1289        }
    1290
    1291        /**
    1292         * Aタグの文字列を解析して、href属性にURLチェック用の暗号化文字列を付加した形で、
    1293         * Aタグを再構築し、返します。
    1294         *
    1295         * @og.rev 4.3.7.1 (2009/06/08) 新規追加
    1296         * @og.rev 4.3.7.4 (2009/07/01) 循環参照を解消
    1297         * @og.rev 5.8.8.0 (2015/06/05) キー指定対応で別メソッドに処理を委譲
    1298         *
    1299         * @param   tag Aタグ文字列
    1300         * @param   key チェックキーのパラメーターキー
    1301         * @param   userid ユーザーID
    1302         * @param   time 有効時間
    1303         *
    1304         * @return  URLチェックキーが付加されたAタグ文字列
    1305         * @og.rtnNotNull
    1306         */
    1307        public static String embedURLCheckKey( final String tag, final String key, final String userid, final long time  ) {
    1308                return embedURLCheckKey( tag, key, userid, time, null  );
    1309        }
    1310
    1311        /**
    1312         * Aタグの文字列を解析して、href属性にURLチェック用の暗号化文字列を付加した形で、
    1313         * Aタグを再構築し、返します。
    1314         *
    1315         * @og.rev 5.8.8.0 (2015/06/05) 新規作成
    1316         *
    1317         * @param   tag Aタグ文字列
    1318         * @param   key チェックキーのパラメーターキー
    1319         * @param   userid ユーザーID
    1320         * @param   time 有効時間
    1321         * @param       crypt 暗号化クラス
    1322         *
    1323         * @return  URLチェックキーが付加されたAタグ文字列
    1324         */
    1325        public static String embedURLCheckKey( final String tag, final String key, final String userid, final long time, final HybsCryptography crypt ) {
    1326                String rtn = tag;
    1327                final int hrefStr = rtn.indexOf( "href=\"" );
    1328                if( hrefStr >= 0 ) {
    1329                        final int hrefEnd = rtn.indexOf( "\"",hrefStr + 6 );
    1330                        if( hrefEnd >= 0 ) {
    1331                                String href = rtn.substring( hrefStr + 6, hrefEnd );
    1332                                href = XHTMLTag.addURLCheckKey( href, key, userid, time, crypt );
    1333                                rtn = rtn.substring( 0,  hrefStr ) + "href=\"" + href + rtn.substring( hrefEnd );
    1334                        }
    1335                }
    1336                return rtn;
    1337        }
    1338}