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.model; 017 018import org.opengion.fukurou.system.OgRuntimeException ; // 6.4.2.0 (2016/01/29) 019import org.opengion.fukurou.system.Closer; // 6.2.0.0 (2015/02/27) 020import org.opengion.fukurou.system.ThrowUtil; // 6.5.0.1 (2016/10/21) 021import org.opengion.fukurou.xml.HybsErrorListener; // 6.4.0.2 (2015/12/11) 022import static org.opengion.fukurou.system.HybsConst.CR; // 6.1.0.0 (2014/12/26) refactoring 023 024import java.io.InputStream; 025import java.io.File; // 6.2.0.0 (2015/02/27) 026import java.io.IOException; 027import java.util.List; // 6.0.3.0 (2014/11/13) XSSFイベントモデル 028import java.util.ArrayList; // 6.0.3.0 (2014/11/13) XSSFイベントモデル 029 030import org.apache.poi.xssf.eventusermodel.XSSFReader; 031import org.apache.poi.xssf.model.SharedStringsTable; 032import org.apache.poi.xssf.model.StylesTable; // 6.2.0.0 (2015/02/27) 033import org.apache.poi.xssf.usermodel.XSSFRichTextString; 034import org.apache.poi.openxml4j.opc.OPCPackage; 035import org.apache.poi.openxml4j.exceptions.InvalidFormatException ; 036import org.apache.poi.openxml4j.exceptions.OpenXML4JException ; // 6.1.0.0 (2014/12/26) findBugs 037import org.xml.sax.Attributes; 038import org.xml.sax.InputSource; 039import org.xml.sax.SAXException; 040import org.xml.sax.XMLReader; 041import org.xml.sax.helpers.DefaultHandler; 042import javax.xml.parsers.SAXParserFactory; // 6.8.2.4 (2017/11/20) 7.0.0.0準備(java9対応) 043import javax.xml.parsers.ParserConfigurationException; // 6.8.2.4 (2017/11/20) 7.0.0.0準備(java9対応) 044 045/** 046 * POI による、Excel(xlsx)の読み取りクラスです。 047 * 048 * xlsx形式のEXCELを、イベント方式でテキストデータを読み取ります。 049 * このクラスでは、XSSF(.xlsx)形式のファイルを、TableModelHelper を介したイベントで読み取ります。 050 * TableModelHelperイベントは、openGion形式のファイル読み取りに準拠した方法をサポートします。 051 * ※ openGion形式のEXCELファイルとは、#NAME 列に、カラム名があり、#で始まる 052 * レコードは、コメントとして判断し、読み飛ばす処理の事です。 053 * 054 * @og.rev 6.0.3.0 (2014/11/13) 新規作成 055 * @og.rev 6.2.0.0 (2015/02/27) パッケージ変更(util → model),クラス名変更(ExcelReader_XSSF → EventReader_XLSX) 056 * @og.group ファイル入力 057 * 058 * @version 6.0 059 * @author Kazuhiko Hasegawa 060 * @since JDK7.0, 061 */ 062public final class EventReader_XLSX implements EventReader { 063 /** このプログラムのVERSION文字列を設定します。 {@value} */ 064 private static final String VERSION = "7.2.9.4 (2020/11/20)" ; 065 066 /** 6.2.0.0 (2015/02/27) タイプのenum */ 067 private enum XSSFDataType { 068// private static enum XSSFDataType { 069 BOOL, 070 ERROR, 071 FORMULA, 072 INLINESTR, 073 SSTINDEX, 074 NUMBER, 075 } 076 077 /** 078 * 引数ファイル(Excel)を、XSSFイベントモデルを使用してテキスト化します。 079 * 080 * TableModelHelperは、EXCEL読み取り処理用の統一されたイベント処理クラスです。 081 * openGion特有のEXCEL処理方法(#NAME , 先頭行#コメントなど)を実装しています。 082 * これは、HSSFやXSSFの処理を、統一的なイベントモデルで扱うためです。 083 * SSモデルが良いのですが、巨大なXSSF(.xlsx)ファイルを解析すると、OutOfMemoryエラーが 084 * 発生する為、個々に処理する必要があります。 085 * あくまで、読み取り限定であれば、こちらのイベントモデルで十分です。 086 * 087 * @og.rev 6.0.3.0 (2014/11/13) 新規作成 088 * @og.rev 6.1.0.0 (2014/12/26) シートの数のイベント 089 * @og.rev 6.2.0.0 (2015/02/27) staticメソッドをインスタンスメソッドに変更 090 * @og.rev 6.4.0.2 (2015/12/11) org.xml.sax.ErrorHandler の登録 091 * @og.rev 6.4.3.2 (2016/02/19) findBugs対応。冗長な null チェックが行われている。 092 * @og.rev 6.8.2.4 (2017/11/20) 7.0.0.0準備(java9対応) 093 * @og.rev 7.2.9.4 (2020/11/20) spotbugs:null 値を例外経路で利用している可能性がある 094 * 095 * @param file 入力ファイル 096 * @param helper イベント処理するオブジェクト 097 */ 098 @Override 099 public void eventReader( final File file , final TableModelHelper helper ) { 100 OPCPackage pkg = null; 101 XMLReader parser = null; // 6.4.0.2 (2015/12/11) org.xml.sax.ErrorHandler の登録 102 103 try { 104 // 6.2.0.0 (2015/02/27) TableModelHelper 変更に伴う修正 105 helper.startFile( file ); 106 pkg = OPCPackage.open( file ); // InvalidFormatException 107 final XSSFReader rd = new XSSFReader( pkg ); // IOException , OpenXML4JException 108 109 parser = SAXParserFactory.newInstance().newSAXParser().getXMLReader(); // 6.8.2.4 (2017/11/20) 7.0.0.0準備(java9対応) 110 111 parser.setErrorHandler( new HybsErrorListener() ); // 6.4.0.2 (2015/12/11) org.xml.sax.ErrorHandler の登録 112 113 final List<SheetObj> shtList = getSheetList( rd,parser ); // SAXException , InvalidFormatException 114 helper.sheetSize( shtList.size() ); // 6.1.0.0 (2014/12/26) 115 116 final SharedStringsTable sst = rd.getSharedStringsTable(); // IOException , InvalidFormatException 117 final StylesTable styles = rd.getStylesTable(); 118 119 final SheetHandler handler = new SheetHandler( styles,sst,helper ); // ContentHandler のサブクラス 120 parser.setContentHandler( handler ); // ContentHandler のサブクラスを設定 121 122 // Iterator<InputStream> sheets = rd.getSheetsData(); 123 // while(sheets.hasNext()) { 124 // sheet = sheets.next(); 125 // ・・・・・ 126 // } 127 // 形式で、全シート対象に処理できますが、シート名が取り出せません。 128 129 InputStream sheet = null; 130 for( int i=0; i<shtList.size(); i++ ) { 131 final SheetObj sht = shtList.get(i); 132 133 if( helper.startSheet( sht.getName() , i ) ) { // イベント処理 134 try { 135 // シートIDは、rId# で取得できる。 136 sheet = rd.getSheet( sht.getRid() ); // IOException , InvalidFormatException 137 parser.parse( new InputSource( sheet ) ); // IOException 138 } 139 finally { 140 Closer.ioClose( sheet ); 141 } 142 } 143 helper.endSheet( i ); // イベント処理 144 } 145 } 146 // 6.1.0.0 (2014/12/26) findBugs: Bug type REC_CATCH_EXCEPTION (click for details) 147 // 例外がスローされないのに例外をキャッチしています。 148 catch( final OpenXML4JException ex ) { // サブクラスの、InvalidFormatException も含まれます。 149 final String errMsg = ".xlsxのファイル解析に失敗しました。" 150 + " filename=" + file + CR 151 + ex.getMessage() ; 152 throw new OgRuntimeException( errMsg , ex ); 153 } 154 catch( final ParserConfigurationException ex ) { // 6.8.2.4 (2017/11/20) 7.0.0.0準備(java9対応) 155 final String errMsg = "要求された構成を満たすパーサーを生成できませんでした。" 156 + " filename=" + file + CR 157 + ex.getMessage() ; 158 throw new OgRuntimeException( errMsg , ex ); 159 } 160 catch( final SAXException ex ) { 161 final String errMsg = "SAX の一般的なエラーまたは警告が発生しました。" 162 + " filename=" + file + CR 163 // 6.4.0.2 (2015/12/11) org.xml.sax.ErrorHandler の登録 164 + parser == null ? ex.getMessage() 165 : parser.getErrorHandler().toString(); 166 // 6.4.3.2 (2016/02/19) findBugs対応。冗長な null チェックが行われている。 167 // parser の処理中に発生するエラーなので、当然、parser は、null ではない。 168 // 7.2.9.4 (2020/11/20) spotbugs:null 値を例外経路で利用している可能性がある 169 // + parser.getErrorHandler().toString(); 170 171 throw new OgRuntimeException( errMsg , ex ); 172 } 173 catch( final IOException ex ) { 174 final String errMsg = ".xlsxのファイルの読み取りに失敗しました。" 175 + " filename=" + file + CR 176 + ex.getMessage() ; 177 throw new OgRuntimeException( errMsg , ex ); 178 } 179 finally { 180 if( pkg != null ) { 181 pkg.revert(); // Close the package WITHOUT saving its content. 182 // Closer.ioClose( pkg ); // OPCPackage を close すると、書き戻しされる。 183 } 184 helper.endFile( file ); // 6.2.0.0 (2015/02/27) 185 } 186 } 187 188 /** 189 * この内部クラスは、XSSFイベントモデルに基づいた、xlsxファイルを SAX処理します。 190 * 191 * この処理のオリジナルは、https://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/FromHowTo.java です。 192 * 193 * また、日付変換で、StylesTable を使用するのは、http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xssf/eventusermodel/XLSX2CSV.java です。 194 * 195 * DefaultHandler を継承しており、xlsx の シート処理を行い、カラム番号と値を取得します。 196 * このクラス自体は、内部で使用されるため、TableModelHelper を引数に設定することで、 197 * 外部から、EXCELのセル情報の取得が可能です。 198 * 199 * @og.rev 6.0.3.0 (2014/11/13) 新規作成 200 * @og.rev 6.2.0.0 (2015/02/27) 日付型の処理(DATE=0,DATETIME=1,TIME=2) 201 * 202 * @see org.xml.sax.helpers.DefaultHandler 203 */ 204 private static final class SheetHandler extends DefaultHandler { 205 private final SharedStringsTable sst ; 206 private final TableModelHelper helper; 207 private final ExcelStyleFormat format; 208 209 private String lastContents = "" ; // 6.3.9.0 (2015/11/06) 初期化 210 private XSSFDataType nextDataType = XSSFDataType.NUMBER; // 6.2.0.0 (2015/02/27) 初期化 211 private String cellStyleStr ; // 6.2.0.0 (2015/02/27) 初期化 212 213 private int rowNo = -1; // 現在の行番号 214 private int colNo = -1; // 現在の列番号 215 216 private boolean isRowSkip ; // 行の読み取りを行うかどうか 217 218 /** 219 * コンストラクター 220 * 221 * SharedStringsTable は、テキストの値を持っているオブジェクトです。 222 * ここで指定する TableModelHelper に対して、パーサー処理の結果がセットされます。 223 * 224 * @og.rev 6.0.3.0 (2014/11/13) 新規作成 225 * @og.rev 6.2.0.0 (2015/02/27) 日付型の処理(DATE=0,DATETIME=1,TIME=2) 226 * @og.rev 6.4.1.1 (2016/01/16) PMD refactoring. It is a good practice to call super() in a constructor 227 * 228 * @param styles StylesTableオブジェクト 229 * @param sst SharedStringsTableオブジェクト 230 * @param helper イベント処理するオブジェクト 231 */ 232 public SheetHandler( final StylesTable styles , final SharedStringsTable sst , final TableModelHelper helper ) { 233 super(); 234 this.sst = sst; 235 this.helper = helper; 236 format = new ExcelStyleFormat( styles ); // 6.2.0.0 (2015/02/27) StylesTable 追加 237 } 238 239 /** 240 * 要素の開始通知を受け取ります。 241 * 242 * インタフェース ContentHandler 内の startElement メソッドをオーバーライドしています。 243 * パーサは XML 文書内の各要素の前でこのメソッドを呼び出します。 244 * 各 startElement イベントには対応する endElement イベントがあります。 245 * これは、要素が空である場合も変わりません。対応する endElement イベントの前に、 246 * 要素のコンテンツ全部が順番に報告されます。 247 * ここでは、タグがレベル3以上の場合は、上位タグの内容として取り扱います。よって、 248 * タグに名前空間が定義されている場合、その属性は削除します。 249 * 250 * @og.rev 6.0.3.0 (2014/11/13) 新規作成 251 * @og.rev 6.2.0.0 (2015/02/27) 日付型の処理(DATE=0,DATETIME=1,TIME=2) 252 * 253 * @param namespace 名前空間 URI 254 * @param localName 前置修飾子を含まないローカル名。名前空間処理が行われない場合は空文字列 255 * @param qname 前置修飾子を持つ修飾名。修飾名を使用できない場合は空文字列 256 * @param attributes 要素に付加された属性。属性が存在しない場合、空の Attributesオブジェクト 257 * @see org.xml.sax.helpers.DefaultHandler#startElement(String , String , String , Attributes ) 258 */ 259 @Override 260 public void startElement( final String namespace, final String localName, final String qname, final Attributes attributes ) { 261 if( "row".equals(qname) ) { // row 262 rowNo = Integer.parseInt( attributes.getValue("r") ) - 1; // 0 から始まる 263 isRowSkip = false; 264 } 265 else if( isRowSkip ) { return ; } 266 else if( "c".equals(qname) ) { // c => cell 267 final String kigo = attributes.getValue("r") ; // Excelの行列記号(A1 など) 268 final int[] rowCol = POIUtil.kigo2rowCol( kigo ); // Excelの行列記号を、行番号と列番号に分解します。 269 270 // rowNo = rowCol[0]; // 行番号・・・・ 271 colNo = rowCol[1]; // カラム番号 272 273 // 6.2.0.0 (2015/02/27) 日付型の処理 274 nextDataType = XSSFDataType.NUMBER; 275 cellStyleStr = attributes.getValue("s"); 276 // fmtIdx = -1; 277 // fmtStr = null; 278 279 final String cellType = attributes.getValue("t"); 280 if( "b".equals(cellType) ) { nextDataType = XSSFDataType.BOOL; } 281 else if( "e".equals(cellType) ) { nextDataType = XSSFDataType.ERROR; } 282 else if( "inlineStr".equals(cellType) ) { nextDataType = XSSFDataType.INLINESTR; } 283 else if( "s".equals(cellType) ) { nextDataType = XSSFDataType.SSTINDEX; } 284 else if( "str".equals(cellType) ) { nextDataType = XSSFDataType.FORMULA; } 285 } 286 lastContents = ""; // なんでもクリアしておかないと、関数文字列を拾ってしまう。 287 } 288 289 /** 290 * 要素の終了通知を受け取ります。 291 * 292 * インタフェース ContentHandler 内の endElement メソッドをオーバーライドしています。 293 * SAX パーサは、XML 文書内の各要素の終わりにこのメソッドを呼び出します。 294 * 各 endElement イベントには対応する startElement イベントがあります。 295 * これは、要素が空である場合も変わりません。 296 * 297 * @og.rev 6.0.3.0 (2014/11/13) 新規作成 298 * @og.rev 6.2.0.0 (2015/02/27) 日付型の処理(DATE=0,DATETIME=1,TIME=2) 299 * @og.rev 6.5.0.1 (2016/10/21) ex.toString() の代わりに、ThrowUtil#ogThrowMsg(String,Throwable) を使います。 300 * @og.rev 6.8.2.4 (2017/11/20) POIで作成したEXCEL(XLSX)は、文字列を、inlineStr で持っている為、取り出し方が特殊になります。 301 * @og.rev 7.0.0.0 (2018/10/01) 警告:[deprecation] SharedStringsTableのgetEntryAt(int)は推奨されません (POI4.0.0) 302 * 303 * @param namespace 名前空間 URI 304 * @param localName 前置修飾子を含まないローカル名。名前空間処理が行われない場合は空文字列 305 * @param qname 前置修飾子を持つ XML 1.0 修飾名。修飾名を使用できない場合は空文字列 306 * @see org.xml.sax.helpers.DefaultHandler#endElement(String , String , String ) 307 */ 308 @Override 309 public void endElement( final String namespace, final String localName, final String qname ) { 310 isRowSkip = helper.isSkip( rowNo ); // イベント 311 312 if( isRowSkip ) { return ; } 313 314 String thisStr = null; 315 316 // v は、値なので、空の場合は、イベントが発生しない。 317 if( "v".equals(qname) ) { // v の時の値出力を行う。 318 // Process the last contents as required. 319 // Do now, as characters() may be called more than once 320 switch( nextDataType ) { 321 case BOOL: 322 // 6.3.9.0 (2015/11/06) ゼロ文字列のチェックを追加 323 thisStr = lastContents.isEmpty() || lastContents.charAt(0) == '0' ? "FALSE" : "TRUE"; 324 break; 325 326 case ERROR: 327 thisStr = "\"ERROR:" + lastContents + '"'; 328 break; 329 330 case FORMULA: 331 // A formula could result in a string value, 332 // so always add double-quote characters. 333 thisStr = '"' + lastContents + '"'; 334 break; 335 336 case INLINESTR: 337 // TODO: have seen an example of this, so it's untested. 338 thisStr = new XSSFRichTextString( lastContents ).toString(); 339 break; 340 341 case SSTINDEX: 342 final String sstIndex = lastContents; 343 try { 344 final int idx = Integer.parseInt( sstIndex ); 345// thisStr = new XSSFRichTextString( sst.getEntryAt(idx) ).toString(); 346 thisStr = sst.getItemAt(idx).getString(); // 7.0.0.0 (2018/10/01) poi-4.0.0 Deprecated. 347 } 348 catch( final NumberFormatException ex ) { 349 final String errMsg = ThrowUtil.ogThrowMsg( "Failed to parse SST index [" + sstIndex + "]: ",ex ) ; 350 System.out.println( errMsg ); 351 } 352 break; 353 354 case NUMBER: 355 thisStr = format.getNumberValue( cellStyleStr,lastContents ); 356 break; 357 358 default: 359 thisStr = "(TODO: Unexpected type: " + nextDataType + ")"; 360 break; 361 } 362 } 363 // 6.8.2.4 (2017/11/20) POIで作成したEXCEL(XLSX)は、文字列を、inlineStr で持っている為、取り出し方が特殊になります。 364 else if( "t".equals(qname) && nextDataType == XSSFDataType.INLINESTR ) { // t で、INLINESTR の時 365 // TODO: have seen an example of this, so it's untested. 366 thisStr = new XSSFRichTextString( lastContents ).toString(); 367 } 368 369 if( thisStr != null ) { 370 // v => contents of a cell 371 // Output after we've seen the string contents 372 // 文字列(値) 行 列 373 374 helper.value( thisStr, rowNo , colNo ); 375 } 376 } 377 378 /** 379 * 要素内の文字データの通知を受け取ります。 380 * 381 * インタフェース ContentHandler 内の characters メソッドをオーバーライドしています。 382 * 各文字データチャンクに対して特殊なアクション (ノードまたはバッファへのデータの追加、 383 * データのファイルへの出力など) を実行することができます。 384 * 385 * @og.rev 6.0.3.0 (2014/11/13) 新規作成 386 * @og.rev 6.4.1.2 (2016/01/22) void で 途中で、return しているが、難しいロジックでないので、統合する。 387 * 388 * @param buffer 文字データ配列 389 * @param start 配列内の開始位置 390 * @param length 配列から読み取られる文字数 391 * @see org.xml.sax.helpers.DefaultHandler#characters(char[] , int , int ) 392 */ 393 @Override 394 public void characters( final char[] buffer, final int start, final int length ) { 395 if( !isRowSkip ) { 396 lastContents += new String( buffer, start, length ); // StringBuilder#append より速かった。 397 } 398 } 399 } 400 401 /** 402 * シート一覧を、XSSFReader から取得します。 403 * 404 * 取得元が、XSSFReader なので、xlsx 形式のみの対応です。 405 * 汎用的なメソッドではなく、大きな xlsx ファイルは、通常の DOM処理すると、 406 * 大量のメモリを消費する為、イベントモデルで処理する場合に、使います。 407 * 408 * EXCEL上のシート名を、配列で返します。 409 * 410 * @og.rev 6.0.3.0 (2014/11/13) 新規作成 411 * 412 * @param rd XSSFReaderオブジェクト 413 * @param parser XMLReaderオブジェクト 414 * @return シート名とシートIDを持つオブジェクトのリスト 415 * @throws SAXException SAX の一般的なエラーが発生 416 * @throws IOException SAXパース処理時のI/Oエラー 417 * @throws InvalidFormatException よみとったEXCEL ファイルのフォーマットが異なる。 418 */ 419 public static List<SheetObj> getSheetList( final XSSFReader rd, final XMLReader parser ) 420 throws SAXException,IOException,InvalidFormatException { 421 final List<SheetObj> shtList = new ArrayList<>(); 422 423 parser.setContentHandler( 424 new DefaultHandler() { 425 /** 426 * 要素の開始通知を受け取ります。 427 * 428 * @param uri 名前空間 URI 429 * @param localName 前置修飾子を含まないローカル名。名前空間処理が行われない場合は空文字列 430 * @param name 前置修飾子を持つ修飾名。修飾名を使用できない場合は空文字列 431 * @param attributes 要素に付加された属性。属性が存在しない場合、空の Attributesオブジェクト 432 * @see org.xml.sax.helpers.DefaultHandler#startElement(String , String , String , Attributes ) 433 */ 434 public void startElement( final String uri, final String localName, final String name, final Attributes attributes) { 435 if( "sheet".equals(name) ) { 436 final String shtNm = attributes.getValue("name"); // シート名 437 final String shtId = attributes.getValue("r:id"); // シートID( rId# #は、1から始まる ) 438 shtList.add( new SheetObj( shtNm,shtId ) ); 439 } 440 } 441 } 442 ); 443 444 InputStream workbk = null; 445 try { 446 workbk = rd.getWorkbookData(); // IOException,InvalidFormatException 447 parser.parse( new InputSource( workbk ) ); // IOException,SAXException 448 } 449 finally { 450 Closer.ioClose( workbk ); 451 } 452 453 return shtList; 454 } 455 456 /** 457 * シート名とシートIDを持つオブジェクトのインナークラス 458 * 459 * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善 460 */ 461 private static final class SheetObj { 462 private final String name; 463 private final String rid ; 464 465 /** 466 * シート名とシートIDを引数に取るコンストラクター 467 * 468 * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善 469 * 470 * @param name シート名 471 * @param rid シートID(rId# #は、1から始まる番号) 472 */ 473 public SheetObj( final String name , final String rid ) { 474 this.name = name; 475 this.rid = rid; 476 } 477 478 /** 479 * シート名を返します。 480 * 481 * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善 482 * 483 * @return シート名 484 */ 485 public String getName() { return name ; } 486 487 /** 488 * シートIDを返します。 489 * 490 * @og.rev 6.1.0.0 (2014/12/26) Excel関係改善 491 * 492 * @return シートID(rId# #は、1から始まる番号) 493 */ 494 public String getRid() { return rid ; } 495 } 496 497 /** 498 * アプリケーションのサンプルです。 499 * 500 * 入力ファイル名 は必須で、第一引数固定です。 501 * 502 * Usage: java org.opengion.fukurou.model.EventReader_XLSX 入力ファイル名 503 * 504 * @og.rev 6.0.3.0 (2014/11/13) 新規作成 505 * @og.rev 6.2.0.0 (2015/02/27) staticメソッドをインスタンスメソッドに変更 506 * 507 * @param args コマンド引数配列 508 */ 509 public static void main( final String[] args ) { 510 final String usageMsg = "Usage: java org.opengion.fukurou.model.EventReader_XLSX 入力ファイル名" ; 511 if( args.length == 0 ) { 512 System.err.println( usageMsg ); 513 return ; 514 } 515 516 final File file = new File( args[0] ); 517 final EventReader reader = new EventReader_XLSX(); 518 519 reader.eventReader( // 6.2.0.0 (2015/02/27) 520 file, 521 new TableModelHelper() { 522 /** 523 * シートの読み取り開始時にイベントが発生します。 524 * 525 * @param shtNm シート名 526 * @param shtNo シート番号(0~) 527 * @return true:シートの読み取り処理を継続します/false:このシートは読み取りません。 528 */ 529 public boolean startSheet( final String shtNm,final int shtNo ) { 530 System.out.println( "S[" + shtNo + "]=" + shtNm ); 531 return super.startSheet( shtNm,shtNo ); 532 } 533 534 // public void columnNames( final String[] names ) { 535 // System.out.println( "NM=" + java.util.Arrays.toString( names ) ); 536 // } 537 538 // public void values( final String[] vals,final int rowNo ) { 539 // System.out.println( "V[" + rowNo + "]=" + java.util.Arrays.toString( vals ) ); 540 // } 541 542 // public boolean isSkip( final int rowNo ) { 543 // super.isSkip( rowNo ); 544 // return false; 545 // } 546 547 /** 548 * 読み取り状態の時に、rowNo,colNo にあるセルの値を引数にイベントが発生します。 549 * 550 * @param val 文字列値 551 * @param rowNo 行番号(0~) 552 * @param colNo 列番号(0~) 553 * @return 読み取りするかどうか(true:読み取りする/false:読み取りしない) 554 */ 555 public boolean value( final String val,final int rowNo,final int colNo ) { 556 System.out.println( "R[" + rowNo + "],C[" + colNo + "]=" + val ); 557 return super.value( val,rowNo,colNo ); 558 } 559 } 560 ); 561 } 562}