    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.fukurou.util.Closer ;
    019import org.opengion.fukurou.util.LogWriter;
    020
    021import org.apache.poi.poifs.filesystem.POIFSFileSystem;
    022import org.apache.poi.hssf.eventusermodel.HSSFRequest ;
    023import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
    024import org.apache.poi.hssf.eventusermodel.HSSFListener ;
    025import org.apache.poi.hssf.record.SSTRecord ;
    026import org.apache.poi.hssf.record.Record ;
    027import org.apache.poi.hssf.record.BOFRecord  ;
    028import org.apache.poi.hssf.record.BoundSheetRecord;
    029import org.apache.poi.hssf.record.LabelSSTRecord;
    030//import org.apache.poi.hssf.record.UnicodeString;
    031import org.apache.poi.hssf.record.common.UnicodeString;                 // 5.9.0.0 (2015/09/04) POI変更対応
    032
    033import java.io.File;
    034import java.io.InputStream;
    035import java.io.FileInputStream;
    036import java.io.IOException;
    037
    038/**
    039 * 【EXCEL取込】雛形EXCELシートの解析処理を行う為の、HSSFListener 拡張クラスです。
    040 * このオブジェクトは、HSSFRequest クラスの addListenerForAllRecords メソッドに渡す
    041 * HSSFListener インターフェースを実装しています。また、雛形EXCEL を処理後、ExcelLayout
    042 * 管理クラスを取得することが出来ます。
    043 *
    044 * @og.rev 3.8.0.0 (2005/06/07) 新規追加
    045 * @og.group 帳票システム
    046 *
    047 * @version  4.0
    048 * @author   Kazuhiko Hasegawa
    049 * @since    JDK5.0,
    050 */
    051public class HybsHSSFListener implements HSSFListener {
    052        private SSTRecord sstrec;
    053        private int       sheetNo = -1;
    054        private int       sheetSize = 0;
    055        private boolean   trace  = false;
    056
    057        private ExcelLayout laynot = null;
    058
    059        /**
    060         * 雛形EXCELの {&#064;カラム} 解析情報を設定します。
    061         *
    062         * 雛形EXCELは、HSSFListener を使用して、イベント駆動で取得します。その場合、
    063         * {&#064;カラム}を含むセルを見つける都度、このメソッドを呼び出して、{&#064;カラム}の
    064         * 位置(行列番号)を設定します。
    065         * データEXCELからデータを読み出す場合は、ここで登録したカラムの行列より、読み込みます。
    066         * 具体的には、HSSFListener#processRecord( Record )で、SSTRecord.sid の 情報をキープしておき、
    067         * LabelSSTRecord.sid 毎に、{&#064;カラム}を含むかチェックし、含む場合に、このメソッドに
    068         * 解析情報を設定します。
    069         *
    070         * @og.rev 4.3.4.0 (2008/12/01) POI3.2対応 引数の型変更(SSTRecord の toString() 化)
    071         *
    072         * @param record Recordオブジェクト
    073         */
    074        public void processRecord( final Record record ) {
    075                switch ( record.getSid() ) {
    076                        // Workbook での シート毎に呼ばれます。先行するため、この回数をシート数として数えます。
    077                        case BoundSheetRecord.sid:
    078                                // 4.0.0.0 (2007/11/29) 入れ子if の統合
    079                                if( trace && record instanceof BoundSheetRecord ) {
    080                                        BoundSheetRecord bsr = (BoundSheetRecord) record;
    081                                        System.out.println("Sheet named: " + bsr.getSheetname() );
    082                                }
    083                                sheetSize ++ ;
    084                                break;
    085                        // TYPE_WORKSHEET の場合、シート開始毎に呼ばれます。
    086                        case BOFRecord.sid:
    087                                if( record instanceof BOFRecord ) {
    088                                        BOFRecord bof = (BOFRecord) record;
    089                                        if(bof.getType() == BOFRecord.TYPE_WORKBOOK) {
    090                                                if( trace ) { System.out.println("Encountered workbook"); }
    091                                        }
    092                                        else if(bof.getType() == BOFRecord.TYPE_WORKSHEET) {
    093                                                // シート開始毎に呼ばれるため、現在のシート番号を得るのに使用します。
    094                                                sheetNo++ ;
    095                                                if( trace ) { System.out.println("Encountered sheet [" + sheetNo + "]" ); }
    096                                        }
    097                                }
    098                                break;
    099                        // すべてのレコードにアクセスするために、一度だけ呼ばれます。ここで初期化しておきます。
    100                        case SSTRecord.sid:
    101                                if( record instanceof SSTRecord ) {
    102                                        sstrec = (SSTRecord) record;
    103                                        laynot = new ExcelLayout( sheetSize );
    104                                        if( trace ) { System.out.println( "SSTRecord:[" + sstrec.getNumUniqueStrings() + "]" ); }
    105                        //              for( int k=0; k<sstrec.getNumUniqueStrings(); k++ )  {
    106                        //                      String val = sstrec.getString(k);
    107                        //                      System.out.println("SSTRecord id=[" + k + "]=[" + val + "]" );
    108                        //              }
    109                                }
    110                                break;
    111                        // 文字型のレコードです。
    112                        case LabelSSTRecord.sid:
    113                                if( record instanceof LabelSSTRecord ) {
    114                                        LabelSSTRecord lrec = (LabelSSTRecord) record;
    115
    116                                        int   row  = lrec.getRow();
    117                                        short col  = lrec.getColumn();
    118// POI3.0の場合            String val = sstrec.getString( lrec.getSSTIndex() ) ;
    119                                        UnicodeString ustr = sstrec.getString( lrec.getSSTIndex() ) ;
    120                                        String val = ustr.getString();
    121
    122                                        // カラムに、{@を含む場合は、laynot に雛形情報を追加します。
    123                                        // 整合性チェックは、ExcelLayoutData クラスで行います。
    124                                        if( val != null && val.indexOf( "{@" ) >= 0 ) {
    125                                                if( trace ) { System.out.println("String cell id,sheet,row,col=[" + lrec.getSSTIndex() + "," + sheetNo + "," + row + "," + col + "] => " + val ); }
    126                                                laynot.addModel( sheetNo,val,row,col );
    127                                        }
    128                                }
    129                                break;
    130                        default :
    131                                LogWriter.log( "想定外のイベントを受け取りました。=[" + record.getSid() + "]" );
    132                                break;
    133                }
    134        }
    135
    136        /**
    137         * 雛形EXCELシートの {&#064;カラム} 解析データ管理クラスを返します。
    138         *
    139         * 雛形EXCELを解析し終わった後で、解析データ管理クラスを取り出します。
    140         * 雛形EXCELと、データEXCELが１対１ではないため、リアルタイム処理が出来ません。
    141         * 一旦、すべての雛形EXCELを解析し終わった後で、データEXCEL処理を行う必要があります。
    142         *
    143         * @return      雛形EXCELシート
    144         */
    145        public ExcelLayout getLayout() { return laynot; }
    146
    147        /**
    148         * 雛形EXCEL のシート数を返します。
    149         *
    150         * @return      雛形シート数
    151         */
    152        public int getSheetSize() { return sheetSize; }
    153
    154        /**
    155         * 処理経過情報を表示するかどうか[true/false]を指定します(初期値:false)
    156         *
    157         * イベント毎の状況を、標準出力に出力するかどうかのフラグです。
    158         * 初期値は、false です。
    159         *
    160         * @param       flag    処理経過情報を表示するかどうか[true/false]
    161         */
    162        public void setTrace( final boolean flag ) { trace = flag; }
    163
    164        /**
    165         * EXCELレイアウト情報を取得します。
    166         *
    167         * POIのイベント処理(HSSFListener)で、各イベントごとに処理を行います。
    168         * イベントは、BOFRecord、BoundSheetRecord、SSTRecord、LabelSSTRecord について
    169         * 発生するように設定しています。
    170         *
    171         * @param       file    処理するEXCELファイル
    172         * @param       trace   標準出力にトレース情報を出力するかどうかを指定します。
    173         *
    174         * @return      EXCELレイアウト情報
    175         * @throws IOException 入出力エラーが発生した場合
    176         */
    177        public static ExcelLayout makeExcelLayout( final File file ,final boolean trace ) throws IOException {
    178
    179                FileInputStream fin = null;
    180                InputStream din = null;
    181                final HybsHSSFListener event ;
    182                try {
    183                        fin = new FileInputStream( file );
    184                        POIFSFileSystem poifs = new POIFSFileSystem( fin );
    185                        din = poifs.createDocumentInputStream( "Workbook" );
    186                        HSSFRequest req = new HSSFRequest();
    187
    188                        event = new HybsHSSFListener();
    189                        event.setTrace( trace );                // 標準出力にトレース情報を出力します。
    190
    191                //      req.addListenerForAllRecords( event );  // 全イベントを処理
    192                        req.addListener( event,BOFRecord.sid );
    193                        req.addListener( event,BoundSheetRecord.sid );
    194                        req.addListener( event,SSTRecord.sid );
    195                        req.addListener( event,LabelSSTRecord.sid );
    196
    197                        HSSFEventFactory factory = new HSSFEventFactory();
    198                        factory.processEvents( req,din );
    199                }
    200                finally {
    201                        Closer.ioClose( fin );          // 4.0.0 (2006/01/31) close 処理時の IOException を無視
    202                        Closer.ioClose( din );          // 4.0.0 (2006/01/31) close 処理時の IOException を無視
    203        //              fin.close();
    204        //              din.close();
    205                }
    206
    207                return event.getLayout();
    208        }
    209}