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.security.HybsCryptography;
019
020/**
021 * XHTMLTag.java は、共通的に使用されるHTMLタグの生成メソッドを集約したクラスです。
022 *
023 * 全変数/メソッドは、public static final 宣言されています。
024 *
025 * @version  4.0
026 * @author   Kazuhiko Hasegawa
027 * @since    JDK5.0,
028 */
029public final class XHTMLTag {
030
031        /** システム依存の改行記号をセットします。 */
032        public static final String CR = System.getProperty("line.separator");
033
034        /** バッファの初期容量を通常より若干多い目に設定します。(50)  */
035        public static final int BUFFER_SMALL = 50;
036
037        /** バッファの初期容量を通常より多い目に設定します。(200)  */
038        public static final int BUFFER_MIDDLE = 200;
039
040        /** バッファの初期容量を通常より大幅に多い目に設定します。(500)  */
041        public static final int BUFFER_LARGE  = 500;
042
043        /** URLチェックキー発行用 4.3.7.1 (2009/06/08) */
044        private static final HybsCryptography HYBS_CRYPTOGRAPHY = new HybsCryptography(); // 4.3.7.0 (2009/06/01)
045
046        /**
047         * BUTTON タグの属性リストです。
048         *
049         * @og.rev 5.7.1.0 (2013/12/06) HTML5関連の属性を追加
050         */
051        private static final String[]
052                BUTTON_KEY =  { "type","name","value","onClick"
053                                                ,"id","class","lang","dir","title","style","xml:lang"
054                                                ,"disabled","tabindex","accesskey"
055                                                ,"onBlur","onFocus","ondblClick","onMouseDown","onMouseUp"
056                                                ,"onMouseMove","onMouseOut","onMouseOver"
057                                                // 5.7.1.0 (2013/12/06) HTML5関連の属性
058                                                ,"autofocus"
059                                        };
060
061        /**
062         * INPUT タグの属性リストです。
063         *
064         * @og.rev 5.7.1.0 (2013/12/06) HTML5関連の属性を追加
065         */
066        private static final String[]
067                INPUT_KEY = { "type","size","maxlength","checked","src"
068                                                ,"alt","accept","usemap","ismap"
069                                                ,"id","class","lang","dir","title","style","xml:lang"
070                                                ,"readonly","disabled","tabindex","accesskey","onClick","onChange"
071                                                ,"onBlur","onFocus","ondblClick","onMouseDown","onMouseUp"
072                                                ,"onMouseMove","onMouseOut","onMouseOver"
073                                                ,"onSelect","onKeydown","onKeypress","onKeyup"
074                                                // 5.7.1.0 (2013/12/06) HTML5関連の属性
075                                                ,"autocomplete","autofocus","pattern","placeholder","list","min","max","step","required"
076                                        };
077
078        /**
079         * TEXTAREA タグの属性リストです。
080         *
081         * @og.rev 5.7.1.0 (2013/12/06) HTML5関連の属性を追加
082         */
083        private static final String[]
084                TEXTAREA_KEY = { "name","rows","cols"
085                                                ,"id","class","lang","dir","title","style","xml:lang"
086                                                ,"readonly","disabled","tabindex","accesskey","onClick"
087                                                ,"onBlur","onFocus","ondblClick","onMouseDown","onMouseUp"
088                                                ,"onMouseMove","onMouseOut","onMouseOver"
089                                                ,"onSelect","onKeydown","onKeypress","onKeyup"
090                                                // 5.7.1.0 (2013/12/06) HTML5関連の属性
091                                                ,"autofocus","placeholder"
092                                        };
093
094        /**
095         * LINK タグの属性リストです。
096         *
097         */
098        private static final String[]
099                LINK_KEY = { "type","name","hreflang","rel","rev","charset"
100                                                ,"target","shape","coords","onClick"
101                                                ,"id","class","lang","dir","title","style","xml:lang"
102                                                ,"tabindex","accesskey"
103                                                ,"onBlur","onFocus","ondblClick","onMouseDown","onMouseUp"
104                                                ,"onMouseMove","onMouseOut","onMouseOver"
105                                        };
106
107        /**
108         * SELECT タグの属性リストです。
109         *
110         * @og.rev 5.7.1.0 (2013/12/06) HTML5関連の属性を追加
111         */
112        private static final String[]
113                SELECT_KEY = { "size","multiple",
114                                                "id","class","lang","dir","title","style","xml:lang"
115                                                ,"disabled","tabindex","onClick","onChange"
116                                                ,"onBlur","onFocus","ondblClick","onMouseDown","onMouseUp"
117                                                ,"onMouseMove","onMouseOut","onMouseOver"
118                                                ,"onSelect","onKeydown","onKeypress","onKeyup"
119                                                // 5.7.1.0 (2013/12/06) HTML5関連の属性
120                                                ,"autofocus"
121                                        };
122
123        /**
124         * OPTION タグの属性リストです。
125         *
126         */
127        private static final String[]
128                OPTION_KEY = { "value","label","selected"
129                                                ,"id","class","lang","dir","title","style","xml:lang"
130                                                ,"disabled"
131                                        };
132
133        /**
134         * FRAME タグの属性リストです。
135         *
136         */
137        private static final String[]
138                FRAME_KEY = { "name","longdesc","marginwidth","marginheight","noresize"
139                                                ,"scrolling","frameborder"
140                                                ,"id","class","title","style"
141                                        };
142
143        /**
144         * IMAGE タグの属性リストです。
145         *
146         */
147        private static final String[]
148                IMAGE_KEY = { "src","alt","longdesc","width","height","usemap","ismap","name","onClick"
149                                                ,"align","border","hspace","vspace"              // この行は非推奨属性です。
150                                                ,"id","class","title","style","lang","dir","xml:lang"
151                                                ,"onBlur","onFocus","ondblClick","onMouseDown","onMouseUp"
152                                                ,"onMouseMove","onMouseOut","onMouseOver"
153                                        };
154
155        /**
156         * FORM タグの属性リストです。
157         *
158         */
159        private static final String[]
160                FORM_KEY = { "action","method","enctype","accept-charset","accept","name","target"
161                                                ,"id","class","title","style","lang","dir","xml:lang"
162                                        };
163
164        /**
165         * SPAN タグの属性リストです。
166         *
167         */
168        private static final String[]
169                SPAN_KEY = { "id","class","title","style","lang","dir","xml:lang" };
170
171        /**
172         * PRE タグの属性リストです。
173         *
174         */
175        private static final String[]
176                PRE_KEY = { "id","class","title","style","lang","dir","xml:lang" };
177
178        /**
179         *  デフォルトコンストラクターをprivateにして、
180         *  オブジェクトの生成をさせないようにする。
181         *
182         */
183        private XHTMLTag() { }
184
185        /**
186         * ボタンを作成します。
187         *
188         * <button type="形式" name="名前" value="送信文字" オプション・・・ >ラベル</button>
189         *
190         * <table border="1" frame="box" rules="all" >
191         *   <caption>Attributes に設定できる属性</caption>
192         *   <tr><td>name="名前"</td><td>オプション</td><td>LabelResource.properties のキー</td></tr>
193         *   <tr><td>type="形式"</td><td>必須</td><td>submit/reset/button</td></tr>
194         *   <tr><td>value="値"</td><td>オプション</td><td>name属性と共に送信される値</td></tr>
195         *   <tr><td>disabled="disabled"</td><td>オプション</td><td>ボタンを利用できない状態にする場合に指定</td></tr>
196         *   <tr><td>tabindex="Tab移動順"</td><td>オプション</td><td>0~32767の範囲で数字で指定(小さい順に移動)</td></tr>
197         *   <tr><td>accesskey="ショートカットキー"</td><td>オプション</td><td>文字セット中の1文字:WindowsであればAltキーと同時使用</td></tr>
198         *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
199         *   <tr><td>body="表示するタグ文字列"</td><td>オリジナル</td><td>画像や文字などボタン上に表示させたいタグの文字列</td></tr>
200         * </table>
201         *
202         * 設定できる属性
203         * 形式は,
204         *  submit  送信(サブミット)
205         *  reset   リセット
206         *  button  汎用ボタン
207         * を指定します。
208         *
209         * ラベルに,HTMLテキスト(強調文字など)をはめ込むことが出来ます。
210         * また,イメージ &lt;img ・・・・&gt; を指定することも,可能です。
211         * disabled="disabled" のとき,このボタンのデータはサーバーに送信されません。
212         * 属性群は,タグの中に,CSS等で使用できる class="XXX" などの
213         * 汎用属性を自由に登録する事が出来ます。
214         *
215         * @param   attri 属性群
216         *
217         * @return  ボタンタグ文字列
218         */
219        public static String button( final Attributes attri ) {
220                String   checkedType = "|submit|reset|button|";
221
222                String type  = attri.get( "type" );
223                if( checkedType.indexOf( "|" + type + "|" ) < 0 ) {
224                        String errMsg = "button タイプ設定エラー [" + type + "]";
225                        throw new RuntimeException( errMsg );
226                }
227
228                String values = attri.getAttribute( BUTTON_KEY );
229                String body   = attri.get( "body" );
230                if( body == null ) { body = "" ; }
231
232                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
233                rtn.append("<button ");
234                rtn.append( values );
235                rtn.append( ">" );
236                rtn.append( body );
237                rtn.append("</button>");
238
239                return rtn.toString();
240        }
241
242        /**
243         * 入力フォームを作成します。
244         *
245         * @param   attri 属性群
246         *
247         * @return  入力フォームタグ文字列
248         * @see     #input( Attributes attri,String name,String value,String optAtt )
249         */
250        public static String input( final Attributes attri ) {
251                String name     = attri.get( "name" );
252                String value    = attri.get( "value" );
253                String optAttri = attri.get( "optionAttributes" );
254
255                return input( attri,name,value,optAttri );
256        }
257
258        /**
259         * 入力フォームを作成します。
260         *
261         * &lt;input type="text" name="名前" value="送信文字" ....&gt;
262         *
263         * <table border="1" frame="box" rules="all" >
264         *   <caption>Attributes に設定できる属性</caption>
265         *   <tr><td>name="名前"</td><td>オプション</td><td>LabelResource.properties のキー</td></tr>
266         *   <tr><td>type="形式"</td><td>必須</td><td>text/password/checkbox/radio/submit/reset/button/image/file/hidden</td></tr>
267         *   <tr><td>value="値"</td><td>オプション</td><td>name属性と共に送信される値</td></tr>
268         *   <tr><td>size="30"</td><td>オプション</td><td>inputタグの大きさ</td></tr>
269         *   <tr><td>maxlength="50"</td><td>オプション</td><td>type属性が「text」,「password」 のときの最大文字数</td></tr>
270         *   <tr><td>checked="checked"</td><td>オプション</td><td>type属性が「checkbox」,「radio」 の場合に選択されている状態にする。</td></tr>
271         *   <tr><td>disabled="disabled"</td><td>オプション</td><td>選択や変更の操作をできない状態にする場合に指定</td></tr>
272         *   <tr><td>accept="MIMEタイプ"</td><td>オプション</td><td>type属性が「file」の場合に処理可能なMIMEタイプを指定</td></tr>
273         *   <tr><td>tabindex="Tab移動順"</td><td>オプション</td><td>0~32767の範囲で数字で指定(小さい順に移動)</td></tr>
274         *   <tr><td>accesskey="ショートカットキー"</td><td>オプション</td><td>文字セット中の1文字:WindowsであればAltキーと同時使用</td></tr>
275         *   <tr><td>src="URL"</td><td>オプション</td><td>type属性が「image」の場合送信ボタンの画像URLを指定</td></tr>
276         *   <tr><td>alt="代替文字列"</td><td>オプション</td><td>type属性が「image」の場合、画像が表示できないときの代替文字列を指定</td></tr>
277         *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
278         *   <tr><td>body="表示するタグ文字列"</td><td>オリジナル</td><td>画像や文字などボタン上に表示させたいタグの文字列</td></tr>
279         *   <tr><td>サポート外</td><td>未実装</td><td>readonly属性、usemap属性、ismap属性、align属性</td></tr>
280         * </table>
281         *
282         * 設定できる属性
283         * 形式は,
284         *  text       1行のテキストフィールド
285         *  password   パスワード用テキストフィールド
286         *  checkbox   チェックボックス(複数選択可)
287         *  radio      ラジオボタン(複数選択不可)
288         *  submit     送信(サブミット)
289         *  reset      リセット
290         *  button     汎用ボタン
291         *  image      イメージによる画像ボタン
292         *  file       送信ファイルの選択
293         *  hidden     表示せずにサーバーに送信する。
294         * を指定します。
295         *
296         * ラジオボタン/チェックボックスであらかじめ,チェックをして
297         * おきたい場合は,checked 属性に "checked" を登録します。
298         * ファイルダイアログの場合は,attributesの accept 属性に "MIMEタイプ"
299         * を登録します。
300         * 属性群は,タグの中に,CSS等で使用できる class="XXX" などの
301         * 文字を自由に登録する事が出来ます。
302         * CSSでクラスを対応 class="XXXX"
303         * タブで移動順を指定する tabindex="タブ順"
304         * ショートカットキーを割り当てる accesskey="ショートカットキー"
305         *
306         * @param   attri  属性群
307         * @param   name   名前
308         * @param   value  値
309         * @param   optAttri オプション文字列(タグ属性定義されていない属性の登録用文字列)
310         *
311         * @return  入力フォームタグ文字列
312         */
313        public static String input( final Attributes attri,final String name,final String value,final String optAttri ) {
314                String values = attri.getAttribute( INPUT_KEY );
315
316                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
317                rtn.append("<input ");
318                if( name  != null ) { rtn.append("name=\"").append( name ).append( "\" " ); }
319                if( value != null ) { rtn.append("value=\"").append( value ).append( "\" " ); }
320                rtn.append( values );
321                if( optAttri != null ) {
322                        rtn.append( " " );
323                        rtn.append( optAttri );
324                }
325                rtn.append( " />" );
326
327                return rtn.toString();
328        }
329
330        /**
331         * 入力フォームの属性情報のみの文字列を作成します。
332         * これは、name 属性や value 属性など、一般に都度変更されるフィールド
333         * 以外の固定的な属性情報を、先に作成しておく場合に、使用します。
334         *
335         * @param   attri       属性リスト
336         *
337         * @return  入力フォームタグの属性情報文字列
338         */
339        public static String inputAttri( final Attributes attri ) {
340                return attri.getAttribute( INPUT_KEY );
341        }
342
343        /**
344         * テキストエリアの属性情報のみの文字列を作成します。
345         * これは、name 属性や value 属性など、一般に都度変更されるフィールド
346         * 以外の固定的な属性情報を、先に作成しておく場合に、使用します。
347         *
348         * @param   attri       属性リスト
349         *
350         * @return  テキストエリアの属性情報文字列
351         */
352        public static String textareaAttri( final Attributes attri ) {
353                return attri.getAttribute( TEXTAREA_KEY );
354        }
355
356        /**
357         * プルダウン等のメニューの属性情報のみの文字列を作成します。
358         * これは、name 属性や value 属性など、一般に都度変更されるフィールド
359         * 以外の固定的な属性情報を、先に作成しておく場合に、使用します。
360         *
361         * @param   attri       属性リスト
362         *
363         * @return  プルダウン等のメニューの属性情報文字列
364         */
365        public static String selectAttri( final Attributes attri ) {
366                return attri.getAttribute( SELECT_KEY );
367        }
368
369        /**
370         * HIDDEN フォームを作成します。
371         *
372         * id属性に、name と同じ値が設定されます。
373         *
374         * @og.rev 5.5.4.0 (2012/07/02) ID属性追加
375         *
376         * @param   name  フォームの名前
377         * @param   value 値
378         *
379         * @return  HIDDENフォームタグ文字列
380         */
381        public static String hidden( final String name,final String value ) {
382                return hidden(name,value,name);
383        }
384
385        /**
386         * HIDDEN フォームを作成します。
387         *
388         * @og.rev 5.5.4.0 (2012/07/02) ID属性追加
389         *
390         * @param   name  フォームの名前
391         * @param   value 値
392         * @param   id    フォームのID
393         *
394         * @return  HIDDENフォームタグ文字列
395         */
396        public static String hidden( final String name, final String value, final String id ) {
397                StringBuilder rtn = new StringBuilder( BUFFER_SMALL );
398
399                rtn.append( "<input type=\"hidden\" " );
400                rtn.append( "name=\"" ).append( name );
401                rtn.append( "\" value=\"" ).append( value );
402                rtn.append( "\" id=\"" ).append( id );
403                rtn.append( "\" />" );
404
405                return rtn.toString();
406        }
407
408        /**
409         * テキストエリアを作成します。
410         *
411         * &lt;textarea name="名前" rows="4" cols="40"  ....&gt;送信文字列 &lt;/textarea&gt;
412         *
413         * <table border="1" frame="box" rules="all" >
414         *   <caption>Attributes に設定できる属性</caption>
415         *   <tr><td>name="名前"</td><td>オプション</td><td>LabelResource.properties のキー</td></tr>
416         *   <tr><td>rows="行数"</td><td>オプション</td><td>入力フィールドの表示行数</td></tr>
417         *   <tr><td>cols="幅"</td><td>オプション</td><td>入力フィールドの表示幅(文字数)</td></tr>
418         *   <tr><td>disabled="disabled"</td><td>オプション</td><td>選択や変更の操作をできない状態にする場合に指定</td></tr>
419         *   <tr><td>tabindex="Tab移動順"</td><td>オプション</td><td>0~32767の範囲で数字で指定(小さい順に移動)</td></tr>
420         *   <tr><td>accesskey="ショートカットキー"</td><td>オプション</td><td>文字セット中の1文字:WindowsであればAltキーと同時使用</td></tr>
421         *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
422         *   <tr><td>value="値"</td><td>オリジナル</td><td>name属性と共に送信される値</td></tr>
423         *   <tr><td>body="表示するタグ文字列"</td><td>オリジナル</td><td>画像や文字などボタン上に表示させたいタグの文字列</td></tr>
424         *   <tr><td>サポート外</td><td>未実装</td><td>readonly属性</td></tr>
425         * </table>
426         *
427         * 設定できる属性
428         *
429         * 属性群は,タグの中に,CSS等で使用できる class="XXX" などの
430         * 文字を自由に登録する事が出来ます。
431         * CSSでクラスを対応 class="XXXX"
432         * タブで移動順を指定する tabindex="タブ順"
433         * ショートカットキーを割り当てる accesskey="ショートカットキー"
434         *
435         * @param   attri 属性群
436         *
437         * @return  入力フォームタグ文字列
438         */
439        public static String textarea( final Attributes attri ) {
440                String values = attri.getAttribute( TEXTAREA_KEY );
441                String body   = attri.get( "body" );
442                if( body == null ) { body = "" ; }
443
444                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
445                rtn.append("<textarea ");
446                rtn.append( values );
447                rtn.append( ">" );
448                rtn.append( body );
449                rtn.append( "</textarea>" );
450
451                return rtn.toString();
452        }
453
454        /**
455         * ページリンクを作成します。
456         *
457         * &lt;A href="URL" target="ターゲット名"&gt;ラベル&lt;/A&gt;
458         *
459         * <table border="1" frame="box" rules="all" >
460         *   <caption>Attributes に設定できる属性</caption>
461         *   <tr><td>href="URL"</td><td>必須</td><td>リンク先のURLを指定します。</td></tr>
462         *   <tr><td>charset="文字セット"</td><td>オプション</td><td>リンク先の文字コードセットを指定します。</td></tr>
463         *   <tr><td>hreflang="言語セット"</td><td>オプション</td><td>リンク先の基本となる言語コードを指定します。</td></tr>
464         *   <tr><td>type="MIMEタイプ"</td><td>オプション</td><td>リンク先のMIMEタイプを指定します。</td></tr>
465         *   <tr><td>name="名前"</td><td>オプション</td><td>この要素をリンクの到達点とするための名前を指定します。</td></tr>
466         *   <tr><td>rel="リンクタイプ"</td><td>オプション</td><td>この文書からみた href 属性で指定されるリンク先との関係</td></tr>
467         *   <tr><td>rev="リンクタイプ"</td><td>オプション</td><td>href 属性で指定されるリンク先からみた、この文書との関係</td></tr>
468         *   <tr><td>tabindex="Tab移動順"</td><td>オプション</td><td>0~32767の範囲で数字で指定(小さい順に移動)</td></tr>
469         *   <tr><td>accesskey="ショートカットキー"</td><td>オプション</td><td>文字セット中の1文字:WindowsであればAltキーと同時使用</td></tr>
470         *   <tr><td>target="フレーム名"</td><td>オプション</td><td>リンク先のフレーム名</td></tr>
471         *   <tr><td>body="表示するタグ文字列"</td><td>オリジナル</td><td>画像や文字などをリンクにできます。</td></tr>
472         *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
473         *   <tr><td>サポート外</td><td>未実装</td><td>shape属性、coords属性</td></tr>
474         * </table>
475         *
476         * 設定できる属性
477         *
478         * ラベルなしの場合, href属性の "URL" そのものを付けます。
479         *
480         * target属性のフレーム名は
481         *
482         *  _top        フレームを解除して,リンク先をフレーム全体に表示する。
483         *  _parent リンク先を親フレームに表示する。
484         *  _self   リンク先を自分自身に表示する。
485         *  _blank  新しいウインドウを開いて,表示する。
486         *  その他  フレーム作成時の名前で指定可能。
487         *
488         * を指定します。
489         * なしの場合 _self (自分自身)を指定します。
490         *
491         * リンクメール機能
492         * URLを,mailto:メールアドレス で設定すれば,メール送信ダイアログを
493         * 開く事が出来ます。
494         * 画像リンク機能
495         * 画像をクリックするリンクは,ラベルの個所に &lt;img&gt;タグを設定します。
496         *
497         * &lt;a href="books.html"&gt;&lt;img src="banner.gif" width="468px" height="60px" alt="関連書籍紹介" border="0"&gt;&lt;/a&gt;
498         *
499         * 属性群は,タグの中に,CSS等で使用できる class="XXX" などの
500         * 文字を自由に登録する事が出来ます。
501         * CSSでクラスを対応 class="XXXX"
502         * タブで移動順を指定する tabindex="タブ順"
503         * ショートカットキーを割り当てる accesskey="ショートカットキー"
504         *
505         * @param   attri 属性群
506         *
507         * @return  ページリンクタグ文字列
508         */
509        public static String link( final Attributes attri ) {
510                return link( attri,"" );
511        }
512
513        /**
514         * ページリンクを作成します。
515         *
516         * @param   attri 属性群
517         * @param   urlEncode 文字列   ( ?key1=val1&amp;・・・・ という文字列 無いときは "" )
518         *
519         * @return  ページリンクタグ文字列
520         */
521        public static String link( final Attributes attri, final String urlEncode ) {
522
523                String href = addUrlEncode( attri.get( "href" ),urlEncode );
524
525                String values = attri.getAttribute( LINK_KEY );
526                String body   = attri.get( "body" );
527                if( body == null ) { body = attri.get( "href" ) ; }
528
529                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
530                rtn.append("<a href=\"");
531                rtn.append( href );
532                rtn.append( "\" " );
533                rtn.append( values );
534                rtn.append( ">" );
535                rtn.append( body );
536                rtn.append( "</a>" );
537
538                return rtn.toString();
539        }
540
541        /**
542         * xlink 形式のページリンクを作成します。
543         *
544         * 基本的には、link と同じです。アドレスの指定も、href で指定してください。
545         * 内部的に、xlink:href に変換します。
546         * また、URL引数を、"&amp;" で結合するのではなく、"&amp;amp;" で結合させます。
547         * これは、xlink そのものが、XML上に記述された場合に、XMLのルールで再度パース
548         * される為です。
549         *
550         * @param   attri 属性群
551         * @param   urlEncode 文字列   ( ?key1=val1&amp;・・・・ という文字列 無いときは "" )
552         *
553         * @return  ページリンクタグ文字列
554         */
555        public static String xlink( final Attributes attri, final String urlEncode ) {
556
557                String href = addUrlEncode( attri.get( "href" ),urlEncode,"&amp;" );
558
559                String values = attri.getAttribute( LINK_KEY );
560                String body   = attri.get( "body" );
561                if( body == null ) { body = attri.get( "href" ) ; }
562
563                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
564                rtn.append("<a xlink:href=\"");
565                rtn.append( href );
566                rtn.append( "\" " );
567                rtn.append( values );
568                rtn.append( ">" );
569                rtn.append( body );
570                rtn.append( "</a>" );
571
572                return rtn.toString();
573        }
574
575        /**
576         * メニューを作成します。
577         *
578         * @param   attri 属性群
579         * @param   opt 選択肢(オプション)
580         *
581         * @return  メニュータグ文字列
582         */
583        public static String select( final Attributes attri,final Options opt ) {
584                String name     = attri.get( "name" );
585                String optAttri = attri.get( "optionAttributes" );
586
587                return select( attri,opt,name,optAttri );
588        }
589
590        /**
591         * メニューを作成します。
592         *
593         * &lt;select size="行数" name="名前" multiple&gt;
594         *   &lt;option value="送信文字1"&gt;コメント&lt;/option&gt;
595         *   &lt;option value="送信文字2"&gt;コメント&lt;/option&gt;
596         *   &lt;option value="送信文字3" selected="selected"&gt;コメント&lt;/option&gt;
597         * &lt;/select&gt;
598         *
599         * <table border="1" frame="box" rules="all" >
600         *   <caption>Attributes に設定できる属性</caption>
601         *   <tr><td>name="名前"</td><td>オプション</td><td>LabelResource.properties のキー</td></tr>
602         *   <tr><td>size="行数"</td><td>オプション</td><td>select要素をリストボックスとして表示する場合の行数</td></tr>
603         *   <tr><td>multiple="multiple"</td><td>オプション</td><td>選択肢の中から複数選択出来るようにする。</td></tr>
604         *   <tr><td>disabled="disabled"</td><td>オプション</td><td>選択や変更の操作をできない状態にする場合に指定</td></tr>
605         *   <tr><td>tabindex="Tab移動順"</td><td>オプション</td><td>0~32767の範囲で数字で指定(小さい順に移動)</td></tr>
606         *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
607         * </table>
608         *
609         * 属性群は,タグの中に,CSS等で使用できる class="XXX" などの
610         * 文字を自由に登録する事が出来ます。
611         * CSSでクラスを対応 class="XXXX"
612         *
613         * @param   attri       属性群
614         * @param   opt         選択肢(オプション)
615         * @param   name        名前
616         * @param   optAttri オプション属性
617         *
618         * @return  メニュータグ文字列
619         */
620        public static String select( final Attributes attri,final Options opt,final String name,final String optAttri ) {
621                String values  = attri.getAttribute( SELECT_KEY );
622                String options = opt.getOption();
623
624                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
625                rtn.append("<select ");
626                if( name  != null ) { rtn.append("name=\"").append( name ).append( "\" " ); }
627                rtn.append( values );
628                if( optAttri != null ) {
629                        rtn.append( " " );
630                        rtn.append( optAttri );
631                }
632                rtn.append( ">" );
633                rtn.append( options );
634                rtn.append( "</select>" );
635
636                return rtn.toString();
637        }
638
639        /**
640         * オプションを作成します。
641         *
642         * &lt;select size="行数" name="名前" multiple&gt;
643         *   &lt;option value="送信文字1"&gt;コメント&lt;/option&gt;
644         *   &lt;option value="送信文字2"&gt;コメント&lt;/option&gt;
645         *   &lt;option value="送信文字3" selected="selected"&gt;コメント&lt;/option&gt;
646         * &lt;/select&gt;
647         *
648         * <table border="1" frame="box" rules="all" >
649         *   <caption>Attributes に設定できる属性</caption>
650         *   <tr><td>value="値"</td><td>オプション</td><td>送信する値</td></tr>
651         *   <tr><td>selected="selected"</td><td>オプション</td><td>選択肢をあらかじめ選択された状態にしておく</td></tr>
652         *   <tr><td>disabled="disabled"</td><td>オプション</td><td>選択や変更の操作をできない状態にする場合に指定</td></tr>
653         *   <tr><td>body="表示するタグ文字列"</td><td>オリジナル</td><td>選択肢に表示させたいタグの文字列</td></tr>
654         *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
655         * </table>
656         *
657         * セレクタとは,リストボックスやメニューなどの option引数にセットする
658         * 複数のデータをoptionタグでくるんだものです。
659         *
660         * @param   attri 属性群
661         *
662         * @return  オプションタグ文字列
663         */
664        public static String option( final Attributes attri ) {
665                String values  = attri.getAttribute( OPTION_KEY );
666                String body     = attri.get( "body" );
667                if( body == null ) { body = "No Label" ; }
668
669                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
670                rtn.append("<option ");
671                rtn.append( values );
672                rtn.append( " >" );
673                rtn.append( body );
674                rtn.append( "</option>" );
675
676                return rtn.toString();
677        }
678
679        /**
680         * フレームタグを作成します。
681         *
682         * &lt;frame marginheight="2px" marginwidth="2px" src="query.jsp" name="QUERY" /&gt;
683         *
684         * <table border="1" frame="box" rules="all" >
685         *   <caption>Attributes に設定できる属性</caption>
686         *   <tr><td>src="URL"</td><td>オプション</td><td>フレームの表示先URLを指定します。</td></tr>
687         *   <tr><td>name="フレーム名"</td><td>オプション</td><td>フレームに付ける名前を指定します。</td></tr>
688         *   <tr><td>longdesc="URI"</td><td>オプション</td><td>フレームの詳しい説明のURI</td></tr>
689         *   <tr><td>marginwidth="左右のマージン"</td><td>オプション</td><td>フレーム内の左右のマージンを指定します。</td></tr>
690         *   <tr><td>marginheight="上下のマージン"</td><td>オプション</td><td>フレーム内の上下のマージンを指定します。</td></tr>
691         *   <tr><td>noresize="noresize"</td><td>オプション</td><td>フレームサイズを変更できないようにします。</td></tr>
692         *   <tr><td>scrolling="スクロールの制御"</td><td>オプション</td><td>yes:スクロールバーを表示 no:表示しない auto:必要に応じて表示(デフォルト)</td></tr>
693         *   <tr><td>frameborder="枠の表示"</td><td>オプション</td><td>0:枠を表示しない  1:枠を表示する。(デフォルト)</td></tr>
694         *   <tr><td>keys="引数にセットするキー"</td><td>オプション</td><td>URI の引数にセットするキーを CSV 形式でセットします。</td></tr>
695         *   <tr><td>value="引数にセットする値"</td><td>オプション</td><td>URI の引数にセットする値を CSV 形式でセットします。</td></tr>
696         *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style</td></tr>
697         * </table>
698         *
699         * 設定できる属性
700         *
701         * scrolling属性
702         *
703         *  yes:常にスクロールバーを表示
704         *  no:常にスクロールバーを表示しない
705         *  auto:必要に応じてスクロールバーを表示(デフォルト)
706         *
707         * を指定します。
708         *
709         * frameborder属性
710         *
711         *  0:枠を表示しない
712         *  1:枠を表示する。(デフォルト)
713         *
714         * を指定します。
715         *
716         * 属性群は,タグの中に,CSS等で使用できる class="XXX" などの
717         * 文字を自由に登録する事が出来ます。
718         * CSSでクラスを対応 class="XXXX"
719         *
720         * @param   attri 属性群
721         *
722         * @return  フレームタグ文字列
723         */
724        public static String frame( final Attributes attri ) {
725                return frame( attri,"" );
726        }
727
728        /**
729         * フレームタグを作成します。
730         *
731         * @param   attri 属性群
732         * @param   urlEncode 文字列   ( ?key1=val1&amp;・・・・ という文字列 無いときは "" )
733         *
734         * @return  フレームタグ文字列
735         */
736        public static String frame( final Attributes attri,final String urlEncode ) {
737
738                String src  = addUrlEncode( attri.get( "src" ),urlEncode );
739                String values = attri.getAttribute( FRAME_KEY );
740
741                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
742                rtn.append("<frame src=\"");
743                rtn.append( src );
744                rtn.append( "\" " );
745                rtn.append( values );
746                rtn.append( " />" );
747
748                return rtn.toString();
749        }
750
751        /**
752         * URLエンコード文字列を作成します。
753         * エンコードすべき文字列が無い場合は, 0ストリング("") を返します。
754         * エンコード文字列がある場合は, "?KEY1=VAL1&amp;KEY2=VAL2&amp;・・・" という文字列を
755         * 返します。
756         * つまり、どちらのケースでも、URI に 連結させればよいことになります。
757         *
758         * @param   keys   URLの引数となるキー群
759         * @param   values URLの引数となる値群
760         *
761         * @return  URLエンコード文字列
762         */
763        public static String urlEncode( final String keys,final String values ) {
764                return urlEncode( keys,values,"&" );
765        }
766
767        /**
768         * URLエンコード文字列を作成します。
769         * エンコードすべき文字列が無い場合は, 0ストリング("") を返します。
770         * エンコード文字列がある場合は, "?KEY1=VAL1&amp;KEY2=VAL2&amp;・・・" という文字列を
771         * 返します。
772         * つまり、どちらのケースでも、URI に 連結させればよいことになります。
773         *
774         * @param   keys   URLの引数となるキー群
775         * @param   values URLの引数となる値群
776         * @param   join   URLの引数群を連結させる文字列
777         *
778         * @return  URLエンコード文字列
779         */
780        public static String urlEncode( final String keys,final String values,final String join ) {
781                if( keys == null || values == null ) { return ""; }
782
783                String[] key = StringUtil.csv2Array( keys );
784                String[] val = StringUtil.csv2Array( values );
785
786                return urlEncode( key,val,join ) ;
787        }
788
789        /**
790         * URLエンコード文字列を作成します。
791         * エンコードすべき文字列が無い場合は, 0ストリング("") を返します。
792         * エンコード文字列がある場合は, "?KEY1=VAL1&amp;KEY2=VAL2&amp;・・・" という文字列を
793         * 返します。
794         * つまり、どちらのケースでも、URI に 連結させればよいことになります。
795         *
796         * @param   key   URLの引数となるキーの配列
797         * @param   val   URLの引数となる値の配列
798         *
799         * @return  URLエンコード文字列
800         */
801        public static String urlEncode( final String[] key,final String[] val ) {
802                return urlEncode( key,val,"&" );
803        }
804
805        /**
806         * URLエンコード文字列を作成します。
807         * エンコードすべき文字列が無い場合は, 0ストリング("") を返します。
808         * エンコード文字列がある場合は, "?KEY1=VAL1&amp;KEY2=VAL2&amp;・・・" という文字列を
809         * 返します。
810         * つまり、どちらのケースでも、URI に 連結させればよいことになります。
811         *
812         * @og.rev 4.3.3.3 (2008/10/22) valに対して副作用を及ぼさないように修正
813         *
814         * @param   key   URLの引数となるキーの配列
815         * @param   val   URLの引数となる値の配列
816         * @param   join   URLの引数群を連結させる文字列
817         *
818         * @return  URLエンコード文字列
819         */
820        public static String urlEncode( final String[] key,final String[] val,final String join ) {
821                if( key == null || key.length == 0 || val == null || val.length == 0 ) {
822                        return "";
823                }
824                else if( key.length != val.length ) {
825                        String errMsg = "urlEncode のキーとバリューの個数が異なります。" + CR
826                                                + "key.length=[" + key.length + "]  val.length=[" + val.length + "]";
827                        throw new RuntimeException( errMsg );
828                }
829
830                // 4.3.3.3 (2008/10/22)
831                String[] tval = new String[val.length];
832
833                for( int i=0; i<val.length; i++ ) {
834                        if( key[i] == null || key[i].length() == 0 ) { return ""; }
835                        if( val[i] == null || val[i].length() == 0 ) { tval[i] = ""; }
836                        else if( val[i].charAt(0) == '[' ) {            // 暫定対応
837                                tval[i] = val[i];
838                        }
839                        else {
840                                tval[i] = StringUtil.urlEncode( val[i] );
841                        }
842                }
843
844                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
845
846                rtn.append( key[0] ).append( "=" ).append( tval[0] );
847                for( int i=1; i<key.length; i++) {
848                        rtn.append( join );
849                        rtn.append( key[i] ).append( "=" ).append( tval[i] );
850                }
851                return rtn.toString();
852        }
853
854        /**
855         * URL文字列に、URLエンコード文字列を連結します。
856         *
857         * URL文字列中にすでに "?" 文字が存在する場合は、URLエンコード側の
858         * 文字列とは、 "&amp;" で連結します。
859         * 逆に、"?" が存在しなければ、"?" で連結します。
860         * URLエンコード文字列が null の場合は、連結しません。
861         *
862         * @param   url URL文字列
863         * @param   encode URLエンコード文字列
864         *
865         * @return  連結文字列
866         */
867        public static String addUrlEncode( final String url,final String encode ) {
868                return addUrlEncode( url,encode,"&" );
869        }
870
871        /**
872         * URL文字列に、URLエンコード文字列を連結します。
873         *
874         * URL文字列中にすでに "?" 文字が存在する場合は、URLエンコード側の
875         * 文字列とは、 join (例 "&amp;" ) で連結します。
876         * 逆に、"?" が存在しなければ、"?" で連結します。
877         * URLエンコード文字列が null の場合は、連結しません。
878         * 連結する、encode 文字列の先頭が、join 文字列の場合、そのまま連結します。
879         * 先頭が、そうでない場合は、join 文字列で連結します。
880         * "?" が存在せず、encode 文字列の先頭が、join 文字列の場合は、、
881         * encode 文字列の先頭を取り除いて、"?" で連結します。
882         *
883         * 例:
884         *    ①. abc.html    key1=val1&amp;key2=val2      ⇒ abc.html?key1=val1&amp;key2=val2
885         *    ②.abc.html   &amp;key1=val1&amp;key2=val2  ⇒ abc.html?key1=val1&amp;key2=val2
886         *    ③.abc.html?key1=val1    key2=val2          ⇒ abc.html?key1=val1&amp;key2=val2
887         *    ④.abc.html?key1=val1   &amp;key2=val2      ⇒ abc.html?key1=val1&amp;key2=val2
888         *
889         * @og.rev 5.2.1.0 (2010/10/01) urlがnullの場合に、NullPointerExceptionが発生するバグを修正
890         *
891         * @param   url URL文字列
892         * @param   encode URLエンコード文字列
893         * @param   join   URLの引数群を連結させる文字列
894         *
895         * @return  連結文字列
896         */
897        public static String addUrlEncode( final String url,final String encode,final String join ) {
898                // 5.2.1.0 (2010/10/01) urlがnullの場合に、NullPointerExceptionが発生するバグを修正
899                String tmpUrl = ( url == null ? "" : url );
900
901                if( encode == null || encode.length() == 0 ) { return tmpUrl; }
902
903                final String rtn ;
904                if( tmpUrl.indexOf( '?' ) < 0 ) {
905                        if( encode.startsWith( join ) ) {
906                                rtn = tmpUrl + "?" + encode.substring(join.length());           // ②
907                        }
908                        else {
909                                rtn = tmpUrl + "?" + encode;                                                            // ①
910                        }
911                }
912                else {
913                        if( encode.startsWith( join ) ) {
914                                rtn = tmpUrl + encode;                                          // ④
915                        }
916                        else {
917                                rtn = tmpUrl + join + encode;                           // ③
918                        }
919                }
920                return rtn ;
921        }
922
923        /**
924         * 指定位置に画像を配置します。
925         *
926         * @param   attri 属性群
927         *
928         * @return  イメージタグ文字列
929         */
930        public static String img( final Attributes attri ) {
931                String values = attri.getAttribute( IMAGE_KEY );
932                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
933                rtn.append( "<img " );
934                rtn.append( values );
935                rtn.append( " />" );
936
937                return rtn.toString();
938        }
939
940        /**
941         * フォームを作成します。
942         *
943         * &lt;form action="URI" method="HTTPメソッド" enctype="MIMEタイプ" target="フレーム名" ・・・ &gt;フォーム等&lt;/form&gt;
944         *
945         * <table border="1" frame="box" rules="all" >
946         *   <caption>Attributes に設定できる属性</caption>
947         *   <tr><td>action="URI"</td><td>必須</td><td>送信されたフォームデータを処理するプログラムURI</td></tr>
948         *   <tr><td>method="HTTPメソッド"</td><td>オプション</td><td>get/post</td></tr>
949         *   <tr><td>enctype="MIMEタイプ"</td><td>オプション</td><td>フォームデータ送信時のMIMEタイプ</td></tr>
950         *   <tr><td>accept-charset="文字セット"</td><td>オプション</td><td>データとして受付可能な文字セットの指定</td></tr>
951         *   <tr><td>accept="MIMEタイプ"</td><td>オプション</td><td>データとして処理可能なMIMEタイプを指定</td></tr>
952         *   <tr><td>name="名前"</td><td>オプション</td><td>スクリプト等から参照する場合の名前</td></tr>
953         *   <tr><td>target="フレーム名"</td><td>オプション</td><td>フォームを送信した結果を表示させるフレーム</td></tr>
954         *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
955         *   <tr><td>body="フォーム等の文字列"</td><td>必須</td><td>input 等のフォーム要素</td></tr>
956         * </table>
957         *
958         * @param   attri 属性群
959         *
960         * @return  フォームタグ文字列
961         */
962        public static String form( final Attributes attri ) {
963                String values = attri.getAttribute( FORM_KEY );
964                String body   = attri.get( "body" );
965                if( body == null ) { body = "" ; }
966
967                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
968                rtn.append("<form ");
969                rtn.append( values );
970                rtn.append( ">" );
971                rtn.append( CR );
972                rtn.append( body );
973                rtn.append( CR );
974                rtn.append("</form>");
975
976                return rtn.toString();
977        }
978
979        /**
980         * 汎用インライン要素(SPAN)を作成します。
981         *
982         * &lt;span class="XXXX" ・・・ &gt;テキスト等&lt;/span&gt;
983         *
984         * <table border="1" frame="box" rules="all" >
985         *   <caption>Attributes に設定できる属性</caption>
986         *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
987         *   <tr><td>body="テキスト等の文字列"</td><td>オプション</td><td>このテキストを修飾します。</td></tr>
988         * </table>
989         *
990         * @param   attri 属性群
991         *
992         * @return  SPANタグ文字列
993         */
994        public static String span( final Attributes attri ) {
995                String values = attri.getAttribute( SPAN_KEY );
996
997                String optAttri = attri.get( "optionAttributes" );
998                String body   = attri.get( "body" );
999                if( body == null ) { body = "" ; }
1000
1001                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
1002                rtn.append("<span ");
1003                rtn.append( values );
1004                if( optAttri != null ) {
1005                        rtn.append( " " );
1006                        rtn.append( optAttri );
1007                }
1008                rtn.append( ">" );
1009                rtn.append( body );
1010                rtn.append( "</span>" );
1011
1012                return rtn.toString();
1013        }
1014
1015        /**
1016         * 整形済みテキスト(PRE)を作成します。
1017         *
1018         * &lt;pre class="XXXX" ・・・ &gt;テキスト等&lt;/pre&gt;
1019         *
1020         * <table border="1" frame="box" rules="all" >
1021         *   <caption>Attributes に設定できる属性</caption>
1022         *   <tr><td>汎用属性</td><td>オプション</td><td>class,id,title,style,lang,dir,xml:lang</td></tr>
1023         *   <tr><td>body="テキスト等の文字列"</td><td>オプション</td><td>このテキストを修飾します。</td></tr>
1024         * </table>
1025         *
1026         * @param   attri 属性群
1027         *
1028         * @return  PREタグ文字列
1029         */
1030        public static String pre( final Attributes attri ) {
1031                String values = attri.getAttribute( PRE_KEY );
1032
1033                String optAttri = attri.get( "optionAttributes" );
1034                String body   = attri.get( "body" );
1035                if( body == null ) { body = "" ; }
1036
1037                StringBuilder rtn = new StringBuilder( BUFFER_MIDDLE );
1038                rtn.append("<pre ");
1039                rtn.append( values );
1040                if( optAttri != null ) {
1041                        rtn.append( " " );
1042                        rtn.append( optAttri );
1043                }
1044                rtn.append( ">" );
1045                rtn.append( body );
1046                rtn.append( "</pre>" );
1047
1048                return rtn.toString();
1049        }
1050
1051        /**
1052         * URLチェック用のキーを返します。
1053         *
1054         * 引数に指定されたhrefに対して、時間とユーザーIDを付加した暗号化文字列を
1055         * 引数に追加します。
1056         *
1057         * 暗号化は、org.opengion.fukurou.util.HybsCryptographyを使用します。
1058         * 暗号化を行う文字列のフォーマットは、[href],time=[checkTime],userid=[loginUser]です。
1059         *
1060         * @og.rev 4.3.7.1 (2009/06/08) 新規追加
1061         * @og.rev 4.3.7.4 (2009/07/01) 循環参照を解消
1062         *
1063         * @param   href チェック対象のURL
1064         * @param   key チェックキーのパラメーターキー
1065         * @param   userid ユーザーID
1066         * @param   time 有効時間
1067         *
1068         * @return  チェックキー
1069         * @see org.opengion.fukurou.security.HybsCryptography
1070         */
1071        public static String addURLCheckKey( final String href, final String key, final String userid, final long time ) {
1072                String checkKey = href;
1073
1074                checkKey = checkKey.replace( "../", "" );
1075                checkKey = checkKey + ",time=" + time + ",userid=" + userid;
1076                checkKey = HYBS_CRYPTOGRAPHY.encrypt( checkKey );
1077
1078                return addUrlEncode( href, key + "=" + checkKey );
1079        }
1080
1081        /**
1082         * Aタグの文字列を解析して、href属性にURLチェック用の暗号化文字列を付加した形で、
1083         * Aタグを再構築し、返します。
1084         *
1085         * @og.rev 4.3.7.1 (2009/06/08) 新規追加
1086         * @og.rev 4.3.7.4 (2009/07/01) 循環参照を解消
1087         *
1088         * @param   tag Aタグ文字列
1089         * @param   key チェックキーのパラメーターキー
1090         * @param   userid ユーザーID
1091         * @param   time 有効時間
1092         *
1093         * @return  URLチェックキーが付加されたAタグ文字列
1094         */
1095        public static String embedURLCheckKey( final String tag, final String key, final String userid, final long time  ) {
1096                String rtn = tag;
1097                int hrefStr = rtn.indexOf( "href=\"" );
1098                if( hrefStr >= 0 ) {
1099                        int hrefEnd = rtn.indexOf( "\"",hrefStr + 6 );
1100                        if( hrefEnd >= 0 ) {
1101                                String href = rtn.substring( hrefStr + 6, hrefEnd );
1102                                href = XHTMLTag.addURLCheckKey( href, key, userid, time );
1103                                rtn = rtn.substring( 0,  hrefStr ) + "href=\"" + href + rtn.substring( hrefEnd );
1104                        }
1105                }
1106                return rtn;
1107        }
1108}