    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.hayabusa.report;
    017
    018import org.opengion.hayabusa.common.HybsSystemException;
    019import org.opengion.fukurou.util.StringUtil;
    020import org.opengion.fukurou.system.Closer ;
    021import org.opengion.fukurou.system.DateSet;                                                     // 6.4.2.0 (2016/01/29)
    022
    023import org.apache.poi.poifs.filesystem.POIFSFileSystem;
    024import org.apache.poi.util.RecordFormatException;                                       // 6.4.6.0 (2016/05/27) poi-3.15
    025
    026import org.apache.poi.hssf.usermodel.HSSFWorkbook;
    027import org.apache.poi.hssf.usermodel.HSSFSheet;
    028import org.apache.poi.hssf.usermodel.HSSFRow;
    029import org.apache.poi.hssf.usermodel.HSSFCell;
    030// import org.apache.poi.hssf.usermodel.HSSFDateUtil;                           // 7.3.0.0 (2021/01/06) Deprecated.
    031import org.apache.poi.ss.usermodel.DateUtil;                                            // 7.3.0.0 (2021/01/06)
    032import org.apache.poi.hssf.usermodel.HSSFRichTextString;
    033
    034import java.io.File;
    035import java.io.InputStream;
    036import java.io.FileInputStream;
    037import java.io.IOException;
    038
    039import java.text.NumberFormat ;
    040import java.text.DecimalFormat ;
    041import java.util.Iterator ;
    042
    043/**
    044 * 【EXCEL取込】雛形EXCELシートの解析処理を行う為の、HSSFListener 拡張クラスです。
    045 * このオブジェクトは、HSSFRequest クラスの addListenerForAllRecords メソッドに渡す
    046 * HSSFListener インターフェースを実装しています。また、雛形EXCEL を処理後、ExcelLayout
    047 * 管理クラスを取得することが出来ます。
    048 *
    049 *   ※ 最新のPOIでは、org.apache.poi.ss.usermodel を使う事で、2003形式、2007形式に対応させます。
    050 *      report パッケージは保守対象外なので、あえて修正しません。
    051 *
    052 * @og.rev 3.8.0.0 (2005/06/07) 新規追加
    053 * @og.group 帳票システム
    054 *
    055 * @version  4.0
    056 * @author   Kazuhiko Hasegawa
    057 * @since    JDK5.0,
    058 */
    059public class ExcelDataPickup {
    060
    061        private final ExcelLayout       layout  ;
    062
    063        private final InputStream       in      ;
    064        private final HSSFWorkbook      wb      ;
    065        private NumberFormat numFormat  ;
    066
    067        private final boolean debug             ;
    068
    069        /**
    070         * 雛形EXCELを処理済みのExcelLayoutオブジェクトと、
    071         * データEXCELファイル名よりオブジェクトを構築します。
    072         *
    073         * 内部で、HSSFWorkbook を構築します。
    074         *
    075         * @param       layout  雛形EXCELを処理済みのExcelLayoutオブジェクト
    076         * @param       filename        データEXCELファイル名
    077         * @param debug デバッグフラグ
    078         */
    079        public ExcelDataPickup( final ExcelLayout layout,final File filename, final boolean debug ) {
    080                this.layout     = layout;
    081                this.debug      = debug;
    082
    083                try {
    084                        in = new FileInputStream( filename );
    085
    086                        final POIFSFileSystem fs = new POIFSFileSystem( in );
    087                        wb = new HSSFWorkbook( fs );
    088                }
    089                catch( final IOException ex) {
    090                        final String errMsg = "ファイル読込みエラー[" + filename.getName() + "]"  ;
    091                        throw new HybsSystemException( errMsg,ex );
    092                }
    093                catch( final RecordFormatException ex) {
    094                        final String errMsg = "無効の形式/データが使用されています。[" + filename.getName() + "]"
    095                                        + "現バージョンのPOIでは読み取ることが出来ません。"
    096                                        + "例えば、自動フィルタの設定されたシートが含まれる場合などです。" ;
    097                        throw new HybsSystemException( errMsg,ex );
    098                }
    099        }
    100
    101        /**
    102         * データEXCELファイル名のシート数を返します。
    103         *
    104         * 内部で、HSSFWorkbook を構築します。
    105         *
    106         * @return      シート数
    107         */
    108        public int getSheetSize() {
    109                return wb.getNumberOfSheets();
    110        }
    111
    112        /**
    113         * データEXCELファイル名のデータをピックアップします。
    114         *
    115         * この処理を行うと、ExcelLayout オブジェクトにデータEXCEL解析結果を
    116         * 保存しますので、処理側でその結果を取り出して使用します。
    117         *
    118         * @og.rev 3.8.1.1 (2005/11/21) デバッグ用コメント修正
    119         *
    120         * @param       modelSheetNo    雛形シート番号
    121         * @param       sheetNo データシート番号
    122         * @param       loopClm 繰返必須カラム(なければ通常の１対１処理)
    123         */
    124        public void execute( final int modelSheetNo, final int sheetNo, final String loopClm ) {
    125
    126                final HSSFSheet sheet = wb.getSheetAt( sheetNo );
    127                layout.dataClear();
    128
    129                if( debug ) { System.out.println( sheetNo + ":" + wb.getSheetName( sheetNo ) ); }
    130
    131                final Iterator<ExcelLayoutData> ite = layout.getLayoutDataIterator( modelSheetNo,loopClm ) ;
    132                while( ite.hasNext() ) {
    133                        final ExcelLayoutData data = ite.next();
    134                        final String clm  = data.getClm();
    135                        final int    edbn = data.getEdbn();
    136                        final int    row  = data.getRowNo();
    137                        final short  col  = data.getColNo();
    138
    139        //              if( clm.indexOf( debugClm ) >= 0 ) { debug = true; }
    140        //              else { debug = false; }
    141
    142                        final String val = getValue( sheet,row,col );
    143                        layout.addData( clm,edbn,val );
    144                        if( debug ) { System.out.println( data.toString() + "=[" + val + "]" ); }
    145                }
    146        }
    147
    148        /**
    149         * シートオブジェクト(HSSFSheet)から行列番号を指定して値を取り出します。
    150         * 行オブジェクト(HSSFRow)や列オブジェクト(HSSFCell)が存在しない場合は、nullを返します。
    151         * それ以外は、各セルタイプに応じて、処理を行います。
    152         * 関数タイプ(HSSFCell.CELL_TYPE_FORMULA)の場合は、まず、文字列として取り出し、ゼロ文字列の
    153         * 場合は、数字タイプとして取り出します。
    154         *
    155         * @og.rev 3.8.0.9 (2005/10/17) 結果を rtrim(右スペース削除)します。
    156         * @og.rev 3.8.1.1 (2005/11/21) デバッグ用コメント修正
    157         * @og.rev 3.9.0.5 (2008/11/27) POI3.2対応 引数の型変更(short⇒int)
    158         * @og.rev 6.5.0.0 (2016/09/30) poi-3.15 対応(Cell.CELL_TYPE_XXXX → CellType.XXXX)
    159         *
    160         * @param       sheet   EXCELのシートオブジェクト
    161         * @param       row             行番号
    162         * @param       col             列番号
    163         *
    164         * @return      セルの値
    165         */
    166        @SuppressWarnings(value={"deprecation"})        // poi-3.15
    167        private String getValue( final HSSFSheet sheet,final int row, final int col ) {
    168
    169                final HSSFRow  oRow  = sheet.getRow(row);
    170                if( oRow == null ) { return null; }
    171                final HSSFCell oCell = oRow.getCell(col);
    172                if( oCell == null ) { return null; }
    173
    174                String strText = "";
    175                HSSFRichTextString richText ;
    176        //      final int nCellType = oCell.getCellType();                                                              // 6.5.0.0 (2016/09/30) poi-3.12
    177        //      switch( nCellType ) {                                                                                                   // 6.5.0.0 (2016/09/30) poi-3.12
    178        //      switch( oCell.getCellTypeEnum() ) {                                                                             // 6.5.0.0 (2016/09/30) poi-3.15
    179                switch( oCell.getCellType() ) {                                                                                 // 8.0.0.0 (2021/07/31) poi-4.1.2.jar → poi-5.0.0.jar
    180        //              case HSSFCell.CELL_TYPE_NUMERIC:                                                                        // 6.5.0.0 (2016/09/30) poi-3.12
    181                        case NUMERIC:                                                                                                           // 6.5.0.0 (2016/09/30) poi-3.15
    182                                        strText = getNumericTypeString( oCell );
    183                                        break;
    184        //              case HSSFCell.CELL_TYPE_STRING:                                                                         // 6.5.0.0 (2016/09/30) poi-3.12
    185                        case STRING:                                                                                                            // 6.5.0.0 (2016/09/30) poi-3.15
    186        // POI3.0               strText = oCell.getStringCellValue();
    187                                        richText = oCell.getRichStringCellValue();
    188                                        strText =  richText.getString();
    189                                        if( debug ) { System.out.print( "String :" ); }
    190                                        break;
    191        //              case HSSFCell.CELL_TYPE_FORMULA:                                                                        // 6.5.0.0 (2016/09/30) poi-3.12
    192                        case FORMULA:                                                                                                           // 6.5.0.0 (2016/09/30) poi-3.15
    193        //                              strText = oCell.getCellFormula();
    194        // POI3.0               strText = oCell.getStringCellValue();
    195                                        richText = oCell.getRichStringCellValue();
    196                                        strText =  richText.getString();
    197                                        if( strText == null || strText.isEmpty() ) {
    198                                                strText = getNumericTypeString( oCell );
    199                                        }
    200                                        else {
    201                                                if( debug ) { System.out.print( "Formula:" ); }
    202                                        }
    203                                        break;
    204        //              case HSSFCell.CELL_TYPE_BOOLEAN:                                                                        // 6.5.0.0 (2016/09/30) poi-3.12
    205                        case BOOLEAN:                                                                                                           // 6.5.0.0 (2016/09/30) poi-3.15
    206                                        strText = String.valueOf(oCell.getBooleanCellValue());
    207                                        if( debug ) { System.out.print( "Boolean:" ); }
    208                                        break;
    209        //              case HSSFCell.CELL_TYPE_BLANK :                                                                         // 6.5.0.0 (2016/09/30) poi-3.12
    210                        case BLANK  :                                                                                                           // 6.5.0.0 (2016/09/30) poi-3.15
    211                                        if( debug ) { System.out.print( "Blank  :" ); }
    212                                        break;
    213        //              case HSSFCell.CELL_TYPE_ERROR :                                                                         // 6.5.0.0 (2016/09/30) poi-3.12
    214                        case ERROR  :                                                                                                           // 6.5.0.0 (2016/09/30) poi-3.15
    215                                        if( debug ) { System.out.print( "Error  :" ); }
    216                                        break;
    217                        default :
    218        //                              if( debug ) { System.out.print( "Other " + nCellType + ":" ); }
    219        //                              if( debug ) { System.out.print( "Other " + oCell.getCellTypeEnum() + ":" ); }   // 6.5.0.0 (2016/09/30) poi-3.15
    220                                        if( debug ) { System.out.print( "Other " + oCell.getCellType() + ":" ); }               // 8.0.0.0 (2021/07/31) poi-4.1.2.jar → poi-5.0.0.jar
    221                                break;
    222                }
    223
    224                return StringUtil.rTrim( strText );             // 3.8.0.9 (2005/10/17)
    225        }
    226
    227        /**
    228         * セル値が数字の場合に、数字か日付かを判断して、対応する文字列を返します。
    229         *
    230         * @og.rev 3.8.1.1 (2005/11/21) デバッグ用コメント修正
    231         * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します。
    232         *   ※ 最新のPOIでは、org.apache.poi.ss.usermodel を使う事で、2003形式、2007形式に対応させます。
    233         *      report パッケージは保守対象外なので、あえて修正しません。
    234         * @og.rev 7.3.0.0 (2021/01/06) HSSFDateUtil(Deprecated) → DateUtil (poi-4.1.2)
    235         *
    236         * @param oCell Cellオブジェクト
    237         *
    238         * @return      数字の場合は、文字列に変換した結果を、日付の場合は、"yyyyMMddHHmmss" 形式で返します。
    239         */
    240        private String getNumericTypeString( final HSSFCell oCell ) {
    241                final String strText ;
    242
    243                final double dval = oCell.getNumericCellValue() ;
    244        //      if( HSSFDateUtil.isCellDateFormatted( oCell ) ) {
    245        //              strText = DateSet.getDate( HSSFDateUtil.getJavaDate( dval ).getTime() , "yyyyMMddHHmmss" );
    246
    247                if( DateUtil.isCellDateFormatted( oCell ) ) {                           // 7.3.0.0 (2021/01/06) poi-4.1.2
    248                        strText = DateSet.getDate( DateUtil.getJavaDate( dval ).getTime() , "yyyyMMddHHmmss" );
    249                        if( debug ) { System.out.print( "Date   :" ); }
    250                }
    251                else {
    252                        // 3.8.0.9 (2005/10/17) 数字について、NumberFormat を行います。
    253                        if( numFormat == null ) {
    254                                numFormat = NumberFormat.getInstance();
    255                                if( numFormat instanceof DecimalFormat ) {
    256                                        ((DecimalFormat)numFormat).applyPattern( "#.####" );
    257                                }
    258                        }
    259                        strText = numFormat.format( dval );
    260                        if( debug ) { System.out.print( "Numeric:" ); }
    261                }
    262                return strText ;
    263        }
    264
    265        /**
    266         * EXCEL をオープンした InputStream を閉じます。
    267         */
    268        public void close() {
    269                Closer.ioClose( in );           // 4.0.0 (2006/01/31) close 処理時の IOException を無視
    270        }
    271}