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 org.xml.sax.Attributes;
019    import java.util.List;
020    
021    /**
022     * エレメントをあらわす、OGElement クラスを定義しますã?
023     *
024     * エレメントã?、OGNode クラスを継承しã?名称、属æ?、ノードリストを持つオブジェクトですã?
025     * 通常でè¨?�†ところの、タグになりますã?
026     * 属æ?は、OGAttributes クラスで管ç�?�—ますã?ノã?ドリスãƒ?に関する操作ã?、OGNodeクラスの実è£?�§すã?
027     *
028     * OGNode は、enum OGNodeType で区別される状態を持ってã�?�¾すã?
029     * OGNodeType は、それぞれã?再設定が可能ですã?
030     * 例えば、既存ã?エレメントやノã?ドに対して、コメントタイãƒ?Comment)を指定するとã€?
031     * ファイル等への出力時にコメントとして出力されますã?
032     *
033     * @og.rev 5.1.8.0 (2010/07/01) 新規作æ?
034     *
035     * @version  5.0
036     * @author   Kazuhiko Hasegawa
037     * @since    JDK6.0,
038     */
039    public class OGElement extends OGNode {
040    //      public static final String CR  = System.getProperty("line.separator");
041    
042            // 5.2.1.0 (2010/10/01) nameSpace 対å¿?og: ã‚?mis:)
043            // 5.6.1.2 (2013/02/22) 個別に設定すべきã?削除
044            /** 特殊:å?部çš?�«、タグ属æ?の改行å?ç�?‚’行うタグ名ã? Stringを持ってã�?�¾すã? **/
045    //      private static final String CR_SET = ":comment , :view , :select" ;
046    
047            private final String            qName ;                         // こã?タグの名前(nameSpace も含ã‚?‚¨レメントã?名前)
048    //      private final int                       paraCnt;                        // 階層(-1は階層なしã?1は改行ã?み)
049            private           OGAttributes  attri = null;           // 属æ?オブジェクãƒ?
050    
051            // 階層に応じたスペã?スの設å®?
052            private static final int      PARA_LEN  = 8;
053            private static final String   PARA_CHAR = "\t";
054            private static final String[] PARA = new String[PARA_LEN];
055            static {
056                    PARA[0] = CR;
057                    StringBuilder buf = new StringBuilder();
058                    buf.append( CR );
059                    for( int i=1; i<PARA_LEN; i++ ) {
060                            buf.append( PARA_CHAR );
061                            PARA[i] = buf.toString();
062                    }
063            }
064    
065            /**
066             * ノã?ド名を指定してのトコンストラクター
067             *
068             * ノã?ド名のみæŒ?®šするためã?属æ?と、ノードリストが空のエレメントを構築しますã?
069             *
070             * @param       qName   ノã?ド名
071             */
072            public OGElement( final String qName ) {
073                    this( qName,null );
074            }
075    
076            /**
077             * ノã?ド名と階層を指定してのトコンストラクター
078             *
079             * ノã?ド名のみを持つ、属æ?と、ノードリストが空のエレメントを構築しますã?
080             *
081             * @param       qName   ノã?ド名
082             * @param       cnt             階層
083             */
084    //      public OGElement( final String qName , final int cnt ) {
085    //              this( qName,(Attributes)null );
086    //      }
087    
088            /**
089             * ノã?ド名を指定してのトコンストラクター
090             *
091             * ノã?ド名のみæŒ?®šするためã?属æ?と、ノードリストが空のエレメントを構築しますã?
092             *
093             * @og.rev 5.6.1.2 (2013/02/22) å»?­¢
094             *
095             * @param       qName   ノã?ド名
096             * @param       attri   属æ?オブジェクãƒ?
097             */
098    //      public OGElement( final String qName , final OGAttributes attri ) {
099    //              super();
100    //              setNodeType( OGNodeType.Element );
101    //
102    //              if( qName == null ) {
103    //                      String errMsg = "エレメントには、ノード名はå¿??ですã?";
104    //                      throw new RuntimeException( errMsg );
105    //              }
106    //
107    //              boolean useCR = CR_SET.contains( qName );
108    //              if( useCR ) { attri.setUseCR( useCR ); }                // true の場合ã?みセãƒ?ƒˆするã€?
109    //
110    //              this.qName   = qName;
111    //              this.attri   = attri ;
112    //              this.paraCnt = -1 ;
113    //      }
114    
115            /**
116             * ノã?ド名、属æ?タブã?属æ?リストをæŒ?®šしてのトコンストラクター
117             *
118             * 注æ„?属æ?値の正規化はå¿?�š行われますã?
119             * 属æ?値に含まれるCR(復帰), LF(改è¡?, TAB(タãƒ?はã€?半角スペã?スに置き換えられますã?
120             * XMLの規定では、属æ?の並びé ??保障されませんがã?SAXのAttributesは、XMLに記述されたé?番で
121             * 取得できてã�?�¾すã?で、このクラスでの属æ?リストも、記述é ?�§の並びé ?�«なりますã?
122             *
123             * @og.rev 5.2.1.0 (2010/10/01) タグ属æ?の改行å?ç�?‚’、Set からString[] に変更ã€?
124             * @og.rev 5.6.1.2 (2013/02/22) CR_SET をé?列から文字å?に変更
125             *
126             * @param       qName   ノã?ド名
127             * @param       atts    属æ?リスãƒ?
128             */
129    //      public OGElement( final String qName , final String attTab , final Attributes atts , final int cnt ) {
130            public OGElement( final String qName , final Attributes atts ) {
131                    super();
132                    setNodeType( OGNodeType.Element );
133    
134                    if( qName == null ) {
135                            String errMsg = "エレメントには、ノード名はå¿??ですã?";
136                            throw new RuntimeException( errMsg );
137                    }
138    
139                    this.qName   = qName;
140    //              this.paraCnt = cnt ;
141    
142                    // 5.2.1.0 (2010/10/01) nameSpace の取得ã?CR_SET ã‚?SetからString[] に変更ã€?
143                    // 5.6.1.2 (2013/02/22) 完å?ä¸??ではなくã?indexOf の部åˆ?¸??で反転するように変更ã€?
144    //              boolean useCR = CR_SET.contains( qName );
145    
146    //              String attTab = getPara( paraCnt+1 );
147    //              this.attri = new OGAttributes( attTab , atts , useCR ) ;
148                    this.attri = new OGAttributes( atts ) ;
149            }
150    
151            /**
152             * ノã?ド名を返しますã?
153             *
154             * @return      ノã?ド名
155             */
156            public String getTagName() {
157                    return qName;
158            }
159    
160            /**
161             * 属æ?オブジェクトを返しますã?
162             *
163             * これは、org.xml.sax.Attributes ではなくã?OGAttributes オブジェクトを返しますã?
164             * å†?ƒ¨オブジェクトそのもã?を返しますã?で、この OGAttributes の変更は、この
165             * エレメントが持つå†?ƒ¨属æ?も変更されますã?
166             *
167             * @return      属æ?オブジェクãƒ?
168             */
169            public OGAttributes getOGAttributes() {
170                    return attri;
171            }
172    
173            /**
174             * 属æ?オブジェクトをセãƒ?ƒˆしますã?
175             *
176             * 属æ?オブジェクトã?セãƒ?ƒˆは、このメソãƒ?ƒ‰からのみできるようにしますã?
177             * å†?ƒ¨オブジェクトそのもã?にセãƒ?ƒˆしますã?で、異なã‚?OGAttributes をセãƒ?ƒˆしたã�??合ã?ã€?
178             * 外部で、コピã?してからセãƒ?ƒˆしてくださいã€?
179             *
180             * @og.rev 5.6.1.2 (2013/02/22) 新規追åŠ?
181             *
182             * @param       attri 属æ?オブジェクãƒ?org.opengion.fukurou.xml.OGAttributes)
183             */
184            public void setOGAttributes( final OGAttributes attri ) {
185    
186    //              boolean useCR = CR_SET.contains( qName );
187    //              attri.setUseCR( useCR );
188    //              String attTab = getPara( paraCnt+1 );
189    //              attri.setAttrTab( attTab );
190    
191                    this.attri = attri;
192            }
193    
194            /**
195             * 属æ?リストからã?id属æ?の、属æ?値を取得しますã?
196             *
197             * id属æ? は、å?部çš?�«キャãƒ?‚·ュしており、すぐに取り出せますã?
198             * タグを特定するå?合ã?ä¸?ˆ¬属æ?のキーと値で選別するのではなくã?
199             * id属æ?を付与して選別するようにすればã€?«˜é?に見つけることが可能になりますã?
200             *
201             * @og.rev 5.1.9.0 (2010/08/01) 新規追åŠ?
202             *
203             * @return      id属æ?値
204             */
205            public String getId() {
206    //              return attri.getId() ;
207                    return (attri != null) ? attri.getId() : null ;
208            }
209    
210            /**
211             * 属æ?リストからã?æŒ?®šã?属æ?キーの、属æ?値を取得しますã?
212             *
213             * こã?処ç�??、属æ?リストをすべてスキャンして、キーにマッチすã‚?
214             * 属æ?オブジェクトを見つけã?そこから、属æ?値を取りå?すã?でã€?
215             * パフォーマンスに問題がありますã?
216             * 基本çš?�«は、アドレスæŒ?®šで、属æ?値を取りå?すよã�?�«してくださいã€?
217             *
218             * @og.rev 5.6.1.2 (2013/02/22) 新規追åŠ?
219             *
220             * @param       key     属æ?キー
221             *
222             * @return      属æ?値
223             */
224            public String getVal( final String key ) {
225    //              return attri.getVal( key );
226                    return (attri != null) ? attri.getVal( key ) : null ;
227            }
228    
229            /**
230             * 属æ?リストに、属æ?(キー、å?のセãƒ?ƒˆ)を設定しますã?
231             *
232             * 属æ?リストã?ä¸?•ªæœ?¾Œに、属æ?(キー、å?のセãƒ?ƒˆ)を設定しますã?
233             *
234             * @param       key     属æ?リストã?キー
235             * @param       val     属æ?リストã?値
236             */
237            public void addAttr( final String key , final String val ) {
238                    if( attri == null ) { attri = new OGAttributes() ; }
239                    attri.add( key,val ) ;
240            }
241    
242            /**
243             * 自åˆ??身の状態が、指定ã?条件に合è?してã�?‚‹かどã�?�‹、判定しますã?
244             *
245             * 合è?してã�?‚‹場合ã?、true をã?合è?してã�?�ªã�??合ã?、false を返しますã?
246             *
247             * æŒ?®šã?属æ?ã�?null の場合ã?、すべてに合è?すると判断しますã?
248             * 例えば、kye のみæŒ?®šすると、その属æ?名を持ってã�?‚‹エレメントすべてで
249             * true が返されますã?
250             * 実行é?度をè?えると、ノード名はæŒ?®šすべきですã?
251             *
252             * @param       name    ノã?ド名 null の場合ã?、すべての ノã?ド名 に合è?
253             * @param       key     属æ?å�?null の場合ã?、すべての 属æ?å�?に合è?
254             * @param       val     属æ?値 null の場合ã?、すべての 属æ?値 に合è?
255             *
256             * @return      条件がこのエレメントに合è?した場å�?true
257             */
258            public boolean match( final String name , final String key , final String val ) {
259                    // name が存在するがã?不ä¸??の場合ã?、false
260                    if( name != null && ! name.equals( qName ) ) { return false; }
261    
262                    // attri ã�?null なのに、key ã�?val がã?null でなã�??合ã?合è?しなã�??で、false と判断
263                    if( attri == null && ( key != null || val != null ) ) { return false; }
264    
265                    // キーが存在しã?値も存在する場合ã?、その値の合è?と同じ結果となるã?
266                    if( key != null ) {
267                            if( val != null ) { return val.equals( attri.getVal( key ) ); }         // 値があれã?、比è¼?�™るã?
268                            else              { return ( attri.getAdrs( key ) >= 0 );     }              // 値がなければ、存在チェãƒ?‚¯
269                    }
270    
271                    // 値が存在する場合ã?、その値が含まれるかチェãƒ?‚¯しã?あれば、true, なければ false
272                    if( val != null ) {
273                            boolean flag = false;
274                            int len = attri.size();
275                            for( int i=0; i<len; i++ ) {
276                                    if( val.equals( attri.getVal(i) ) ) { flag = true; break; }
277                            }
278                            return flag;
279                    }
280    
281                    // 上記ã?条件以外ã?、すべてã�?null なので、true
282                    return true;
283            }
284    
285            /**
286             * 段落æ–?­—å?を返しますã?
287             *
288             * 段落æ–?­—å?はã€?šŽ層を表す文字å?ですã?
289             * 通常はã€?AB ですが、XMLの階層がã?PARA_LEN をè¶?�ˆてもã?段落を増やしませんã€?
290             * 段落のæœ??のæ–?­—ã?、改行ですã?
291             *
292             * @og.rev 5.6.1.2 (2013/02/22) å†?ƒ¨ãƒ?‚­ストがなã�??合ã?タグの終äº?™‚にスペã?スは入れなã�??
293             * @og.rev 5.6.4.4 (2013/05/31) PARA_LEN をè¶?�ˆてもã?段落を増やしませんã€?
294             *
295             * @param       cnt     階層(-1:なしã?
296             * @return      段落æ–?­—å?
297             * @see OGNodeType
298             */
299            private String getPara( final int cnt ) {
300                    if( cnt < 0 ) { return ""; }
301                    if( cnt < PARA_LEN ) {       return PARA[cnt]; }
302                    else {                                  return  PARA[PARA_LEN-1]; }                     // 5.6.4.4 (2013/05/31) PARA_LEN をè¶?�ˆてもã?段落を増やしませんã€?
303    
304    //              StringBuilder buf = new StringBuilder();
305    //              buf.append( PARA[PARA_LEN-1] );
306    //              for( int i=PARA_LEN-1; i<cnt; i++ ) {
307    //                      buf.append( PARA_CHAR );
308    //              }
309    
310    //              return buf.toString();
311            }
312    
313            /**
314             * オブジェクトã?æ–?­—å?表現を返しますã?
315             *
316             * æ–?­—å?は、OGNodeType により異なりますã?
317             * Comment ノã?ドã?場合ã?、コメント記号をã?Cdata ノã?ドã?場合ã?、CDATA ã‚?
318             * つけて出力しますã?
319             *
320             * @og.rev 5.6.1.2 (2013/02/22) å†?ƒ¨ãƒ?‚­ストがなã�??合ã?タグの終äº?™‚にスペã?スは入れなã�??
321             * @og.rev 5.6.4.4 (2013/05/31) 改行3つを改行2つに置換しますã?
322             *
323             * @param       cnt             Nodeの階層??1:なしã?0:改行ã?みã€?:改行ï¼?  "・・・・??
324             * @return      こã?オブジェクトã?æ–?­—å?表現
325             * @see OGNode#toString()
326             */
327    //      public String toString() {
328            @Override
329            public String getText( final int cnt ) {
330                    StringBuilder buf = new StringBuilder();
331    
332                    buf.append( getPara(cnt) );
333                    buf.append( "<" ).append( qName );
334    
335    //              boolean useCR = CR_SET.contains( qName );
336                    buf.append( attri.getText( getPara(cnt+1) ) );
337    //              if( useCR ) { buf.append( getPara(cnt) ); }
338    
339                    String text = super.getText(cnt+1);
340    
341                    if( text.trim().isEmpty() ) {
342    //                      buf.append( " />" );
343                            buf.append( "/>" );                                  // 5.6.1.2 (2013/02/22) タグの終äº?™‚にスペã?スは入れなã�??
344                    }
345                    else {
346                            buf.append( ">" ).append( text );
347                            buf.append( getPara(cnt) );
348                            buf.append( "</" ).append( qName ).append( ">" );
349                    //      buf.append( CR );
350                    }
351                    String rtn = buf.toString();
352    
353                    switch( getNodeType() ) {
354                            case Comment:   rtn = "<!-- "      + rtn + " -->"; break;
355                            case Cdata:             rtn = "<![CDATA[ " + rtn + " ]]>"; break;
356    //                      case Text:
357    //                      case List:
358                            default:                break;
359                    }
360    
361    //              return rtn ;
362                    return rtn.replaceAll( CR+CR+CR , CR+CR ) ;                     // 改行3つを改行2つに置換しますã?
363            }
364    
365            /**
366             * オブジェクトã?æ–?­—å?表現を返しますã?
367             *
368             * æ–?­—å?は、OGNodeType により異なりますã?
369             * Comment ノã?ドã?場合ã?、コメント記号をã?Cdata ノã?ドã?場合ã?、CDATA ã‚?
370             * つけて出力しますã?
371             *
372             * @og.rev 5.6.1.2 (2013/02/22) å»?­¢。継承å…?�§処ç�??
373             *
374             * @return      こã?オブジェクトã?æ–?­—å?表現
375             * @see OGNode#toString()
376             */
377    //      @Override
378    //      public String toString() {
379    //              return getText(-10);
380    //      }
381    }