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