    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.xml;
    017
    018import java.util.Map;
    019import java.util.LinkedHashMap;
    020import java.util.List;
    021import java.util.Collections;                                                                                                   // 6.4.3.1 (2016/02/12) refactoring
    022
    023import static org.opengion.fukurou.system.HybsConst.CR;                                                 // 6.1.0.0 (2014/12/26) refactoring
    024import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;                              // 6.1.0.0 (2014/12/26) refactoring
    025
    026/**
    027 * このｸﾗｽは、XMLﾌｧｲﾙのﾀｸﾞｴﾚﾒﾝﾄを表すｵﾌﾞｼﾞｪｸﾄです。
    028 * ﾀｸﾞとしては、ｺﾝｽﾄﾗｸﾀにMapを指定すれば(defaultMap)ﾀｸﾞのｶﾗﾑを
    029 * 初期設定します。この場合、Map に LinkedHashMap を指定すれば、ｶﾗﾑの
    030 * 順番も指定順になります。
    031 * ここで指定したMapの値は、put ﾒｿｯﾄﾞにより上書きされます。
    032 * setAfterMap で指定したMapは、既存の内部情報を上書きします。ｷｰがあれば、
    033 * afterMap の値が上書きされ、ｷｰが無ければ新規にｷｰが追加されます。
    034 * 一般には、XMLﾌｧｲﾙから構築された後で、XMLﾌｧｲﾙの情報を一括して
    035 * 書き換える場合などに使用します。
    036 * 処理の途中にｾｯﾄした場合は、それまでの値が上書きされ、それ以降の値は、
    037 * put により設定された値が 優先されます。
    038 * toString() により、簡易的に ｵﾗｸﾙXDK形式のXMLﾌｧｲﾙの
    039 * 1ﾚｺｰﾄﾞ 分の情報を返します。
    040 * ｵﾗｸﾙXDK形式のXMLﾌｧｲﾙとは、下記のような ROWSET をﾄｯﾌﾟとする ROW の
    041 * 集まりで1ﾚｺｰﾄﾞを表し、各ROWには、ｶﾗﾑ名をｷｰとするXMLになっています。
    042 *
    043 *   &lt;ROWSET&gt;
    044 *       &lt;ROW num="1"&gt;                   ← この部分のみ
    045 *           &lt;ｶﾗﾑ1&gt;値1&lt;/ｶﾗﾑ1&gt;      ← この部分のみ
    046 *             ･･･                             ← この部分のみ
    047 *           &lt;ｶﾗﾑn&gt;値n&lt;/ｶﾗﾑn&gt;      ← この部分のみ
    048 *       &lt;/ROW&gt;                          ← この部分のみ
    049 *        ･･･
    050 *       &lt;ROW num="n"&gt;
    051 *          ･･･
    052 *       &lt;/ROW&gt;
    053 *   &lt;ROWSET&gt;
    054 *
    055 * この形式であれば、XDK(Oracle XML Developer's Kit)を利用すれば、非常に簡単に
    056 * ﾃﾞｰﾀﾍﾞｰｽとXMLﾌｧｲﾙとの交換が可能です。
    057 * <a href="https://docs.oracle.com/cd/F19136_01/adxdk/introduction-to-XDK.html" target="_blank" >
    058 * XDK(Oracle XML Developer's Kit)</a>
    059 *
    060 * @version     4.0
    061 * @author      Kazuhiko Hasegawa
    062 * @since       JDK5.0,
    063 */
    064public class TagElement {
    065        private final String name ;
    066        /** 6.4.3.1 (2016/02/12) Collections.synchronizedMap で同期処理を行います。 */
    067        private final Map<String,String> tagMap = Collections.synchronizedMap( new LinkedHashMap<>() ); // 6.4.3.1 (2016/02/12) ついでに変数名変更。
    068        private String num      ;
    069        private String body     ;
    070
    071        /**
    072         * Tag名を指定して、ｵﾌﾞｼﾞｪｸﾄを構築します。
    073         *
    074         * @param       name    Tag名
    075         */
    076        public TagElement( final String name ) {
    077                this( name,null );
    078        }
    079
    080        /**
    081         * Tag名と初期化ﾏｯﾌﾟを指定して、ｵﾌﾞｼﾞｪｸﾄを構築します。
    082         *
    083         * @og.rev 6.4.3.1 (2016/02/12) Collections.synchronizedMap に置き換え。ついでに変数名変更。
    084         *
    085         * @param       name            Tag名
    086         * @param       defaultMap      初期化ﾏｯﾌﾟ
    087         */
    088        public TagElement( final String name, final Map<String,String> defaultMap ) {
    089                this.name = name;
    090                // 6.4.3.1 (2016/02/12) 最初から、構築しておきます。
    091                if( defaultMap != null ) { tagMap.putAll( defaultMap ); }
    092        }
    093
    094        /**
    095         * Tag名を取得します。
    096         *
    097         * @return      Tag名
    098         */
    099        public String getName() {
    100                return name;
    101        }
    102
    103        /**
    104         * ｶﾗﾑと値のﾍﾟｱを登録します。
    105         * すでに 内部に同一ｶﾗﾑが存在する場合は、値の書き換えを、ｶﾗﾑが
    106         * 存在しない場合は、ｶﾗﾑの追加を行います。
    107         * ｶﾗﾑは、追加された順番を再現してXML化できます。
    108         *
    109         * @og.rev 5.6.6.1 (2013/07/12) key が null や ｾﾞﾛ文字列の場合は、Map に追加しません。
    110         * @og.rev 6.4.3.1 (2016/02/12) Collections.synchronizedMap に置き換え。ついでに変数名変更。
    111         *
    112         * @param       key     ｶﾗﾑ
    113         * @param       val     値
    114         */
    115        public void put( final String key, final String val ) {
    116                if( key != null && key.length() > 0 ) {                                 // 5.6.6.1 (2013/07/12)
    117                        tagMap.put( key,val );
    118                }
    119        }
    120
    121        /**
    122         * すでに構築済みの ｶﾗﾑと値に、上書きで ﾏｯﾌﾟ情報を追加します。
    123         * すでに 内部に同一ｶﾗﾑが存在する場合は、値の書き換えを、ｶﾗﾑが
    124         * 存在しない場合は、ｶﾗﾑの追加を行います。
    125         * ｶﾗﾑは、追加された順番を再現してXML化できます。
    126         *
    127         * @og.rev 6.4.3.1 (2016/02/12) Collections.synchronizedMap に置き換え。ついでに変数名変更。
    128         *
    129         * @param afterMap      後設定ﾏｯﾌﾟ
    130         */
    131        public void setAfterMap( final Map<String,String> afterMap ) {
    132                if( afterMap != null ) {
    133                        tagMap.putAll( afterMap );
    134                }
    135        }
    136
    137        /**
    138         * ｷｰを指定して値を取得します。
    139         *
    140         * @og.rev 6.4.3.1 (2016/02/12) Collections.synchronizedMap に置き換え。ついでに変数名変更。
    141         *
    142         * @param       key     ｶﾗﾑ
    143         *
    144         * @return      値
    145         */
    146        public String get( final String key ) {
    147                // 6.4.3.1 (2016/02/12) ConcurrentMap 系は、key,val ともに not null 制限です。
    148                return key == null ? null : tagMap.get( key );
    149        }
    150
    151        /**
    152         * 行番号を取得します。
    153         *
    154         * @return      値
    155         */
    156        public String getRowNo() {
    157                return num;
    158        }
    159
    160        /**
    161         * 行番号を設定します。
    162         *
    163         * @param       num     値
    164         */
    165        public void setRowNo( final String num ) {
    166                this.num = num ;
    167        }
    168
    169        /**
    170         * BODY部の文字列を取得します。
    171         *
    172         * @return      値
    173         */
    174        public String getBody() {
    175                return body;
    176        }
    177
    178        /**
    179         * BODY部の文字列を設定します。
    180         *
    181         * @param       body    値
    182         */
    183        public void setBody( final String body ) {
    184                this.body = body ;
    185        }
    186
    187        /**
    188         * ｶﾗﾑの配列を返します。
    189         *
    190         * @og.rev 6.4.3.1 (2016/02/12) Collections.synchronizedMap に置き換え。ついでに変数名変更。
    191         *
    192         * @return      ｶﾗﾑの配列(順序は、ｶﾗﾑの登録順)
    193         * @og.rtnNotNull
    194         */
    195        public String[] getKeys() {
    196                return tagMap.keySet().toArray( new String[tagMap.size()] );
    197        }
    198
    199        /**
    200         * ｶﾗﾑ配列の順と同じ、値の配列を返します。
    201         *
    202         * @og.rev 6.4.3.1 (2016/02/12) Collections.synchronizedMap に置き換え。ついでに変数名変更。
    203         *
    204         * @return      値の配列(順序は、ｶﾗﾑの登録順と一致しています。)
    205         * @og.rtnNotNull
    206         */
    207        public String[] getValues() {
    208                return tagMap.values().toArray( new String[tagMap.size()] );
    209        }
    210
    211        /**
    212         * 引数のｶﾗﾑ名のListの順番で、ｶﾗﾑ配列の値の配列を返します。
    213         *
    214         * @og.rev 6.4.3.1 (2016/02/12) Collections.synchronizedMap に置き換え。ついでに変数名変更。
    215         *
    216         * @param clms  ｶﾗﾑ名のListｵﾌﾞｼﾞｪｸﾄ
    217         *
    218         * @return      値の配列(順序は、ｶﾗﾑの登録順と一致しています。)
    219         */
    220        public String[] getValues( final List<String> clms ) {
    221                final int size = clms.size();
    222                final String[] vals = new String[size];
    223                for( int i=0; i<size; i++ ) {
    224                        vals[i] = tagMap.get( clms.get(i) );
    225                }
    226
    227                return vals;
    228        }
    229
    230        /**
    231         * 引数のｶﾗﾑ名の配列の順番で、ｶﾗﾑ配列の値の配列を返します。
    232         * ｶﾗﾑ名が、存在しない場合は、値は、null を返します。
    233         *
    234         * @og.rev 6.4.3.1 (2016/02/12) Collections.synchronizedMap に置き換え。ついでに変数名変更。
    235         *
    236         * @param       clms    ｶﾗﾑ名の文字列配列(可変長引数)
    237         *
    238         * @return      値の配列(順序は、ｶﾗﾑの配列順と一致しています。)
    239         */
    240        public String[] getValues( final String... clms ) {
    241                final int size = clms.length;
    242                final String[] vals = new String[size];
    243                for( int i=0; i<size; i++ ) {
    244                        vals[i] = tagMap.get( clms[i] );
    245                }
    246
    247                return vals;
    248        }
    249
    250        /**
    251         * 内部情報の文字列表現を返します。
    252         * 1ﾚｺｰﾄﾞ分を表す ROW のXML表現を作成します。前後に、ROWSET を
    253         * 追加すれば、ｵﾗｸﾙXDK形式のXMLを作成できます。
    254         *
    255         * @return      内部情報の文字列表現
    256         * @og.rtnNotNull
    257         */
    258        @Override
    259        public String toString() {
    260
    261                // 6.0.2.5 (2014/10/31) char を append する。
    262                final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
    263                buf.append( '<' ).append( name );
    264                if( num != null ) {
    265                        buf.append( " num=\"" ).append( num ).append( "\" " );
    266                }
    267                buf.append( '>' ).append( CR );
    268
    269                // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
    270                if( body == null ) {
    271                        final String[] keys = getKeys();
    272                        for( int i=0; i<keys.length; i++ ) {
    273                                final String val = get( keys[i] );
    274                                if( val == null ) {
    275                                        buf.append( "  <" ).append( keys[i] ).append( " />" );          // XML なので、このまま。
    276                                }
    277                                else {
    278                                        buf.append( "  <" ).append( keys[i] ).append( '>' )
    279                                                .append( val )
    280                                                .append( "</" ).append( keys[i] ).append( '>' );
    281                                }
    282                                buf.append( CR );
    283                        }
    284                }
    285                else {
    286                        buf.append( body ).append( CR );
    287                }
    288
    289                buf.append( "</" ).append( name ).append( '>' ).append( CR );
    290
    291                return buf.toString();
    292        }
    293}