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     */
016    package org.opengion.plugin.io;
017    
018    import java.io.BufferedReader;
019    import java.io.FileInputStream;
020    import java.io.IOException;
021    import java.io.InputStream;
022    import java.text.DecimalFormat;
023    import java.text.NumberFormat;
024    
025    import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
026    import org.apache.poi.ss.usermodel.Cell;
027    import org.apache.poi.ss.usermodel.DateUtil;
028    import org.apache.poi.ss.usermodel.RichTextString;
029    import org.apache.poi.ss.usermodel.Row;
030    import org.apache.poi.ss.usermodel.Sheet;
031    import org.apache.poi.ss.usermodel.Workbook;
032    import org.apache.poi.ss.usermodel.WorkbookFactory;
033    import org.apache.poi.ss.usermodel.CreationHelper;
034    import org.apache.poi.ss.usermodel.FormulaEvaluator;
035    import org.opengion.fukurou.util.Closer;
036    import org.opengion.fukurou.util.StringUtil;
037    import org.opengion.fukurou.util.HybsDateUtil;
038    import org.opengion.hayabusa.common.HybsSystem;
039    import org.opengion.hayabusa.common.HybsSystemException;
040    import org.opengion.hayabusa.db.DBTableModelUtil;
041    
042    /**
043     * POI による、EXCELバイナリファイルを読み取る実?ラスです?
044     *
045     * ファイル名?シート名を指定して、データを読み取ることが可能です?
046     * 第?ラ? # で始まる行?、コメント行なので、読み飛?します?
047     * カラ?の?行で、カラ??null の場合?、その列?読み飛?します?
048     *
049     * 入力形式?、openXML形式にも対応して?す?
050     * ファイルの?に応じて?xlsと.xlsxのどちらで読み取るか?、?部?
051     * 自動判定されます?
052     *
053     * @og.rev 3.5.4.8 (2004/02/23) 新規作?
054     * @og.rev 4.3.6.7 (2009/05/22) ooxml形式対?
055     * @og.group ファイル入?
056     *
057     * @version  4.0
058     * @author   Kazuhiko Hasegawa
059     * @since    JDK5.0,
060     */
061    public class TableReader_Excel extends TableReader_Default {
062            //* こ?プログラ??VERSION??を設定します?       {@value} */
063            private static final String VERSION = "5.5.8.2 (2012/11/09)" ;
064    
065            private String  filename                = null;         // 3.5.4.3 (2004/01/05)
066            private String  sheetName               = null;         // 3.5.4.2 (2003/12/15)
067            private String  sheetNos                = null;         // 5.5.7.2 (2012/10/09)
068    
069            private String  constKeys               = null;         // 5.5.8.2 (2012/11/09) 固定?となるカラ?(CSV形?
070            private String  constAdrs               = null;         // 5.5.8.2 (2012/11/09) 固定?となるアドレス(????・・・)
071            private String  nullBreakClm    = null;         // 5.5.8.2 (2012/11/09) 取込み条件/Sheet BREAK条件
072    
073            /**
074             * DBTableModel から ?式???タを作?して,BufferedReader より読み取ります?
075             * コメン?空行を除き???の行?、??名が?です?
076             * それ以降?、コメン?空行を除き???タとして読み込んで?ます?
077             * こ?メソ?は、EXCEL 読み込み時に使用します?
078             *
079             * @og.rev 4.0.0.0 (2006/09/31) 新規追?
080             * @og.rev 5.1.6.0 (2010/05/01) columns 処?追?
081             * @og.rev 5.1.6.0 (2010/05/01) skipRowCountの追?
082             * @og.rev 5.1.8.0 (2010/07/01) Exception をきちっと記述(InvalidFormatException)
083             * @og.rev 5.2.1.0 (2010/10/01) setTableColumnValues メソ?を経由して、テーブルに??タをセ?する?
084             * @og.rev 5.5.1.2 (2012/04/06) HeaderData ?try の上に?、エラーメ?ージを取得できるようにする?
085             * @og.rev 5.5.7.2 (2012/10/09) sheetNos 追?よる?シート?マ?ジ読み取りサポ??
086             * @og.rev 5.5.8.2 (2012/11/09) HeaderData に ??フラグを渡します?
087             *
088             * @see #isExcel()
089             */
090            @Override
091            public void readDBTable() {
092                    InputStream  in = null;
093                    HeaderData data = null;         // 5.5.1.2 (2012/04/06)
094                    try {
095                            boolean isDebug = isDebug();                    // 5.5.7.2 (2012/10/09) ????
096    
097                            if( isDebug ) { System.out.println( " Filename=" + filename ) ; }
098    
099                            in = new FileInputStream(filename);
100    
101                            Workbook wb = WorkbookFactory.create(in);
102                            Sheet[] sheets ;                                                                        // 5.5.7.2 (2012/10/09) 配?に変更
103    
104                            if( isDebug ) { wb = ExcelUtil.activeWorkbook( wb ); }          // ??モード時には、エクセルのアク?ブセル領域のみにシュリンクを行う
105    
106                            // 5.5.7.2 (2012/10/09) ?シート?マ?ジ読み取り?sheetNos の?が優先される?
107                            if( sheetNos != null && sheetNos.length() > 0 ) {
108                                    String[] sheetList = StringUtil.csv2ArrayExt( sheetNos , wb.getNumberOfSheets()-1 );    // ?シート番号は、シート数-1
109                                    sheets = new Sheet[sheetList.length];
110                                    for( int i=0; i<sheetList.length; i++ ) {
111                                            sheets[i] = wb.getSheetAt( Integer.parseInt( sheetList[i] ) );
112                                    }
113                            }
114                            else if( sheetName != null && sheetName.length() > 0 ) {
115                                    Sheet sheet = wb.getSheet( sheetName );
116                                    if( sheet == null ) {
117                                            String errMsg = "対応するシートが存在しません?Sheet=[" + sheetName + "]" ;
118                                            throw new HybsSystemException( errMsg );
119                                    }
120                                    sheets = new Sheet[] { sheet };
121                            }
122                            else {
123                                    Sheet sheet = wb.getSheetAt(0);
124                                    sheets = new Sheet[] { sheet };
125                            }
126    
127                            boolean  nameNoSet = true;
128                            table = DBTableModelUtil.newDBTable();
129    
130                            int numberOfRows = 0;
131                            data = new HeaderData();                                // 5.5.1.2 (2012/04/06)
132    
133                            data.setDebug( isDebug );                               // 5.5.8.2 (2012/11/09)
134    
135                            // 5.1.6.0 (2010/05/01) columns 処?
136                            data.setUseNumber( isUseNumber() );
137    
138                            // 5.5.8.2 (2012/11/09) 固定?となるカラ?(CSV形?とアドレス(????・・・)を設?
139                            data.setSheetConstData( constKeys,constAdrs );
140    
141                            int nullBreakClmAdrs = -1;                                              // 5.5.8.2 (2012/11/09) nullBreakClm の DBTableModel上?アドレス?1 は、未使用
142                            if( data.setColumns( columns ) ) {
143                                    nameNoSet = false;
144                                    table.init( data.getColumnSize() );
145                                    setTableDBColumn( data.getNames() ) ;
146                                    nullBreakClmAdrs = table.getColumnNo( nullBreakClm, false );    // 5.5.8.2 (2012/11/09) カラ?号取得?存在しなければ -1 を返す?
147                            }
148    
149                            int skip = getSkipRowCount();                                   // 5.1.6.0 (2010/05/01)
150                            // 5.5.7.2 (2012/10/09) ?シート?マ?ジ読み取り?
151                            for( int i=0; i<sheets.length; i++ ) {                       // 5.5.7.2 (2012/10/09) シート?列を処?ます?
152                                    Sheet sheet = sheets[i] ;                                       // 5.5.7.2 (2012/10/09)
153    
154                                    data.setSheetConstValues( sheet );                              // 5.5.8.2 (2012/11/09) シート単位に固定カラ??値をキャ?ュする?
155    
156                                    int nFirstRow = sheet.getFirstRowNum();
157                                    if( nFirstRow < skip ) { nFirstRow = skip; } // 5.1.6.0 (2010/05/01)
158                                    int nLastRow  = sheet.getLastRowNum();
159                                    if( isDebug ) {         // 5.5.7.2 (2012/10/09) ????
160                                            System.out.println( " Debug: 行?番=" + numberOfRows + " : Sheet= " + sheet.getSheetName() + " , 開?" + nFirstRow + " , 終?" + nLastRow );
161                                    }
162                                    for( int nIndexRow = nFirstRow; nIndexRow <= nLastRow; nIndexRow++) {
163            //                              HSSFRow oRow = sheet.getRow(nIndexRow);
164                                            Row oRow = sheet.getRow(nIndexRow);
165                                            if( data.isSkip( oRow ) ) { continue; }
166                                            if( nameNoSet ) {
167                                                    nameNoSet = false;
168                                                    table.init( data.getColumnSize() );
169                                                    setTableDBColumn( data.getNames() ) ;
170                                                    nullBreakClmAdrs = table.getColumnNo( nullBreakClm, false );    // 5.5.8.2 (2012/11/09) カラ?号取得?存在しなければ -1 を返す?
171                                            }
172    
173                                            if( numberOfRows < getMaxRowCount() ) {
174                                                    String[] tblData = data.row2Array( oRow );                      // 5.5.8.2 (2012/11/09) nullBreakClm の判定?ため、?配?に受ける?
175                                                    if( nullBreakClmAdrs >= 0 && ( tblData[nullBreakClmAdrs] == null || tblData[nullBreakClmAdrs].isEmpty() ) ) {
176                                                            break;          // nullBreakClm ?null の場合?、そのSheet処?中止する?
177                                                    }
178                                                    setTableColumnValues( tblData );                                        // 5.5.8.2 (2012/11/09)
179                                                    numberOfRows ++ ;
180                                            }
181                                            else {
182                                                    table.setOverflow( true );
183                                            }
184                                    }
185    
186                                    // ?まで?NAME が見つから無かった??
187                                    if( nameNoSet ) {
188                                            String errMsg = "?まで?NAME が見つかりませんでした?
189                                                                            + HybsSystem.CR
190                                                                            + "ファイルが空か?もしく?損傷して?可能性があります?"
191                                                                            + HybsSystem.CR ;
192                                            throw new HybsSystemException( errMsg );
193                                    }
194                            }
195                    }
196                    catch ( IOException ex ) {
197                            String errMsg = "ファイル読込みエラー[" + filename + "]"  ;
198                            if( data != null ) { errMsg = errMsg + data.getLastCellMsg(); }         // 5.5.1.2 (2012/04/06)
199                            throw new HybsSystemException( errMsg,ex );             // 3.5.5.4 (2004/04/15) 引数の並び?更
200                    }
201                    // 5.1.8.0 (2010/07/01) Exception をきちっと記述
202                    catch (InvalidFormatException ex) {
203                            String errMsg = "ファイル形式エラー[" + filename + "]"  ;
204                            if( data != null ) { errMsg = errMsg + data.getLastCellMsg(); }         // 5.5.1.2 (2012/04/06)
205                            throw new HybsSystemException( errMsg,ex );
206                    }
207                    finally {
208                            Closer.ioClose( in );           // 4.0.0 (2006/01/31) close 処?の IOException を無?
209                    }
210            }
211    
212            /**
213             * DBTableModel から ?式???タを作?して,BufferedReader より読み取ります?
214             * コメン?空行を除き???の行?、??名が?です?
215             * それ以降?、コメン?空行を除き???タとして読み込んで?ます?
216             *
217             * @og.rev 3.5.4.3 (2004/01/05) 引数に、BufferedReader を受け取る要に変更します?
218             * @og.rev 4.0.0.0 (2006/09/31) UnsupportedOperationException を発行します?
219             *
220             * @param   reader ?式???タ(使用して?せん)
221             */
222            @Override
223            public void readDBTable( final BufferedReader reader ) {
224                    String errMsg = "こ?クラスでは実?れて?せん?;
225                    throw new UnsupportedOperationException( errMsg );
226            }
227    
228            /**
229             * DBTableModelの??タとしてEXCELファイルを読み込?き?シート名を設定します?
230             * これにより、?の形式?異なるデータを?次読み込?と??シートを?して
231             * 読み取ることが可能になります?
232             * sheetNos と sheetName が同時に?された場合?、sheetNos が優先されます?エラーにはならな??でご注意く???
233             * のでご注意く???
234             *
235             * @og.rev 3.5.4.2 (2003/12/15) 新規追?
236             *
237             * @param   sheetName シート名
238             */
239            @Override
240            public void setSheetName( final String sheetName ) {
241                    this.sheetName = sheetName;
242            }
243    
244            /**
245             * EXCELファイルを読み込?き?シート番号を指定しま?初期値:0)?
246             *
247             * EXCEL読み込み時に?シートをマ?ジして取り込みます?
248             * シート番号は? から始まる数字で表します?
249             * ヘッ??は、最初?シート?カラ?置に合わせます????ータイトルの自動認識?ありません。?
250             * よって、指定するシート?、すべて同?イアウトでな?取り込み時にカラ??ずれが発生します?
251             * 
252             * シート番号の??、カンマ区?で、??できます?また?N-M の様にハイフンで繋げることで?
253             * N 番から、M 番のシート?を??可能です?また?"*" による、?シート指定が可能です?
254             * これら??合わせも可能です???0,1,3,5-8,10-* ??
255             * ただし?"*" に関しては例外的に、?字だけで、すべてのシートを表すか、N-* を最後に?するかの
256             * どちらかです?途中には?*" は、現れません?
257             * シート番号は??1,1,2,2)??転(3,2,1) での?が可能です?これは、その??で、読み込まれます?
258             * sheetNos と sheetName が同時に?された場合?、sheetNos が優先されます?エラーにはならな??でご注意く???
259             * こ?メソ?は、isExcel() == true の場合?み利用されます?
260             * 
261             * 初期値は??第?ート?です?
262             *
263             * ※ こ?クラスでは実?れて?せん?
264             *
265             * @og.rev 5.5.7.2 (2012/10/09) 新規追?
266             *
267             * @param   sheetNos EXCELファイルのシート番号??から始まる?
268             * @see         #setSheetName( String ) 
269             */
270            @Override
271            public void setSheetNos( final String sheetNos ) {
272                    this.sheetNos = sheetNos;
273            }
274    
275            /**
276             * EXCELファイルを読み込?き?シート単位?固定?を設定するため?カラ?とアドレスを指定します?
277             * カラ?は、カンマ区?で?します?
278             * 対応するアドレスを?EXCEL上??列を?から始まる整数でカンマ区?で?します?
279             * これにより、シート???書かれて???を?DBTableModel のカラ?固定?として
280             * 設定することができます?
281             * 例として、DB定義書で、テーブル名をシート?全レコードに設定したい場合などに使?す?
282             * こ?メソ?は、isExcel() == true の場合?み利用されます?
283             *
284             * @og.rev 5.5.8.2 (2012/11/09) 新規追?
285             *
286             * @param   constKeys 固定?となるカラ?(CSV形?
287             * @param   constAdrs 固定?となるアドレス(????・・・)
288             */
289            @Override
290            public void setSheetConstData( final String constKeys,final String constAdrs ) {
291                    this.constKeys = constKeys;
292                    this.constAdrs = constAdrs;
293            }
294    
295            /**
296             * ここに?されたカラ??に NULL が現れた時点で読み取りを中止します?
297             *
298             * これは、指定?カラ????と?事を条件に、そのレコードだけを読み取る処?行います?
299             * ?Sheetの場合?、次のSheetを読みます?
300             * 現時点では、Excel の場合?み有効です?
301             *
302             * @og.rev 5.5.8.2 (2012/11/09) 新規追?
303             *
304             * @param   clm カラ??
305             */
306            @Override
307            public void setNullBreakClm( final String clm ) {
308                    nullBreakClm = clm;
309            }
310    
311            /**
312             * こ?クラスが?EXCEL対応機?を持って?かど?を返します?
313             *
314             * EXCEL対応機?とは、シート名のセ?、読み込み?ァイルの
315             * Fileオブジェクト取得などの、特殊機?です?
316             * 本来は、インターフェースを?けるべきと?ますが、taglib クラス等?
317             * 関係があり、問?わせによる条件?で対応します?
318             *
319             * @og.rev 3.5.4.3 (2004/01/05) 新規追?
320             *
321             * @return      EXCEL対応機?を持って?かど?(常にtrue)
322             */
323            @Override
324            public boolean isExcel() {
325                    return true;
326            }
327    
328            /**
329             * 読み取り?ァイル名をセ?します?(DIR + Filename)
330             * これは、EXCEL追??として実?れて?す?
331             *
332             * @og.rev 3.5.4.3 (2004/01/05) 新規作?
333             *
334             * @param   filename 読み取り?ァイル?
335             */
336            @Override
337            public void setFilename( final String filename ) {
338                    this.filename = filename;
339                    if( filename == null ) {
340                            String errMsg = "ファイル名が?されて?せん? ;
341                            throw new HybsSystemException( errMsg );
342                    }
343            }
344    }
345    
346    /**
347     * EXCEL ネイ?ブ???タを???ローカルクラスです?
348     * こ?クラスでは、コメント行?スキ??判定?ヘッ??部のカラ?取得?
349     * 行情報(Row)から、カラ??配?の取得などを行います?
350     *
351     * @og.rev 3.5.4.8 (2004/02/23) 新規追?
352     * @og.group ファイル入?
353     *
354     * @version  4.0
355     * @author   儲
356     * @since    JDK5.0,
357     */
358    class HeaderData {
359            private String[] names ;
360            private int[]    index; // 4.3.4.0 (2008/12/01) POI3.2対?
361            private int              columnSize = 0;
362            private boolean  nameNoSet = true;
363            private boolean  useNumber = true;
364            private boolean  isDebug   = false;             // 5.5.8.2 (2012/11/09)
365    
366            private String[] orgNames ;                     // 5.5.1.2 (2012/04/06) オリジナルのカラ?
367            private Cell     lastCell = null;       // 5.5.1.2 (2012/04/06) ?に実行して?セルを保持(エラー時に使用する?
368    
369            // 5.5.8.2 (2012/11/09) 固定?のカラ?、DBTableModelのアドレス、Sheetの?列番号
370            private int              cnstLen = 0;           // 初期値=0 の場合?、固定?を使わな??事?
371            private String[] cnstKeys ;
372            private int[]    cnstIndx ;
373            private int[]    cnstRowNo;
374            private int[]    cnstClmNo;
375            private String[] cnstVals ;                     // Sheet単位?固定?のキャ?ュ(シート???に値を取得して保持しておく)
376    
377            /**
378             * ????を?出力するかど?[true/false]を指定しま?初期値:false)?
379             *
380             * 初期値は、false(出力しな? です?
381             *
382             * @og.rev 5.5.8.2 (2012/11/09) 新規作?
383             *
384             * @param       isDebug ???? [true:出力す?false:出力しない]
385             */
386            void setDebug( final boolean isDebug ) {
387                    this.isDebug = isDebug ;
388            }
389    
390            /**
391             * 行番号??を?使用して?かど?[true/false]を指定しま?初期値:true)?
392             *
393             * 初期値は、true(使用する) です?
394             *
395             * @og.rev 5.1.6.0 (2010/05/01) 新規作?
396             *
397             * @param       useNumber       行番号?? [true:使用して?/false:して?い]
398             */
399            void setUseNumber( final boolean useNumber ) {
400                    this.useNumber = useNumber ;
401            }
402    
403            /**
404             * 固定?となるカラ?(CSV形?と、constAdrs 固定?となるアドレス(????・・・)を設定します?
405             *
406             * アドレスは、EXCEL上??列をカンマ区?で?します?
407             * 行?は、EXCELオブジェクトに準拠するため?から始まる整数です?
408             * 0-0 ?A1 , 1-0 ?A2 , 0-1 ?B1 になります?
409             * これにより、シート???書かれて???を?DBTableModel のカラ?固定?として
410             * 設定することができます?
411             * 例として、DB定義書で、テーブル名をシート?全レコードに設定したい場合などに使?す?
412             * こ?メソ?は、isExcel() == true の場合?み利用されます?
413             *
414             * 5.7.6.3 (2014/05/23) より?
415             *   ?XCEL表記に準拠した、A1,A2,B1 の記述も??きるように対応します?
416             *     なお?A1,A2,B1 の記述は、?、英??+数?にしてください?A?Zまで)
417             *   ②処?のEXCELシート名をカラ?割り当てるために?SHEET" と?記号に対応します?
418             * 例えば、sheetConstKeys="CLM,LANG,NAME" とし?sheetConstAdrs="0-0,A2,SHEET" とすると?
419             * NAMEカラ?は、シート名を読み込?とができます?
420             * これは、?部処??簡?のためです?
421             *
422             * ちなみに、EXCELのセルに、シート名を表示させる?合?関数は、下記?様になります?
423             * =RIGHT(CELL("filename",$A$1),LEN(CELL("filename",$A$1))-FIND("]",CELL("filename",$A$1)))
424             *
425             * @param       constKeys       固定?となるカラ?(CSV形?
426             * @param       constAdrs       固定?となるアドレス(????・・・)
427             *
428             * @og.rev 5.5.8.2 (2012/11/09) 新規追?
429             * @og.rev 5.7.6.3 (2014/05/23) EXCEL表?A2,B1?の対応と、特殊記号(SHEET)の対?
430             */
431            void setSheetConstData( final String constKeys,final String constAdrs ) {
432                    if( constKeys == null || constKeys.isEmpty() ) {
433                            return ;
434                    }
435    
436                    cnstKeys  = constKeys.split( "," );
437                    cnstLen   = cnstKeys.length;
438                    cnstIndx  = new int[cnstLen];
439                    cnstRowNo = new int[cnstLen];
440                    cnstClmNo = new int[cnstLen];
441    
442                    String[] row_col = constAdrs.split( "," ) ;
443                    cnstRowNo = new int[cnstLen];
444                    cnstClmNo = new int[cnstLen];
445                    for( int j=0; j<cnstLen; j++ ) {
446                            cnstKeys[j] = cnstKeys[j].trim();               // 前後?不要なスペ?スを削除
447                            String rowcol = row_col[j].trim();              // 前後?不要なスペ?スを削除
448    
449                            // 5.7.6.3 (2014/05/23) EXCEL表?A2,B1?の対応と、特殊記号(SHEET)の対?
450                            int sep = rowcol.indexOf( '-' );
451                            if( sep > 0 ) {
452                                    cnstRowNo[j] = Integer.parseInt( rowcol.substring( 0,sep ) );
453                                    cnstClmNo[j] = Integer.parseInt( rowcol.substring( sep+1 ) );
454                            }
455                            else {
456                                    if( "SHEET".equalsIgnoreCase( rowcol ) ) {              // "SHEET" 時?、cnstRowNo を?イナスにしておきます?
457                                            cnstRowNo[j] = -1 ;
458                                            cnstClmNo[j] = -1 ;
459                                    }
460                                    else if( rowcol.length() >= 2 ) {
461                                            cnstRowNo[j] = Integer.parseInt( rowcol.substring( 1 ) ) -1;    // C6 の場合?RowNoは?-1=5
462                                            cnstClmNo[j] = rowcol.charAt(0) - 'A' ;                                                 // C6 の場合?'C'-'A'=2
463                                    }
464                            }
465    
466                            if( isDebug ) {
467                                    System.out.println( " Debug: constKey=" + cnstKeys[j] + " : RowNo=" + cnstRowNo[j] + " , ClmNo=" + cnstClmNo[j] );
468                            }
469                    }
470            }
471    
472            /**
473             * カラ?を外部から?します?
474             * カラ?が?NULL でなければ?NAME より、こちらが優先されます?
475             * カラ?は??番に、指定する?があります?
476             *
477             * @og.rev 5.1.6.0 (2010/05/01) 新規作?
478             * @og.rev 5.5.8.2 (2012/11/09) 固定?取得用の cnstIndx の設定を行う?
479             *
480             * @param       columns EXCELのカラ??(CSV形?
481             *
482             * @return true:処?施/false:無処?
483             */
484            boolean setColumns( final String columns ) {
485                    if( columns != null && columns.length() > 0 ) {
486                            names = StringUtil.csv2Array( columns );
487                            columnSize = names.length ;
488                            index = new int[columnSize];
489                            int adrs = useNumber ? 1:0 ;    // useNumber =true の場合??件目(No)は読み飛?す?
490                            // 5.5.8.2 (2012/11/09) 固定?取得用の cnstIndx の設定を行う?
491                            for( int i=0; i<columnSize; i++ ) {
492                                    index[i] = adrs++;
493                                    for( int j=0; j<cnstLen; j++ ) {
494                                            if( names[i].equalsIgnoreCase( cnstKeys[j] ) ) {
495                                                    cnstIndx[j] = index[i];
496                                            }
497                                    }
498                            }
499                            nameNoSet = false;
500    
501                            return true;
502                    }
503                    return false;
504            }
505    
506            /**
507             * EXCEL ネイ?ブ???タを???ローカルクラスです?
508             * こ?クラスでは、コメント行?スキ??判定?ヘッ??部のカラ?取得?
509             * 行情報(Row)から、カラ??配?の取得などを行います?
510             *
511             * @og.rev 4.3.4.0 (2008/12/01) POI3.2対?
512             *
513             * @param oRow Row EXCELの行オブジェク?
514             *
515             * @return true:コメント?false:通常?
516             */
517            boolean isSkip( Row oRow ) {
518                    if( oRow == null ) { return true; }
519    
520                    int nFirstCell = oRow.getFirstCellNum();
521                    Cell oCell = oRow.getCell(nFirstCell);
522                    String strText =  getValue( oCell );
523                    if( strText != null && strText.length() > 0 ) {
524                            if( nameNoSet ) {
525                                    if( "#Name".equalsIgnoreCase( strText ) ) {
526                                            makeNames( oRow );
527                                            nameNoSet = false;
528                                            return true;
529                                    }
530                                    else if( strText.charAt( 0 ) == '#' ) {
531                                            return true;
532                                    }
533                                    else {
534                                            String errMsg = "#NAME が見つかる前に??タが見つかりました?
535                                                                            + HybsSystem.CR
536                                                                            + "可能性として、ファイルが?ネイ?ブExcelでな?が?られます?"
537                                                                            + HybsSystem.CR ;
538                                            throw new HybsSystemException( errMsg );
539                                    }
540                            }
541                            else {
542                                    if( strText.charAt( 0 ) == '#' ) {
543                                            return true;
544                                    }
545                            }
546                    }
547    
548                    return nameNoSet ;
549            }
550    
551            /**
552             * EXCEL ネイ?ブ?行情報(Row)からカラ???を取得します?
553             *
554             * @og.rev 4.3.4.0 (2008/12/01) POI3.2対?
555             * @og.rev 5.1.6.0 (2010/05/01) useNumber(行番号??を?使用して?(true)/して??false)を指?
556             * @og.rev 5.1.6.0 (2010/05/01) useNumber(行番号??を?使用して?(true)/して??false)を指?
557             * @og.rev 5.5.1.2 (2012/04/06) オリジナルのカラ?を取?
558             * @og.rev 5.5.8.2 (2012/11/09) 固定?取得用の cnstIndx の設定を行う?
559             *
560             * @param oRow Row EXCELの行オブジェク?
561             */
562            private void makeNames( final Row oRow ) {
563                    // 先?カラ???NAME 属?行であるかど?を?useNumber で判定しておく?
564                    short nFirstCell = (short)( useNumber ? 1:0 );
565                    short nLastCell  = oRow.getLastCellNum();
566    
567                    orgNames = new String[nLastCell+1];             // 5.5.1.2 (2012/04/06) オリジナルのカラ?を取?
568    
569                    int maxCnt = nLastCell - nFirstCell;
570                    String[] names2 = new String[maxCnt];
571                    int[]    index2 = new int[maxCnt];
572    
573                    // 先?カラ???NAME 属?行である?+ で、?進めて??
574                    // 先?カラ???NAME 属?行であるかど?を?useNumber で判定しておく?
575                    for( int nIndexCell = nFirstCell; nIndexCell <= nLastCell; nIndexCell++) {
576                            Cell oCell = oRow.getCell(nIndexCell);
577                            String strText = getValue( oCell );
578    
579                            orgNames[nIndexCell] = strText;         // 5.5.1.2 (2012/04/06) オリジナルのカラ?を取?
580    
581                            // #NAME 行が、ゼロ??の場合?、読み飛?す?
582                            if( strText != null && strText.length() > 0 ) {
583                                    names2[columnSize] = strText;
584                                    index2[columnSize] = nIndexCell;
585                                    columnSize++;
586                            }
587                    }
588    
589                    // #NAME を使用しな??合:no?存在しな?ース
590                    if( maxCnt == columnSize ) {
591                            names = names2;
592                            index = index2;
593                    }
594                    else {
595                            names = new String[columnSize];
596                            index = new int[columnSize];
597                            System.arraycopy(names2, 0, names, 0, columnSize);
598                            System.arraycopy(index2, 0, index, 0, columnSize);
599                    }
600    
601                    // 5.5.8.2 (2012/11/09) 固定?取得用の cnstIndx の設定を行う?
602                    if( cnstLen > 0 ) {
603                            for( int i=0; i<columnSize; i++ ) {
604                                    for( int j=0; j<cnstLen; j++ ) {
605                                            if( names[i].equalsIgnoreCase( cnstKeys[j] ) ) {
606                                                    cnstIndx[j] = index[i];
607                                            }
608                                    }
609                            }
610                    }
611            }
612    
613            /**
614             * カラ???を返します?
615             * ここでは、?部配?をそのまま返します?
616             *
617             * @return String[] カラ??配???
618             */
619            String[] getNames() {
620                    return names;
621            }
622    
623            /**
624             * カラ?イズを返します?
625             *
626             * @return      カラ?イズ
627             */
628            int getColumnSize() {
629                    return columnSize;
630            }
631    
632            /**
633             * Sheet単位?固定?のキャ?ュ(シート???に値を取得して保持しておく)を設定します?
634             * これは、シートチェンジの??に?呼び出しておくことで、それ以降?列取得時に
635             * 固定?を利用することで処??度向上を目?ます?
636             *
637             * "SHEET" が指定された場合?、cnstRowNo[j]=-1 が設定されて??
638             *
639             * @og.rev 5.5.8.2 (2012/11/09) 新規作?
640             * @og.rev 5.7.6.3 (2014/05/23) 特殊記号(SHEET)の対?
641             *
642             * @param sheet Sheet EXCELのSheetオブジェク?
643             */
644            void setSheetConstValues( final Sheet sheet ) {
645                    cnstVals = new String[cnstLen];
646                    for( int j=0; j<cnstLen; j++ ) {
647                            // 5.7.6.3 (2014/05/23) 特殊記号(SHEET)の対?
648                            if( cnstRowNo[j] < 0 ) {
649                                    cnstVals[j] = sheet.getSheetName() ;
650                            }
651                            else {
652                                    Row  oRow  = sheet.getRow( cnstRowNo[j] );
653                                    Cell oCell = oRow.getCell( cnstClmNo[j] );
654                                    cnstVals[j] = getValue( oCell );
655                            }
656    
657                            if( isDebug ) {
658                                    System.out.println( " Debug: Sheet=" + sheet.getSheetName() + " : RowNo=" + cnstRowNo[j] + " , ClmNo=" + cnstClmNo[j] + " , " + cnstKeys[j] + "=" + cnstVals[j] );
659                            }
660                    }
661            }
662    
663            /**
664             * カラ???を返します?
665             *
666             * @og.rev 5.5.8.2 (2012/11/09) 固定?の設定を行う?
667             *
668             * @param oRow Row EXCELの行オブジェク?
669             *
670             * @return String[] カラ??配???
671             */
672            String[] row2Array( final Row oRow ) {
673                    if( nameNoSet ) {
674                            String errMsg = "#NAME が見つかる前に??タが見つかりました?;
675                            throw new HybsSystemException( errMsg );
676                    }
677    
678                    String[] data = new String[columnSize];
679                    for( int i=0;i<columnSize; i++ ) {
680                            Cell oCell = oRow.getCell( index[i] );
681                            data[i] = getValue( oCell );
682                    }
683    
684                    // 5.5.8.2 (2012/11/09) 固定?の設定を行う?
685                    for( int j=0; j<cnstLen; j++ ) {
686                            data[cnstIndx[j]] = cnstVals[j];
687                    }
688                    return data;
689            }
690    
691            /**
692             * セルオブジェク?Cell)から値を取り?します?
693             *
694             * @og.rev 3.8.5.3 (2006/08/07) 取り出し方法を少し修正
695             * @og.rev 5.5.1.2 (2012/04/06) フォーマットセルを実行して、その結果を?帰?処?る?
696             *
697             * @param oCell Cell EXCELのセルオブジェク?
698             *
699             * @return      セルの値
700             */
701            private String getValue( final Cell oCell ) {
702                    lastCell = oCell;       // 5.5.1.2 (2012/04/06) 今から実行するセルを取得しておきます?
703    
704                    if( oCell == null ) { return null; }
705    
706                    String strText = "";
707                    RichTextString richText;
708                    int nCellType = oCell.getCellType();
709                    switch(nCellType) {
710                            case Cell.CELL_TYPE_NUMERIC:
711                                            strText = getNumericTypeString( oCell );
712                                            break;
713                            case Cell.CELL_TYPE_STRING:
714            // POI3.0               strText = oCell.getStringCellValue();
715                                            richText = oCell.getRichStringCellValue();
716                                            if( richText != null ) {
717                                                    strText = richText.getString();
718                                            }
719                                            break;
720                            case Cell.CELL_TYPE_FORMULA:
721            // POI3.0               strText = oCell.getStringCellValue();
722                                            // 5.5.1.2 (2012/04/06) フォーマットセルを実行して、その結果を?帰?処?る?
723                                            Workbook wb = oCell.getSheet().getWorkbook();
724                                            CreationHelper crateHelper = wb.getCreationHelper();
725                                            FormulaEvaluator evaluator = crateHelper.createFormulaEvaluator();
726    
727                                            try {
728                                                    strText = getValue(evaluator.evaluateInCell(oCell));
729                                            }
730                                            catch ( Throwable th ) {
731                                                    String errMsg = "セルフォーマットが解析できません?" + oCell.getCellFormula() + "]"
732                                                                            + getLastCellMsg();
733                                                    throw new HybsSystemException( errMsg,th );
734                                            }
735                                            break;
736                            case Cell.CELL_TYPE_BOOLEAN:
737                                            strText = String.valueOf(oCell.getBooleanCellValue());
738                                            break;
739                            case Cell.CELL_TYPE_BLANK :
740                            case Cell.CELL_TYPE_ERROR:
741                                            break;
742                            default :
743                                    break;
744                    }
745                    return strText.trim();
746            }
747    
748            /**
749             * セル値が数字?場合に、数字か日付かを判断して、対応する文字?を返します?
750             *
751             * @og.rev 3.8.5.3 (2006/08/07) 新規追?
752             * @og.rev 5.5.7.2 (2012/10/09) HybsDateUtil を利用するように修正します?
753             *
754             * @param oCell Cell
755             *
756             * @return      数字?場合?、文字?に変換した結果を?日付?場合??yyyyMMddHHmmss" 形式で返します?
757             */
758            private String getNumericTypeString( final Cell oCell ) {
759                    final String strText ;
760    
761                    double dd = oCell.getNumericCellValue() ;
762                    if( DateUtil.isCellDateFormatted( oCell ) ) {
763                            strText = HybsDateUtil.getDate( DateUtil.getJavaDate( dd ).getTime() , "yyyyMMddHHmmss" );      // 5.5.7.2 (2012/10/09) HybsDateUtil を利用
764                    }
765                    else {
766                            NumberFormat numFormat = NumberFormat.getInstance();
767                            if( numFormat instanceof DecimalFormat ) {
768                                    ((DecimalFormat)numFormat).applyPattern( "#.####" );
769                            }
770                            strText = numFormat.format( dd );
771                    }
772                    return strText ;
773            }
774    
775            /**
776             * ?に実行して?セル??を返します?
777             *
778             * エラー発生時に、どのセルでエラーが発生したかの??を取得できるようにします?
779             *
780             * @og.rev 5.5.1.2 (2012/04/06) 新規追?
781             * @og.rev 5.5.8.2 (2012/11/09) エラー??に、シート名も追?
782             *
783             * @return      ?に実行して?セル??の??
784             */
785            String getLastCellMsg() {
786                    String lastMsg = null;
787    
788                    if( lastCell != null ) {
789                            int rowNo = lastCell.getRowIndex();
790                            int celNo = lastCell.getColumnIndex();
791                            int no = lastCell.getColumnIndex();
792                            String shtNm = lastCell.getSheet().getSheetName();
793    
794    
795                            lastMsg = "Sheet=" + shtNm + ", Row=" + rowNo + ", Cel=" + celNo ;
796                            if( orgNames != null && orgNames.length < no ) {
797                                    lastMsg = lastMsg + ", NAME=" + orgNames[no] ;
798                            }
799                    }
800                    return lastMsg;
801            }
802    }