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.opengion.fukurou.util.Closer ;
019    import org.opengion.fukurou.util.FileUtil ;
020    
021    import java.io.PrintWriter ;
022    import java.io.BufferedWriter ;
023    import java.io.OutputStreamWriter ;
024    import java.io.FileOutputStream ;
025    import java.io.IOException ;
026    import java.io.File;
027    import java.io.StringReader ;
028    import java.io.FileNotFoundException ;
029    import java.io.UnsupportedEncodingException;
030    import java.util.Stack;
031    import java.util.List;
032    import java.util.ArrayList;
033    import java.util.Map;
034    import java.util.HashMap;
035    
036    import org.xml.sax.Attributes;
037    import org.xml.sax.ext.DefaultHandler2;
038    import org.xml.sax.InputSource ;
039    import org.xml.sax.SAXException;
040    import org.xml.sax.SAXParseException;
041    import javax.xml.parsers.SAXParserFactory;
042    import javax.xml.parsers.SAXParser;
043    import javax.xml.parsers.ParserConfigurationException;
044    
045    /**
046     * JSP/XMLファイルを読み取って、OGNode/OGElement オブジェクトを取得するã?パã?サークラスですã?
047     *
048     * 自åˆ??身がã?DefaultHandler2 を拡張してã�?�¾すã?で、パーサー本体になりますã?
049     * javax.xml.parsers および、org.w3c.dom の簡易å?ç�?‚’行いますã?
050     * read で、トãƒ??レベルの OGNode を読み込み、write で、ファイルに書きå?しますã?
051     * 通常の W3C 系の オブジェクトを利用しなã�??は、属æ?の並びé ?‚’保障するためですã?
052     * ただしã?属æ?のタブã?改行ã?失われますã?
053     * またã?属æ?値に含まれるCR(復帰), LF(改è¡?, TAB(タãƒ?はã€?半角スペã?スに置き換えられますã?
054     * これは、SAXParser 側での XML の仕様ã?関係で、属æ?は、正規化されるためですã?
055     *
056     * @og.rev 5.1.8.0 (2010/07/01) 新規作æ?
057     * @og.rev 5.1.9.0 (2010/08/01) static メソãƒ?ƒ‰をå»?­¢。é?常のオブジェクトクラスとして扱ã�?�¾すã?
058     *
059     * @version  5.0
060     * @author   Kazuhiko Hasegawa
061     * @since    JDK6.0,
062     */
063    public class JspSaxParser extends DefaultHandler2 {
064            public static final String CR = System.getProperty("line.separator");
065    
066            private final List<JspParserFilter> filters = new ArrayList<JspParserFilter>();     // 5.1.9.0 (2010/08/01)
067            private SAXParser parser = null;
068    
069            // 以下ã?パã?ス時に使用する変数ã€?パã?ス毎に初期化するã?)
070            private Map<String,OGElement> idMap = null;               // 5.1.9.0 (2010/08/01)
071            private Stack<OGNode>               stack = null;
072    
073            private OGNode  ele                     = null;         // 現時点のエレメントノーãƒ?
074            private String  attTab          = "";           // tagBefore のä¸?¬¡TEMP
075            private boolean inCDATA         = false;        // CDATA エレメントã?中かどã�?�‹の判å®?
076            private boolean inEntity        = false;        // Entity の中かどã�?�‹の判å®?
077    //      private File    file            = null;         // 処ç�?®Ÿ行中のファイルå�?
078            private String  filename        = null;         // 処ç�?®Ÿ行中のファイルå�?
079    
080            /**
081             * XMLファイルを読み込み、OGDocument を返しますã?
082             *
083             * å†?ƒ¨çš?�«は、SAXParserFactory から、SAXParser を構築し、Property にã€?
084             * http://xml.org/sax/properties/lexical-handler を設定してã�?�¾すã?
085             * コメントノードを処ç�?�™るためですã?
086             *
087             * @og.rev 5.1.9.0 (2010/08/01) static からノã?マルに変更
088             *
089             * @param       aFile   XMLファイル
090             *
091             * @return      ファイルから読み取って構築したOGDocumentオブジェクãƒ?
092             */
093            public OGDocument read( final File aFile ) {
094    
095    //              JspSaxParser sxp = new JspSaxParser();
096    //              sxp.setFile( aFile );
097                    filename = aFile.getAbsolutePath() ;
098    
099                    try {
100                            if( parser == null ) {
101                                    // SAXパã?サーファクトリを生æˆ?
102                                    SAXParserFactory spfactory = SAXParserFactory.newInstance();
103    
104                                    // SAXパã?サーを生æˆ?
105                                    parser = spfactory.newSAXParser();
106    
107                                    parser.setProperty("http://xml.org/sax/properties/lexical-handler", this);      // LexicalHandler として
108                            }
109                            // XMLファイルを指定されたハンドラーで処ç�?�—まã�?
110                            parser.parse( aFile, this );
111    
112                    } catch ( ParserConfigurationException ex ) {
113                            String errMsg = "重大な構æ?エラーが発生しましたã€?
114                                            + CR + "\t" + ex.getMessage()
115                                            + CR + "\t" + aFile ;
116                            throw new RuntimeException( errMsg,ex );
117            //      5.1.9.0 (2010/08/01) å»?­¢
118            //      } catch ( SAXNotRecognizedException ex ) {
119            //              String errMsg = "XMLReader は、認識されなã�?©Ÿè?またã?プロパティー識別子を検å?しましたã€?
120            //                              + CR + "\t" + ex.getMessage()
121            //                              + CR + "\t" + aFile ;
122            //              if( ex2 != null ) { errMsg = errMsg + CR + "\t" + ex2.getMessage(); }
123            //              throw new RuntimeException( errMsg,ex );
124            //      } catch ( SAXNotSupportedException ex ) {
125            //              String errMsg = "XMLReader は、要求された操ä½?(状態またã?値の設å®? を実行できませんでしたã€?
126            //                              + CR + "\t" + ex.getMessage()
127            //                              + CR + "\t" + aFile ;
128            //              if( ex2 != null ) { errMsg = errMsg + CR + "\t" + ex2.getMessage(); }
129            //              throw new RuntimeException( errMsg,ex );
130                    } catch ( SAXException ex ) {
131                            String errMsg = "SAX のä¸?ˆ¬çš?�ªエラーが発生しましたã€?
132                                            + CR + "\t" + ex.getMessage()
133                                            + CR + "\t" + aFile ;
134                            Exception ex2 = ex.getException();
135                            if( ex2 != null ) { errMsg = errMsg + CR + "\t" + ex2.getMessage(); }
136                            throw new RuntimeException( errMsg,ex );
137                    } catch ( IOException ex ) {
138                            String errMsg = "ファイル読取時にエラーが発生しましたã€?
139                                            + CR + "\t" + ex.getMessage()
140                                            + CR + "\t" + aFile ;
141                            throw new RuntimeException( errMsg,ex );
142            //      5.1.9.0 (2010/08/01) å»?­¢
143            //      } catch( RuntimeException ex ) {
144            //              String errMsg = "実行時エラーが発生しましたã€?
145            //                              + CR + "\t" + ex.getMessage()
146            //                              + CR + "\t" + aFile ;
147            //              throw new RuntimeException( errMsg,ex );
148                    }
149    
150                    return getDocument() ;
151            }
152    
153            /**
154             * XML形式で表現されたã?æ–?­—å?(String) から、OGDocument を構築しますã?
155             *
156             * 処ç�?š„にはã€?read( File ) と同じで、取りå?すå?がã?æ–?­—å?とã�?�†ã�?�‘ですã?
157             * XMLファイルからの読み込みと異なりã?通常は、Element を表現したæ–?­—å?が作æ?されますがã€?
158             * 返されるのは、OGDocument オブジェクトですã?
159             *
160             * @og.rev 5.1.9.0 (2010/08/01) static からノã?マルに変更
161             *
162             * @param       str     XML形式で表現された文字å?
163             *
164             * @return      ファイルから読み取って構築しã�?OGDocumentオブジェクãƒ?
165             */
166            public OGDocument string2Node( final String str ) {
167    
168    //              JspSaxParser sxp = new JspSaxParser();
169                    filename = null ;
170    
171                    try {
172                            if( parser == null ) {
173                                    // SAXパã?サーファクトリを生æˆ?
174                                    SAXParserFactory spfactory = SAXParserFactory.newInstance();
175                                    // SAXパã?サーを生æˆ?
176                                    parser = spfactory.newSAXParser();
177    
178                                    parser.setProperty("http://xml.org/sax/properties/lexical-handler", this);      // LexicalHandler として
179                            }
180    
181                            // XMLファイルを指定されたãƒ?ƒ•ォルトハンドラーで処ç�?�—まã�?
182                            InputSource source = new InputSource( new StringReader( str ) );
183                            parser.parse( source, this );
184    
185                    } catch ( ParserConfigurationException ex ) {
186                            String errMsg = "重大な構æ?エラーが発生しましたã€?
187                                            + CR + ex.getMessage();
188                            throw new RuntimeException( errMsg,ex );
189            //      5.1.9.0 (2010/08/01) å»?­¢
190            //      } catch ( SAXNotRecognizedException ex ) {
191            //              String errMsg = "XMLReader は、認識されなã�?©Ÿè?またã?プロパティー識別子を検å?しましたã€?
192            //                              + CR + ex.getMessage();
193            //              Exception ex2 = ex.getException();
194            //              if( ex2 != null ) { errMsg = errMsg + CR + "\t" + ex2.getMessage(); }
195            //              throw new RuntimeException( errMsg,ex );
196                    } catch ( SAXException ex ) {
197                            String errMsg = "SAX のä¸?ˆ¬çš?�ªエラーが発生しましたã€?
198                                            + CR + ex.getMessage();
199                            Exception ex2 = ex.getException();
200                            if( ex2 != null ) { errMsg = errMsg + CR + "\t" + ex2.getMessage(); }
201                            throw new RuntimeException( errMsg,ex );
202                    } catch ( IOException ex ) {
203                            String errMsg = "ストリーãƒ?‚ªブジェクト作æ?時にエラーが発生しましたã€?
204                                            + CR + ex.getMessage();
205                            throw new RuntimeException( errMsg,ex );
206            //      5.1.9.0 (2010/08/01) å»?­¢
207            //      } catch( RuntimeException ex ) {
208            //              String errMsg = "実行時エラーが発生しましたã€?
209            //                              + CR + ex.getMessage();
210            //              throw new RuntimeException( errMsg,ex );
211                    }
212    
213                    return getDocument() ;
214            }
215    
216            /**
217             * OGDocument を所定ã?ファイルに、XML形式で書きå?しますã?
218             *
219             * ここでは、UTF-8 æ–?­—コードでの書きå?しですã?
220             *
221             * @og.rev 5.1.9.0 (2010/08/01) static からノã?マルに変更
222             *
223             * @param       aFile   書きå?すファイル
224             * @param       node    書きå?ã�?OGDocument
225             */
226    //      public void write( final File aFile, final OGDocument node ) {
227    //              write( aFile,node,"UTF-8" );
228    //      }
229    
230            /**
231             * OGDocument を所定ã?ファイルに、XML形式で書きå?しますã?
232             *
233             * @param       aFile   書きå?すファイル
234             * @param       node    書きå?ã�?OGDocument
235             */
236            public void write( final File aFile, final OGDocument node ) {
237                    PrintWriter out    = null;
238                    String      encode = node.getEncode();
239                    try {
240                            out = new PrintWriter( new BufferedWriter( new OutputStreamWriter( new FileOutputStream(aFile),encode )));
241    //                      out.println( "<?xml version=\"1.0\" encoding=\"" + encode + "\"?>" );
242                            out.println( node.toString() );
243                    } catch ( FileNotFoundException ex ) {
244                            String errMsg = "æŒ?®šされたパス名で示されるファイルが存在しませんでしたã€?
245                                            + CR + "\t" + ex.getMessage()
246                                            + CR + "\t" + aFile ;
247                            throw new RuntimeException( errMsg,ex );
248                    } catch ( UnsupportedEncodingException ex ) {
249                            String errMsg = "æ–?­—ã?エンコーãƒ?‚£ング(" + encode + ")がサポã?トされてã�?�¾せんã€?
250                                            + CR + "\t" + ex.getMessage()
251                                            + CR + "\t" + aFile ;
252                            throw new RuntimeException( errMsg,ex );
253            //      5.1.9.0 (2010/08/01) å»?­¢
254            //      } catch( RuntimeException ex ) {
255            //              String errMsg = "実行時エラーが発生しましたã€?
256            //                              + CR + "\t" + ex.getMessage()
257            //                              + CR + "\t" + aFile ;
258            //              throw new RuntimeException( errMsg,ex );
259                    }
260                    finally {
261                            Closer.ioClose( out );
262                    }
263            }
264    
265            /**
266             * ãƒ?‚£レクトリの再帰処ç�?�§パã?ス処ç�?‚’行いますã?
267             *
268             * @og.rev 5.1.9.0 (2010/08/01) static からノã?マルに変更
269             *
270             * @param       fromFile        読み取りもとのファイル/フォルãƒ?
271             * @param       toFile  書き込み先ã?ファイル/フォルãƒ?
272             */
273            public void copyDirectry( final File fromFile, final File toFile ) {
274                    // コピã?å…?�Œファイルの場合ã?コピã?して、終äº?�™るã?
275                    if( fromFile.exists() && fromFile.isFile() ) {
276                            boolean isOK = false;
277                            String name = fromFile.getName();
278                            if( name.endsWith( ".jsp" ) || name.endsWith( ".xml" ) ) {
279                                    try {
280                                            OGDocument doc = read( fromFile );
281                                            if( doc != null && !filters.isEmpty() ) {
282                                                    for( JspParserFilter filter: filters ) {
283                                                            doc = filter.filter( doc );
284                                                            if( doc == null ) { break; }    // エラー、またã?処ç�??中止
285                                                    }
286                                            }
287                                            if( doc != null ) {
288                                                    write( toFile,doc );
289                                                    isOK = true;
290                                            }
291                                    }
292                                    catch( RuntimeException ex ) {
293                            //              ex.printStackTrace();
294                                            System.out.println( ex.getMessage() );
295                                    }
296                            }
297    
298                            // JSPやXMLでなã�??パã?スエラー、書きå?しエラーなど正常終äº?�§きなかったå?合ã?、バイナリコピã?
299                            if( !isOK ) {
300                                    FileUtil.copy( fromFile,toFile,true );
301                            }
302                            return ;
303                    }
304    
305                    // コピã?先ディレクトリが存在しなければ、作æ?する
306                    if( !toFile.exists() ) {
307                            if( !toFile.mkdirs() ) {
308                                    System.err.println( toFile + " の ãƒ?‚£レクトリ作æ?に失敗しましたã€? );
309                                    return ;
310                            }
311                    }
312    
313                    // ãƒ?‚£レクトリå†??ファイルをすべて取得すã‚?
314                    File[] files = fromFile.listFiles();
315    
316                    // ãƒ?‚£レクトリå†??ファイルに対しコピã?処ç�?‚’行う
317                    for( int i = 0; i<files.length; i++ ){
318                            copyDirectry( files[i], new File( toFile, files[i].getName()) );
319                    }
320            }
321    
322            /**
323             * copyDirectry 処ç�?�§、OGDocument をフィルター処ç�?�™るオブジェクトを登録しますã?
324             *
325             * å†?ƒ¨リストへフィルターを追åŠ?�—ますã?
326             * フィルター処ç�??、追åŠ?�•れたé ?�«行われますã?
327             * å†?ƒ¨リストへの追åŠ??できますが、削除はできませんã€?
328             *
329             * @og.rev 5.1.9.0 (2010/08/01) 新規追åŠ?
330             *
331             * @param       filter  フィルターオブジェクãƒ?
332             */
333            public void addFilter( final JspParserFilter filter ) {
334                    filters.add( filter );
335            }
336    
337            /**
338             * サンプルプログラãƒ?�§すã?
339             *
340             * 引数の IN がファイルの場合ã?、OUTもファイルとして扱ã�?�¾すã?
341             * IN がフォルãƒ??場合ã?ã€?šŽ層にしたがって、å?帰çš?�«処ç�?‚’行い、OUT に出力しますã?
342             * フォルãƒ?šŽ層をパースしてã�?‚‹æœ?¸­に、XMLとして処ç�?�§きなã�??処ç�?¸­にエラーが発生しã�?
343             * などの場合ã?、バイナリコピã?を行いますã?
344             *
345             * "Usage: JspSaxParser  <inFile|inDir> <outFile|outDir> [<JspParserFilter1> ?¥?¥?¥ ]"
346             *
347             * @param       args    コマンド引数配å?
348             */
349            public static void main( final String[] args ) throws Exception {
350                    if( args.length < 2 ) {
351                            System.out.println( "Usage: JspSaxParser  <inFile|inDir> <outFile|outDir> [<JspParserFilter1> ?¥?¥?¥ ]" );
352                    }
353    
354                    File in   = new File( args[0] );
355                    File out  = new File( args[1] );
356    
357                    JspSaxParser jsp = new JspSaxParser();
358    
359                    if( args.length >= 3 ) {
360                            for( int i=2; i<args.length; i++ ) {
361                                    JspParserFilter filter = (JspParserFilter)Class.forName( args[i] ).newInstance();
362                                    jsp.addFilter( filter );
363                            }
364                    }
365    
366                    jsp.copyDirectry( in,out );
367            }
368    
369            /**
370             * 処ç�?¸­のファイルオブジェクトを設定しますã?
371             *
372             * これは、エラー、ワーニング時ã?ファイル名を出力するために利用してã�?�¾すã?
373             *
374             * @og.rev 5.1.9.0 (2010/08/01) å»?­¢
375             *
376             * @param       file    処ç�?¸­のファイルオブジェクãƒ?
377             */
378    //      public void setFile( final File file ) {
379    //              this.file = file;
380    //      }
381    
382            // ********************************************************************************************** //
383            // **                                                                                          ** //
384            // ** ここから下ã?、DefaultHandler2 の実è£?�«なりますã?                                         ** //
385            // **                                                                                          ** //
386            // ********************************************************************************************** //
387    
388            /**
389             * æ–?›¸の開始é?知を受け取りますã?
390             *
391             * インタフェース ContentHandler å†?? startDocument
392             *
393             * @see org.xml.sax.helpers.DefaultHandler#startDocument()
394             * @see org.xml.sax.ContentHandler#startDocument()
395             */
396            @Override
397            public void startDocument() {
398                    stack   = new Stack<OGNode>();
399                    ele             = new OGDocument();
400                    ((OGDocument)ele).setFilename( filename );
401    
402                    idMap   = new HashMap<String,OGElement>();                // 5.1.9.0 (2010/08/01) 追åŠ?
403    
404                    attTab   = "";          // tagBefore のä¸?¬¡TEMP
405                    inCDATA  = false;       // CDATA エレメントã?中かどã�?�‹の判å®?
406                    inEntity = false;       // Entity の中かどã�?�‹の判å®?
407            }
408    
409            /**
410             * 要ç´??開始é?知を受け取りますã?
411             *
412             * インタフェース ContentHandler å†?? startElement
413             *
414             * @param       uri                     名前空é–??µ?²?©。要ç´?�Œ名前空é–??µ?²?© を持たなã�??合ã?またã?名前空間å?ç�?�Œ実行されなã�??合ã? null
415             * @param       localName       前置修飾子を含まなã�?ƒ­ーカル名ã?名前空間å?ç�?�Œ行われなã�??合ã?空æ–?­—å?
416             * @param       qName           接頭辞を持つ修飾名ã?修飾名を使用できなã�??合ã?空æ–?­—å?
417             * @param       attributes      要ç´?�«付加された属æ?。属æ?が存在しなã�??合ã?空の Attributesオブジェクãƒ?
418             *
419             * @see org.xml.sax.helpers.DefaultHandler#startElement(String,String,String,Attributes)
420             * @see org.xml.sax.ContentHandler#startElement(String,String,String,Attributes)
421             */
422            @Override
423            public void startElement( final String uri, final String localName, final String qName, final Attributes attributes ) {
424    
425    //              OGElement newEle = new OGElement( qName,attTab,attributes,-1 );
426                    OGElement newEle = new OGElement( qName,attributes );
427                    String id = newEle.getId();
428                    if( id != null ) { idMap.put( id,newEle ); }            // 5.1.9.0 (2010/08/01) idをMapにキャãƒ?‚·ュ
429    
430                    ele.addNode( newEle );
431                    stack.push( ele );
432                    ele = newEle ;
433            }
434    
435            /**
436             * 要ç´??のæ–?­—データの通知を受け取りますã?
437             *
438             * エンãƒ?‚£ãƒ?‚£ーå†?�‹どã�?�‹を判断する、inEntity フラグã�?true の間ã?ã€?
439             * 何も処ç�?�—ませんã€?
440             *
441             * インタフェース ContentHandler å†?? characters
442             *
443             * @param       cbuf    æ–?­—データ配å?
444             * @param       off             æ–?­—é?列å?の開始位置
445             * @param       len             æ–?­—é?列から使用される文字数
446             *
447             * @see org.xml.sax.helpers.DefaultHandler#characters(char[],int,int)
448             * @see org.xml.sax.ContentHandler#characters(char[],int,int)
449             */
450            @Override
451            public void characters( final char[] cbuf, final int off, final int len ) {
452                    if( inEntity ) { return ; }             // &lt; â‡?< に変換されるã?で、エンãƒ?‚£ãƒ?‚£å†?�§は、なにもå?ç�?�—なã�??
453    
454                    String text = toText( cbuf,off,len );
455                    if( inCDATA ) {
456                            ele.addNode( text );
457                            return ;
458                    }
459    
460                    OGNode node = new OGNode( text );
461                    ele.addNode( node );
462    
463                    // '\r'(CR:復帰)+ '\n'(LF:改è¡?の可能性があるがã€?'\n'(LF:改è¡?がã?より後ろにあるので、これで判定ã?
464                    int lastIdx = text.lastIndexOf( '\n' );
465                    if( lastIdx >= 0 ) {
466                            attTab = text.substring( lastIdx+1 );   // 改行からã?æœ?¾Œまでの部åˆ?–‡字å?
467                    }
468                    else {
469                            attTab = text;                                                  // 改行がなã�??で、すべて
470                    }
471            }
472    
473            /**
474             * CDATA セクションの開始を報告しますã?
475             *
476             * CDATA セクションのコンãƒ?ƒ³ãƒ??、正規ã? characters イベントを介して報告されますã?
477             * こã?イベントã?å¢?•Œの報告だけに使用されますã?
478             *
479             * インタフェース LexicalHandler å†?? startCDATA
480             *
481             * @see org.xml.sax.helpers.DefaultHandler2#startCDATA()
482             * @see org.xml.sax.ext.LexicalHandler#startCDATA()
483             */
484            @Override
485            public void startCDATA() {
486                    OGNode node = new OGNode();
487                    node.setNodeType( OGNodeType.Cdata );
488    
489                    ele.addNode( node );
490                    stack.push( ele );
491                    ele = node ;
492                    inCDATA = true;
493            }
494    
495            /**
496             * CDATA セクションの終わりを報告しますã?
497             *
498             * インタフェース LexicalHandler å†?? endCDATA
499             *
500             * @see org.xml.sax.helpers.DefaultHandler2#endCDATA()
501             * @see org.xml.sax.ext.LexicalHandler#endCDATA()
502             */
503            @Override
504            public void endCDATA() {
505                    ele = stack.pop();
506                    inCDATA = false;
507            }
508    
509            /**
510             * DTD 宣è¨?�Œある場合ã?そã?開始を報告しますã?
511             *
512             * start/endDTD イベントã?、ContentHandler の
513             * start/endDocument イベントå?のæœ??の startElement イベントã?前に出現しますã?
514             *
515             * インタフェース LexicalHandler å†?? startDTD
516             *
517             * @param       name    æ–?›¸型名
518             * @param       publicId        宣è¨?�•れた外部 DTD サブセãƒ?ƒˆの公開識別子ã? 宣è¨?�•れてã�?�ªã�??合ã? null
519             * @param       systemId        宣è¨?�•れた外部 DTD サブセãƒ?ƒˆのシスãƒ?ƒ 識別子ã? 宣è¨?�•れてã�?�ªã�??合ã? nullã€?
520             *                ドキュメントã?ベã?ス URI に対しては解決されなã�?�“とに 注意すること
521             * @see org.xml.sax.helpers.DefaultHandler2#startDTD( String , String , String )
522             * @see org.xml.sax.ext.LexicalHandler#startDTD( String , String , String )
523             */
524            @Override
525            public void startDTD( final String name, final String publicId, final String systemId ) {
526                    StringBuilder buf = new StringBuilder();
527                    buf.append( "<!DOCTYPE " ).append( name );
528                    if( publicId != null ) { buf.append( " PUBLIC \"" ).append( publicId ).append( "\"" ); }
529                    if( systemId != null ) { buf.append( "\"" ).append( systemId).append( "\"" ); }
530    
531                    OGNode node = new OGNode( buf.toString() );
532                    node.setNodeType( OGNodeType.DTD );
533                    ele.addNode( node );
534            }
535    
536            /**
537             * DTD 宣è¨??終わりを報告しますã?
538             *
539             * こã?メソãƒ?ƒ‰は、DOCTYPE 宣è¨??終わりを報告するメソãƒ?ƒ‰ですã?
540             * ここでは、何もしませんã€?
541             *
542             * インタフェース LexicalHandler å†?? endDTD
543             *
544             * @see org.xml.sax.helpers.DefaultHandler2#endDTD()
545             * @see org.xml.sax.ext.LexicalHandler#endDTD()
546             */
547            @Override
548            public void endDTD() {
549                    // ここでは何もしませんã€?
550            }
551    
552            /**
553             * å†?ƒ¨および外部の XML エンãƒ?‚£ãƒ?‚£ーのä¸?ƒ¨の開始を報告しますã?
554             *
555             * インタフェース LexicalHandler の記述:
556             *
557             * ※ ここではã€?amp;lt; などのæ–?­—å?がã?lt とã�?�†名ã?エンãƒ?‚£ãƒ?‚£ーで
558             * 報告されるため、å?の??»˜きのæ–?­—å?に復å…?�—てã�?�¾すã?
559             * エンãƒ?‚£ãƒ?‚£ーå†?�‹どã�?�‹を判断する、inEntity フラグã‚?true にセãƒ?ƒˆしますã?
560             * inEntity=true の間ã?ã€?characters(char[],int,int) は、何も処ç�?�—ませんã€?
561             *
562             * @param       name    エンãƒ?‚£ãƒ?‚£ーの名前
563             * @see org.xml.sax.ext.LexicalHandler#startEntity(String)
564             */
565            @Override
566            public void startEntity( final String name ) {
567                    String text = "&" + name + ";" ;
568                    OGNode node = new OGNode( text );
569                    ele.addNode( node );
570                    inEntity = true;
571            }
572    
573            /**
574             * エンãƒ?‚£ãƒ?‚£ーの終わりを報告しますã?
575             *
576             * インタフェース LexicalHandler の記述:
577             *
578             * ※ ここでは、inEntity=false を設定するだけですã?
579             *
580             * @param       name    エンãƒ?‚£ãƒ?‚£ーの名前
581             * @see org.xml.sax.ext.LexicalHandler#endEntity(String)
582             */
583            @Override
584            public void endEntity( final String name ) {
585                    inEntity = false;
586            }
587    
588            /**
589             * 要ç´?‚³ンãƒ?ƒ³ãƒ?�«含まれる無視できる空白æ–?­—ã?通知を受け取りますã?
590             *
591             * インタフェース ContentHandler å†?? ignorableWhitespace
592             *
593             * @param       cbuf    æ–?­—データ配å?(空白æ–?­?
594             * @param       off             æ–?­—é?列å?の開始位置
595             * @param       len             æ–?­—é?列から使用される文字数
596             *
597             * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[],int,int)
598             */
599            @Override
600            public void ignorableWhitespace( final char[] cbuf, final int off, final int len ) {
601                    String text = toText( cbuf,off,len );
602                    OGNode node = new OGNode( text );
603                    ele.addNode( node );
604            }
605    
606            /**
607             * æ–?›¸å†??任意ã?位置にある XML コメントを報告しますã?
608             *
609             * インタフェース LexicalHandler の記述:
610             *
611             * @param       cbuf    æ–?­—データ配å?(コメント文å­?
612             * @param       off             配å?å†??開始位置
613             * @param       len             配å?から読み取られるæ–?­—数
614             *
615             * @see org.xml.sax.helpers.DefaultHandler#characters(char[],int,int)
616             */
617            @Override
618            public void comment( final char[] cbuf, final int off, final int len ) {
619                    String text = toText( cbuf,off,len );
620                    OGNode node = new OGNode( text );
621                    node.setNodeType( OGNodeType.Comment );
622                    ele.addNode( node );
623            }
624    
625            /**
626             * 要ç´??終äº??知を受け取りますã?
627             *
628             * @param       uri                     名前空é–??µ?²?©。要ç´?�Œ名前空é–??µ?²?© を持たなã�??合ã?またã?名前空間å?ç�?�Œ実行されなã�??合ã? null
629             * @param       localName       前置修飾子を含まなã�?ƒ­ーカル名ã?名前空間å?ç�?�Œ行われなã�??合ã?空æ–?­—å?
630             * @param       qName           接頭辞を持つ修飾名ã?修飾名を使用できなã�??合ã?空æ–?­—å?
631             *
632             * @see org.xml.sax.helpers.DefaultHandler#endElement(String,String,String)
633             * @see org.xml.sax.ContentHandler#endElement(String,String,String)
634             */
635            @Override
636            public void endElement( final String uri, final String localName, final String qName ) {
637                    ele = stack.pop();
638            }
639    
640            /**
641             * パã?サー警告ã?通知を受け取りますã?
642             *
643             * インタフェース org.xml.sax.ErrorHandler å†?? warning
644             *
645             * ここでは、パーサー警告ã?å†?®¹を標準エラーに表示しますã?
646             *
647             * @param       ex      例外として符号化された警告情報
648             * @see org.xml.sax.ErrorHandler#warning(SAXParseException)
649             */
650            @Override
651            public void warning( final SAXParseException ex ) {
652                    String errMsg = ex.getMessage() + ":" + ex.getPublicId()
653                                            + CR + "\t" + filename  + " (" + ex.getLineNumber() + ")";
654                    System.err.println( "WARNING:" + errMsg );
655            }
656    
657            /**
658             * æ–?­—é?列からã?æ–?­—å?を作æ?しますã?(改行コードã?統ä¸?
659             *
660             * 処ç�?š„には、new String( cbuf,off,len ) ですが、XMLでリーãƒ?
661             * されたファイルは、改行コードがã€?\r'(CR:復帰)+ '\n'(LF:改è¡?ではなくã?
662             * '\n'(LF:改è¡? のみに処ç�?�•れますã?(されるよã�?�§すã?規定不æ?)
663             * そこで、実行環å¢??改行コーãƒ?System.getProperty("line.separator"))と
664             * 置き換えますã?
665             *
666             * @param       cbuf    æ–?­—データ配å?
667             * @param       off             配å?å†??開始位置
668             * @param       len             配å?から読み取られるæ–?­—数
669             *
670             * @return      æœ?µ‚的な、Stringオブジェクãƒ?
671             */
672            private String toText( final char[] cbuf, final int off, final int len ) {
673                    String text = new String( cbuf,off,len );
674                    return text.replaceAll( "\n", CR );
675            }
676    
677            /**
678             * OGDocument を取得しますã?
679             *
680             * @return      æœ?µ‚的な、OGNodeオブジェクトに相当しまã�?
681             */
682            private OGDocument getDocument() {
683                    OGDocument doc = null;
684                    if( ele != null && ele.getNodeType() == OGNodeType.Document ) {
685                            doc = (OGDocument)ele;
686                            doc.setIdMap( idMap );
687                    }
688                    return doc;
689            }
690    }