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 * <ROWSET> 044 * <ROW num="1"> ← この部分のみ 045 * <カラム1>値1</カラム1> ← この部分のみ 046 * ・・・ ← この部分のみ 047 * <カラムn>値n</カラムn> ← この部分のみ 048 * </ROW> ← この部分のみ 049 * ・・・ 050 * <ROW num="n"> 051 * ・・・ 052 * </ROW> 053 * <ROWSET> 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}