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