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 */
016 package org.opengion.fukurou.xml;
017
018 import java.util.List;
019 import java.util.ArrayList;
020
021 /**
022 * ノã?ドã?基底クラスとなるã?OGNode クラスを定義しますã?
023 *
024 * OGElement、OGDocument は、この、OGNode クラスを継承しますã?
025 * ただしã?OGAttributes は、独立してã�?‚‹ため、このクラスは継承してã�?�¾せんã€?
026 *
027 * æœ?‚‚ä¸?ˆ¬çš?�ªノã?ドã?、テキストノードでありã€?
028 *
029 * OGNode は、enum OGNodeType で区別される状態を持ってã�?�¾すã?
030 * そã?å†??OGElement と OGDocument は、サブクラスになってã�?�¾すã?
031 * OGNodeType は、それぞれã?再設定が可能ですã?
032 * 例えば、既存ã?エレメントやノã?ドに対して、コメントタイãƒ?Comment)を指定するとã€?
033 * ファイル等への出力時にコメントとして出力されますã?
034 *
035 * ã€??Listã€??ã€?å†?ƒ¨に、OGNode の ArrayList を持つ
036 * ã€??Textã€??ã€?å†?ƒ¨は、文字å?の BODY 部åˆ?‚’持つ
037 * ã€??Comment ã€?å†?ƒ¨は、文字å?であるがã?toString() 時には、コメント記号を前後に出力するã?
038 * ã€??Cdata ã€??:å†?ƒ¨は、TextNodeのArrayList を持つ、toString() 時には、Cdataを前後に出力するã?
039 * ã€??Element ã€?タグ名ã?属æ?、OGNode の ArrayList の入れ子状態をもつ
040 * ã€??Documentã€?トップã?Element として、read/write するときに使用。構é?は、唯ä¸?? OGElement を持つ List タイãƒ?
041 *
042 * @og.rev 5.1.8.0 (2010/07/01) 新規作æ?
043 * @og.rev 5.6.1.2 (2013/02/22) 構想からã‚?‚Š直ã�?
044 *
045 * @version 5.0
046 * @author Kazuhiko Hasegawa
047 * @since JDK6.0,
048 */
049 public class OGNode {
050 public static final String CR = System.getProperty("line.separator");
051 // public static final String TAB = "\t" ;
052
053 private final List<OGNode> nodes = new ArrayList<OGNode>(); // ノã?ドリスãƒ?
054 private final String text; // ãƒ?‚ストノード用のæ–?—å?ノã?ドå?
055 private OGNodeType nodeType ; // List,Text,Comment,Cdata,Element,Document
056 private OGNode parentNode = null; // 自身の親ノã?ãƒ?ただしã?æœ?µ‚セãƒ?ƒˆされたノーãƒ?
057
058 /**
059 * ãƒ?ƒ•ォルトコンストラクター
060 *
061 * ここでは、NodeType は、List に設定されますã?
062 */
063 public OGNode() {
064 this.text = null;
065 nodeType = OGNodeType.List;
066 }
067
068 /**
069 * ãƒ?‚ストノードを構築するためã?コンストラクター
070 *
071 * ãƒ?‚ストノードã?、簡易的に、å?部には、ノードリストではなく文字å?を持ってã�?�¾すã?
072 *
073 * @og.rev 5.6.1.2 (2013/02/22) å†?ƒ¨ãƒ?‚ストがなã�??合ã?タグの終äº?™‚にスペã?スは入れなã�??
074 *
075 * ここでは、NodeType は、Text に設定されますã?
076 * ただしã?引数のãƒ?‚ストが null のNodeType は、List に設定されますã?
077 *
078 * @param txt ãƒ?‚ストノードã?設定å?
079 */
080 public OGNode( final String txt ) {
081 text = txt ;
082 if( text != null ) { nodeType = OGNodeType.Text; }
083 else { nodeType = OGNodeType.List; }
084 }
085
086 /**
087 * ãƒ?‚ストノードをノã?ドリストに追åŠ?�—ますã?
088 *
089 * å†?ƒ¨çš?�«ãƒ?‚ストノードを構築して、リストに追åŠ?�—てã�?�¾すã?
090 * 戻りå?は、StringBuilder#append(String) の様にã€??結登録できるように
091 * 自åˆ??身を返してã�?�¾すã?
092 * ãƒ?‚ストノードに、この処ç�?‚’行うと、エラーになりますã?
093 * ä¸?—¦、テキストノードとして作æ?したノã?ドには、ノードを追åŠ?�§きませんã€?
094 *
095 * @param txt ãƒ?‚ストノードã?設定å?
096 *
097 * @return 自åˆ??身(this)のノã?ãƒ?
098 */
099 public OGNode addNode( final String txt ) {
100 if( txt != null ) {
101 if( nodeType == OGNodeType.Text ) {
102 // ãƒ?‚ストノードにノã?ドã?追åŠ?�§きませんã€?
103 String errMsg = "ä¸?—¦、テキストノードとして作æ?したノã?ドには、ノードを追åŠ?�§きませんã€?;
104 throw new RuntimeException( errMsg );
105 }
106
107 OGNode node = new OGNode( txt );
108 node.parentNode = this;
109 nodes.add( node );
110 }
111 return this;
112 }
113
114 /**
115 * ノã?ドをノã?ドリストに追åŠ?�—ますã?
116 *
117 * 追åŠ?�™るノードã?親として、è?åˆ??身を登録しますã?
118 * なおã?同じオブジェクトを、è¤?•°の親に追åŠ?�™るå?å�?ノã?ドリストには追åŠ?�¯能)はã€?
119 * 親ノã?ドã?、最後に登録されたノードã?みが設定されますã?
120 * ãƒ?‚ストノードに、この処ç�?‚’行うと、エラーになりますã?
121 * ä¸?—¦、テキストノードとして作æ?したノã?ドには、ノードを追åŠ?�§きませんã€?
122 *
123 * @param node ノã?ãƒ?
124 *
125 * @return 自åˆ??身(this)のノã?ãƒ?
126 */
127 public OGNode addNode( final OGNode node ) {
128 if( node != null ) {
129 if( nodeType == OGNodeType.Text ) {
130 // ãƒ?‚ストノードにノã?ドã?追åŠ?�§きませんã€?
131 String errMsg = "ä¸?—¦、テキストノードとして作æ?したノã?ドには、ノードを追åŠ?�§きませんã€?;
132 throw new RuntimeException( errMsg );
133 }
134
135 node.parentNode = this;
136 nodes.add( node );
137 }
138 return this;
139 }
140
141 /**
142 * ノã?ドリストに追åŠ?�•れてã�?‚‹、ノードã?個数を返しますã?
143 *
144 * @return ノã?ドリストã?数
145 */
146 public int nodeSize() {
147 return nodes.size();
148 }
149
150 /**
151 * ノã?ドリストに追åŠ?�•れてã�?‚‹、ノードを返しますã?
152 *
153 * ノã?ドã?æŒ?®šにはã€??列番号を使用しますã?
154 * ノã?ドã?個数は、事前に、nodeSize() で調べて置ã�?�¦くださいã€?
155 * 当然、テキストノードã?場合ã?、nodeSize()==0 なのでã€?
156 * こã?メソãƒ?ƒ‰では取得できませんã€?
157 *
158 * @param adrs ノã?ドリストã?位置
159 *
160 * @return æŒ?®šã?配å?番号のノã?ãƒ?
161 */
162 public OGNode getNode( final int adrs ) {
163 return nodes.get(adrs);
164 }
165
166 /**
167 * ノã?ドリストに、ノードをセãƒ?ƒˆしますã?
168 *
169 * ノã?ドリストã?æŒ?®šã?アドレスに、ノードをセãƒ?ƒˆしますã?
170 * これは、追åŠ?�§はなく置換えになりますã?
171 * ノã?ドã?æŒ?®šにはã€??列番号を使用しますã?
172 * ノã?ドã?個数は、事前に、nodeSize() で調べて置ã�?�¦くださいã€?
173 *
174 * @param adrs ノã?ドリストã?位置
175 * @param node セãƒ?ƒˆするノã?ãƒ?
176 */
177 public void setNode( final int adrs , final OGNode node ) {
178 nodes.set(adrs,node);
179 }
180
181 /**
182 * 自身にセãƒ?ƒˆされてã�?‚‹、親ノã?ドを返しますã?
183 *
184 * 親ノã?ドã?、è?身のオブジェクトに、ä¸?�¤しか設定できませんã€?
185 * これは、オブジェクトとして、同ä¸?ƒŽードを、è¤?•°の親ノã?ドに
186 * 追åŠ?�—たå?å�?これは、ノードリストへの追åŠ?�ªので可能)æœ?¾Œに追åŠ?�—ã�?
187 * 親ノã?ドã?み、保持してã�?‚‹ことになりますã?
188 * XML を構築するときã?、同ä¸??ノã?ドであってもã?毎回、作æ?しなおさなã�?�¨ã€?
189 * 親ノã?ドを見つけて、何かを行う場合には、おかしな動きをすることになりますã?
190 * なおã?ノã?ドオブジェクトè?体が、親ノã?ドから削除されてもã?自身の
191 * 親ノã?ド情報は保持し続けてã�?�¾すã?
192 * ある Element から削除したノã?ドを別のElementに追åŠ?�™ると、その時点でã€?
193 * 親ノã?ドも更新されますã?
194 *
195 * @return 親ノã?ãƒ?
196 */
197 public OGNode getParentNode() {
198 return parentNode;
199 }
200
201 /**
202 * 自身にセãƒ?ƒˆされてã�?‚‹、親ノã?ドã?階層数を返しますã?
203 *
204 * 自身のオブジェクトに設定されてã�?‚‹親ノã?ドをé ?•ªにさかのぼってã€?
205 * 何階層あるか返しますã?
206 * これは、getText(int) の引数に使えますã?
207 * 親ノã?ドがひとつもなã�??合ã?つまりè?身が最上位ã?場合ã?ã€? が返されますã?
208 *
209 * @return 自身の階層
210 */
211 public int getParentCount() {
212 int para = 0;
213 OGNode node = getParentNode();
214 while( node != null ) {
215 para++ ;
216 node = node.getParentNode();
217 }
218 return para;
219 }
220
221 /**
222 * ノã?ドリストからã?æŒ?®šã?配å?番号の、ノードを削除しますã?
223 *
224 * ノã?ドã?æŒ?®šにはã€??列番号を使用しますã?
225 * ノã?ドã?個数は、事前に、nodeSize() で調べて置ã�?�¦くださいã€?
226 *
227 * @param adrs ノã?ドリストã?位置
228 *
229 * @return 削除されたノーãƒ?
230 */
231 public OGNode removeNode( final int adrs ) {
232 return nodes.remove(adrs);
233 }
234
235 /**
236 * ノã?ドリストからã?すべてのノã?ドを削除しますã?
237 *
238 * これは、ノードリストをクリアしますã?
239 *
240 */
241 public void clearNode() {
242 nodes.clear();
243 }
244
245 /**
246 * ノã?ドリストからã?æŒ?®šã?ノã?ãƒ?orgNode)を新しいノã?ãƒ?newNode)に置き換えますã?
247 *
248 * ノã?ドã?、それぞれã?ノã?ドが作æ?されたé?番で、ユニã?クな番号を持ってã�?�¾すã?
249 * そã?番号をå?に、ノードを探しå?して、置き換えますã?
250 * 通常の、XMLパã?スから作æ?されたノードã?、すべてä¸?„�にユニã?ク番号が振られますがã€?
251 * 新しくつったノードをè¤?•°のノã?ドと置き換える場合ã?置き換えられた後ã?ノã?ドã?ã€?
252 * オブジェクトそのもã?がã?同ä¸?�«なるためã?注意がå¿?¦�ですã?
253 *
254 * @param orgNode 置換å?のオリジナルノã?ãƒ?
255 * @param newNode 置換する新しいノã?ãƒ?
256 */
257 public void changeNode( final OGNode orgNode , final OGNode newNode ) {
258 int size = nodes.size();
259 for( int i=0; i<size; i++ ) {
260 OGNode node = nodes.get(i);
261 // if( node.nodeNo == orgNode.nodeNo ) {
262 if( node.equals( orgNode ) ) { // Object.equals なので、オブジェクトそのもã?のä¸??判å®?
263 nodes.set( i,newNode );
264 }
265 else {
266 node.changeNode( orgNode,newNode );
267 }
268 }
269 }
270
271 /**
272 * ノã?ドリストからã?直ä¸?メンバã?)のエレメントã?みをリストにして返しますã?
273 *
274 * ノã?ドリストã?第ä¸?ƒ¬ベルで、エレメントã?みを返しますã?
275 * 通常は、あるエレメントを、getElementList( String ) 等で検索した後ã?そã?子要ç´?‚’
276 * 取り出すå?合に使用しますã?
277 * 該当するエレメントが、なにも存在しなã�??合ã?、空のリストオブジェクトが返されますã?
278 *
279 * @return 直ä¸?メンバã?)のエレメントã?リスãƒ?
280 */
281 public List<OGElement> getChildElementList() {
282 List<OGElement> eles = new ArrayList<OGElement>();
283
284 for( OGNode node : nodes ) {
285 if( node.nodeType == OGNodeType.Element ) {
286 eles.add( (OGElement)node );
287 }
288 }
289
290 return eles;
291 }
292
293 /**
294 * ノã?ドリストからã?下位ã?階層に存在するすべてのエレメントをリストにして返しますã?
295 *
296 * エレメントã?、名前をæŒ?®šして検索しますã?
297 * 該当するエレメントが、なにも存在しなã�??合ã?、空のリストオブジェクトが返されますã?
298 *
299 * @param qName エレメントã?名前
300 *
301 * @return 下位ã?階層に存在するすべてのエレメントã?リスãƒ?
302 */
303 public List<OGElement> getElementList( final String qName ) {
304 List<OGElement> eles = new ArrayList<OGElement>();
305
306 if( qName != null ) {
307 for( OGNode node : nodes ) {
308 if( node.nodeType == OGNodeType.Element ) {
309 OGElement ele = (OGElement)node;
310 if( qName.equals( ele.getTagName() ) ) {
311 eles.add( ele );
312 }
313 eles.addAll( ele.getElementList( qName ) );
314 }
315 }
316 }
317
318 return eles;
319 }
320
321 /**
322 * ノã?ドタイプを設定しますã?
323 *
324 * ノã?ドタイプとは、List , Text , Comment , Cdata , Element , Document などの
325 * ノã?ドã?種別を表ã�?enum タイプですã?
326 * 基本çš?�«は、オブジェクトã?取得時に、ファクトリメソãƒ?ƒ‰経由であれば、è?動的に設å®?
327 * されてã�?�¾すã?
328 * ここでは、可変設定できますã?
329 * 例えば、既存ã?エレメントやノã?ドに対して、コメントタイãƒ?Comment)を指定するとã€?
330 * ファイル等への出力時にコメントとして出力されますã?
331 * null を指定すると、なにもå?ç�?�•れませんã€?
332 *
333 * @param type enumのOGNodeType
334 * @see OGNodeType
335 */
336 public void setNodeType( final OGNodeType type ) {
337 if( type != null ) {
338 if( type != OGNodeType.Text && nodeType == OGNodeType.Text ) {
339 OGNode node = new OGNode( text );
340 node.parentNode = this;
341 nodes.add( node );
342 }
343
344 nodeType = type ;
345 }
346 }
347
348 /**
349 * ノã?ドタイプを取得しますã?
350 *
351 * ノã?ドタイプとは、List , Text , Comment , Cdata , Element , Document などの
352 * ノã?ドã?種別を表ã�?enum タイプですã?
353 * 基本çš?�«は、オブジェクトã?取得時に、ファクトリメソãƒ?ƒ‰経由であれば、è?動的に設å®?
354 * されてã�?�¾すã?
355 *
356 * @return ノã?ドタイãƒ?
357 * @see OGNodeType
358 */
359 public OGNodeType getNodeType() {
360 return nodeType;
361 }
362
363 /**
364 * ノã?ドリストã?æ–?—å?を返しますã?
365 *
366 * これは、タグでè¨?�†ところのBODY部に書かれた文字å?に相当しますã?
367 * 該当する文字å?がã?存在しなã�??合ã?、空のæ–?—å?(ゼロストリング)が返されますã?
368 *
369 * @param cnt Nodeの階層
370 * @return ノã?ドリストã?æ–?—å?(BODY部に書かれた文字å?)
371 */
372 public String getText( final int cnt ) {
373 StringBuilder buf = new StringBuilder();
374
375 if( nodeType == OGNodeType.Text ) {
376 buf.append( text );
377 }
378 else {
379 for( OGNode node : nodes ) {
380 buf.append( node.getText( cnt ) );
381 }
382 }
383
384 String rtn = buf.toString();
385 switch( nodeType ) {
386 case Comment: rtn = "<!-- " + rtn + " -->"; break;
387 case Cdata: rtn = "<![CDATA[ " + rtn + " ]]>"; break;
388 // case Document:
389 // case Text:
390 // case DTD:
391 // case List:
392 default: break;
393 }
394
395 return rtn ;
396 }
397
398 /**
399 * オブジェクトã?æ–?—å?表現を返しますã?
400 *
401 * æ–?—å?は、OGNodeType により異なりますã?
402 * Comment ノã?ドã?場合ã?、コメント記号をã?Cdata ノã?ドã?場合ã?、CDATA ã‚?
403 * つけて出力しますã?
404 *
405 * @return こã?オブジェクトã?æ–?—å?表現
406 * @see Object#toString()
407 */
408 @Override
409 public String toString() {
410 return getText( -10 );
411 }
412 }