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.plugin.io; 017 018import java.io.BufferedReader; 019import java.io.IOException; 020import java.io.InputStream; 021import java.util.ArrayList; 022import java.util.List; 023import java.util.zip.ZipEntry; 024import java.util.zip.ZipFile; 025 026import javax.xml.parsers.DocumentBuilder; 027import javax.xml.parsers.DocumentBuilderFactory; 028import javax.xml.parsers.ParserConfigurationException; 029 030import org.opengion.fukurou.util.StringUtil; 031import org.opengion.fukurou.util.Closer; // 5.5.2.6 (2012/05/25) 032import org.opengion.hayabusa.common.HybsSystem; 033import org.opengion.hayabusa.common.HybsSystemException; 034import org.opengion.hayabusa.db.DBTableModelUtil; 035import org.w3c.dom.Document; 036import org.w3c.dom.Element; 037import org.w3c.dom.NodeList; 038import org.xml.sax.SAXException; 039 040/** 041 * XMLパーサによる、OpenOffice.org Calcの表計算ドキュメントファイルを読み取る実装クラスです。 042 * 043 * @カラム名が指定されている場合 044 * #NAMEで始まる行を検索し、その行のそれぞれの値をカラム名として処理します。 045 * #NAMEで始まる行より以前の行については、全て無視されます。 046 * また、#NAMEより前のカラム及び、#NAMEの行の値がNULL(カラム名が設定されていない)カラムも 047 * 無視します。 048 * 読み飛ばされたカラム列に入力された値は取り込まれません。 049 * また、#NAME行以降の#で始まる行は、コメント行とみなされ処理されません。 050 * 051 * Aカラム名が指定されている場合 052 * 指定されたカラム名に基づき、値を取り込みます。 053 * カラム名の順番と、シートに記述されている値の順番は一致している必要があります。 054 * 指定されたカラム数を超える列の値については全て無視されます。 055 * #で始まる行は、コメント行とみなされ処理されません。 056 * 057 * また、いずれの場合も全くデータが存在していない行は読み飛ばされます。 058 * 059 * @og.group ファイル入力 060 * 061 * @version 4.0 062 * @author Hiroki Nakamura 063 * @since JDK5.0, 064 */ 065public class TableReader_Calc extends TableReader_Default { 066 // * このプログラムのVERSION文字列を設定します。 {@value} */ 067 private static final String VERSION = "5.5.7.2 (2012/10/09)"; 068 069 private String sheetName = null; 070 private String sheetNos = null; // 5.5.7.2 (2012/10/09) 071 private String filename = null; 072 private int numberOfRows = 0; 073 private int firstClmIdx = 0; 074 private int[] valueClmIdx = null; 075 076 /** 077 * DBTableModel から 各形式のデータを作成して,BufferedReader より読み取ります。 078 * コメント/空行を除き、最初の行は、項目名が必要です。 079 * (但し、カラム名を指定することで、項目名を省略することができます) 080 * それ以降は、コメント/空行を除き、データとして読み込んでいきます。 081 * このメソッドは、Calc 読み込み時に使用します。 082 * 083 * @og.rev 4.3.5.0 (2009/02/01) toArray するときに、サイズの初期値指定を追加 084 * @og.rev 5.5.7.2 (2012/10/09) sheetNos 追加による複数シートのマージ読み取りサポート 085 * 086 * @see #isExcel() 087 */ 088 @Override 089 public void readDBTable() { 090 091 ZipFile zipFile = null; 092 boolean errFlag = false; // 5.0.0.1 (2009/08/15) finally ブロックの throw を避ける。 093 try { 094 // OpenOffice.org odsファイルを開く 095 zipFile = new ZipFile( filename ); 096 097 ZipEntry entry = zipFile.getEntry( "content.xml" ); 098 if ( null == entry ) { 099 String errMsg = "ODSファイル中にファイルcontent.xmlが存在しません。"; 100 throw new HybsSystemException( errMsg ); 101 } 102 103 // content.xmlをパースし、行、列単位のオブジェクトに分解します。 104 DomOdsParser odsParser = new DomOdsParser(); 105// odsParser.doParse( zipFile.getInputStream( entry ), sheetName ); 106 odsParser.doParse( zipFile.getInputStream( entry ), sheetName , sheetNos ); // 5.5.7.2 (2012/10/09) sheetNos 対応 107 List<RowInfo> rowInfoList = odsParser.getRowInfoList(); 108 109 // 4.3.5.0 (2009/02/01) toArray するときに、サイズの初期値指定を追加 110// makeDBTableModel( rowInfoList.toArray( new RowInfo[0] ) ); 111 makeDBTableModel( rowInfoList.toArray( new RowInfo[rowInfoList.size()] ) ); 112 } 113 catch ( IOException ex ) { 114 String errMsg = "ファイル読込みエラー[" + filename + "]"; 115 throw new HybsSystemException( errMsg, ex ); 116 } 117 finally { 118 // 5.5.2.6 (2012/05/25) fukurou.util.Closer#zipClose( ZipFile ) を利用するように修正。 119 errFlag = ! Closer.zipClose( zipFile ); // OK の場合、true なので、反転しておく。 120// if ( null != zipFile ) { 121// try { 122// zipFile.close(); 123// } 124// catch ( IOException ex ) { 125// errFlag = true; 126// } 127// } 128 } 129 130 if( errFlag ) { 131 String errMsg = "ODSファイルのクローズ中にエラーが発生しました[" + filename + "]"; 132 throw new HybsSystemException ( errMsg ); 133 } 134 135// finally { 136// if ( null != zipFile ) 137// try { 138// zipFile.close(); 139// } 140// catch ( IOException ex ) { 141// String errMsg = "ODSファイルのクローズ中にエラーが発生しました[" + filename + "]"; 142// throw new HybsSystemException ( errMsg, ex ); 143// } 144// } 145 } 146 147 /** 148 * DBTableModel から 各形式のデータを作成して,BufferedReader より読み取ります。 149 * このメソッドは、この実装クラスでは使用できません。 150 * 151 * @param reader 各形式のデータ(使用していません) 152 */ 153 @Override 154 public void readDBTable( final BufferedReader reader ) { 155 String errMsg = "このクラスでは実装されていません。"; 156 throw new UnsupportedOperationException( errMsg ); 157 } 158 159 /** 160 * DBTableModelのデータとしてCalcファイルを読み込むときのシート名を設定します。 161 * これにより、複数の形式の異なるデータを順次読み込むことや、シートを指定して 162 * 読み取ることが可能になります。 163 * sheetNos と sheetName が同時に指定された場合は、sheetNos が優先されます。エラーにはならないのでご注意ください。 164 * のでご注意ください。 165 * 166 * @param sheetName シート名 167 */ 168 @Override 169 public void setSheetName( final String sheetName ) { 170 this.sheetName = sheetName; 171 } 172 173 /** 174 * Calcファイルを読み込むときのシート番号を指定します(初期値:0)。 175 * 176 * Calc読み込み時に複数シートをマージして取り込みます。 177 * シート番号は、0 から始まる数字で表します。 178 * ヘッダーは、最初のシートのカラム位置に合わせます。(ヘッダータイトルの自動認識はありません。) 179 * よって、指定するシートは、すべて同一レイアウトでないと取り込み時にカラムのずれが発生します。 180 * 181 * シート番号の指定は、カンマ区切りで、複数指定できます。また、N-M の様にハイフンで繋げることで、 182 * N 番から、M 番のシート範囲を一括指定可能です。また、"*" による、全シート指定が可能です。 183 * これらの組み合わせも可能です。( 0,1,3,5-8,10-* ) 184 * ただし、"*" に関しては例外的に、一文字だけで、すべてのシートを表すか、N-* を最後に指定するかの 185 * どちらかです。途中には、"*" は、現れません。 186 * シート番号は、重複(1,1,2,2)、逆転(3,2,1) での指定が可能です。これは、その指定順で、読み込まれます。 187 * sheetNos と sheetName が同時に指定された場合は、sheetNos が優先されます。エラーにはならないのでご注意ください。 188 * このメソッドは、isExcel() == true の場合のみ利用されます。 189 * 190 * 初期値は、0(第一シート) です。 191 * 192 * ※ このクラスでは実装されていません。 193 * 194 * @og.rev 5.5.7.2 (2012/10/09) 新規追加 195 * 196 * @param sheetNos Calcファイルのシート番号(0から始まる) 197 * @see #setSheetName( String ) 198 */ 199 @Override 200 public void setSheetNos( final String sheetNos ) { 201 this.sheetNos = sheetNos; 202 } 203 204 /** 205 * このクラスが、EXCEL対応機能を持っているかどうかを返します。 206 * 207 * EXCEL対応機能とは、シート名のセット、読み込み元ファイルの Fileオブジェクト取得などの、特殊機能です。 208 * 本来は、インターフェースを分けるべきと考えますが、taglib クラス等の 関係があり、問い合わせによる条件分岐で対応します。 209 * 210 * @return EXCEL対応機能を持っているかどうか(常にtrue) 211 */ 212 @Override 213 public boolean isExcel() { 214 return true; 215 } 216 217 /** 218 * 読み取り元ファイル名をセットします。(DIR + Filename) これは、OpenOffice.org 219 * Calc追加機能として実装されています。 220 * 221 * @param filename 読み取り元ファイル名 222 */ 223 @Override 224 public void setFilename( final String filename ) { 225 this.filename = filename; 226 if ( filename == null ) { 227 String errMsg = "ファイル名が指定されていません。"; 228 throw new HybsSystemException( errMsg ); 229 } 230 } 231 232 /** 233 * ODSファイルをパースした結果からDBTableModelを生成します。 234 * 235 * @og.rev 5.1.6.0 (2010/05/01) skipRowCountの追加 236 * 237 * @param rowInfoList 行オブジェクトの配列 238 */ 239 private void makeDBTableModel( final RowInfo[] rowInfoList ) { 240 // カラム名が指定されている場合は、優先する。 241 if( columns != null && columns.length() > 0 ) { 242 makeHeaderFromClms(); 243 } 244 245// for( RowInfo rowInfo : rowInfoList ) { 246 int skip = getSkipRowCount(); // 5.1.6.0 (2010/05/01) 247 for( int row=skip; row<rowInfoList.length; row++ ) { 248 RowInfo rowInfo = rowInfoList[row]; // 5.1.6.0 (2010/05/01) 249 if( valueClmIdx == null ) { 250 makeHeader( rowInfo ); 251 } 252 else { 253 makeBody( rowInfo ); 254 } 255 } 256 257 // 最後まで、#NAME が見つから無かった場合 258 if ( valueClmIdx == null ) { 259 String errMsg = "最後まで、#NAME が見つかりませんでした。" + HybsSystem.CR + "ファイルが空か、もしくは損傷している可能性があります。" + HybsSystem.CR; 260 throw new HybsSystemException( errMsg ); 261 } 262 } 263 264 /** 265 * 指定されたカラム一覧からヘッダー情報を生成します。 266 * 267 * @og.rev 5.1.6.0 (2010/05/01) useNumber の追加 268 */ 269 private void makeHeaderFromClms() { 270 table = DBTableModelUtil.newDBTable(); 271 String[] names = StringUtil.csv2Array( columns ); 272 table.init( names.length ); 273 setTableDBColumn( names ) ; 274 valueClmIdx = new int[names.length]; 275 int adrs = (isUseNumber()) ? 1:0 ; // useNumber =true の場合は、1件目(No)は読み飛ばす。 276 for( int i=0; i<names.length; i++ ) { 277// valueClmIdx[i] = i; 278 valueClmIdx[i] = adrs++; 279 } 280 } 281 282 /** 283 * ヘッダー情報を読み取り、DBTableModelのオブジェクトを新規に作成します。 284 * ※ 他のTableReaderと異なり、#NAME が見つかるまで、読み飛ばす。 285 * 286 * @og.rev 4.3.5.0 (2009/02/01) toArray するときに、サイズの初期値指定を追加 287 * 288 * @param rowInfo 行オブジェクト 289 */ 290 private void makeHeader( final RowInfo rowInfo ) { 291// int rowRepeat = rowInfo.rowRepeat; 292 CellInfo[] cellInfos = rowInfo.cellInfos; 293 294 int cellLen = cellInfos.length; 295 int runPos = 0; 296 ArrayList<String> nameList = null; 297 ArrayList<Integer> posList = null; 298 for ( int idx = 0; idx < cellLen; idx++ ) { 299 // テーブルのヘッダ(#NAME)が見つかる前の行、列は全て無視される 300 CellInfo cellInfo = cellInfos[idx]; 301 String text = cellInfo.text.trim(); 302 303 for ( int cellRep = 0; cellRep < cellInfo.colRepeat; cellRep++ ) { 304 // 空白のヘッダは無視(その列にデータが入っていても読まない) 305 if ( text.length() != 0 ) { 306 if ( firstClmIdx == 0 && text.equalsIgnoreCase( "#NAME" ) ) { 307 nameList = new ArrayList<String>(); 308 posList = new ArrayList<Integer>(); 309 table = DBTableModelUtil.newDBTable(); 310 firstClmIdx = idx; 311 } 312 else if ( nameList != null ) { 313 nameList.add( text ); 314 posList.add( runPos ); 315 } 316 } 317 runPos++; 318 } 319 } 320 321// if ( posList != null && posList.size() > 0 ) { 322 if ( posList != null && ! posList.isEmpty() ) { 323 table = DBTableModelUtil.newDBTable(); 324// String[] names = nameList.toArray( new String[0] ); 325// table.init( names.length ); 326 // 4.3.5.0 (2009/02/01) サイズの初期値指定 327 int size = nameList.size(); 328 String[] names = nameList.toArray( new String[size] ); 329 table.init( size ); 330 setTableDBColumn( names ); 331 332 valueClmIdx = new int[posList.size()]; 333 for( int i = 0; i<posList.size(); i++ ) { 334 valueClmIdx[i] = posList.get( i ).intValue(); 335 } 336 } 337 } 338 339 /** 340 * 行、列(セル)単位の情報を読み取り、DBTableModelに値をセットします 341 * 342 * @og.rev 5.2.1.0 (2010/10/01) setTableColumnValues メソッドを経由して、テーブルにデータをセットする。 343 * 344 * @param rowInfo 行オブジェクト 345 */ 346 private void makeBody( final RowInfo rowInfo ) { 347 int rowRepeat = rowInfo.rowRepeat; 348 CellInfo[] cellInfos = rowInfo.cellInfos; 349 int cellLen = cellInfos.length; 350 boolean isExistData = false; 351 352 List<String> colData = new ArrayList<String>(); 353 for ( int cellIdx = 0; cellIdx < cellLen; cellIdx++ ) { 354 CellInfo cellInfo = cellInfos[cellIdx]; 355 for ( int cellRep = 0; cellRep < cellInfo.colRepeat; cellRep++ ) { 356 colData.add( cellInfo.text ); 357 if( cellInfo.text.length() > 0 ) { 358 isExistData = true; 359 } 360 } 361 } 362 363 if( isExistData ) { 364 // 初めの列(#NAMEが記述されていた列)の値が#で始まっている場合は、コメント行とみなす。 365 String firstVal = colData.get( firstClmIdx ); 366 if( firstVal.length() > 0 && firstVal.startsWith( "#" ) ) { 367 return; 368 } 369 else { 370 String[] vals = new String[valueClmIdx.length]; 371 for( int col = 0; col < valueClmIdx.length; col++ ) { 372 vals[col] = colData.get( valueClmIdx[col] ); 373 } 374 375 // 重複行の繰り返し処理 376 for ( int rowIdx = 0; rowIdx < rowRepeat; rowIdx++ ) { 377 // テーブルモデルにデータをセット 378 if ( numberOfRows < getMaxRowCount() ) { 379 setTableColumnValues( vals ); // 5.2.1.0 (2010/10/01) 380// table.addColumnValues( vals ); 381 numberOfRows++; 382 } 383 else { 384 table.setOverflow( true ); 385 } 386 } 387 } 388 } 389 // 全くデータが存在しない行は読み飛ばし 390 else { 391 return; 392 } 393 } 394 395 /** 396 * ODSファイルに含まれるcontent.xmlをDOMパーサーでパースし、行、列単位に 397 * オブジェクトに変換します。 398 * 399 */ 400 private static class DomOdsParser{ 401 402 // OpenOffice.org Calc tag Names 403// private static final String OFFICE_DOCUMENT_CONTEBT_ELEM = "office:document-content"; 404// private static final String OFFICE_SPREADSHEET_ELEM = "office:spreadsheet"; 405 private static final String TABLE_TABLE_ELEM = "table:table"; 406// private static final String TABLE_TABLE_COLUMN_ELEM = "table:table-column"; 407 private static final String TABLE_TABLE_ROW_ELEM = "table:table-row"; 408 private static final String TABLE_TABLE_CELL_ELEM = "table:table-cell"; 409 private static final String TEXT_P_ELEM = "text:p"; 410 411 // Sheet tag attributes 412 private static final String TABLE_NAME_ATTR = "table:name"; 413// private static final String OFFICE_VALUE_YPE_ATTR = "office:value-type"; 414 private static final String TABLE_NUMBER_ROWS_REPEATED_ATTR = "table:number-rows-repeated"; 415 private static final String TABLE_NUMBER_COLUMNS_REPEATED_ATTR = "table:number-columns-repeated"; 416// private static final String TABLE_NUMBER_ROWS_SPANNED_ATTR = "table:number-rows-spanned"; 417// private static final String TABLE_NUMBER_COLUMNS_SPANNED_ATTR = "table:number-columns-spanned"; 418 419// ArrayList<RowInfo> rowInfoList = new ArrayList<RowInfo>(); 420 List<RowInfo> rowInfoList = new ArrayList<RowInfo>(); 421 /** 422 * DomパーサでXMLをパースする 423 * 424 * @og.rev 5.5.7.2 (2012/10/09) sheetNos 追加による複数シートのマージ読み取りサポート 425 * 426 * @param inputStream InputStream 427 * @param sheetName String 428 * @param sheetNos String 429 */ 430// public void doParse( final InputStream inputStream, final String sheetName ) { 431 public void doParse( final InputStream inputStream, final String sheetName, final String sheetNos ) { 432 try { 433 // ドキュメントビルダーファクトリを生成 434 DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); 435 dbFactory.setNamespaceAware( true ); 436 437 // ドキュメントビルダーを生成 438 DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); 439 // パースを実行してDocumentオブジェクトを取得 440 Document doc = dBuilder.parse( inputStream ); 441// processBook( doc, sheetName ); 442 processBook( doc, sheetName, sheetNos ); // 5.5.7.2 (2012/10/09) sheetNos 追加 443 } 444 catch ( ParserConfigurationException ex ) { 445 throw new HybsSystemException( ex ); 446 } 447 catch ( SAXException ex ) { 448 String errMsg = "ODSファイル中に含まれるcontent.xmlがXML形式ではありません。"; 449 throw new HybsSystemException( errMsg, ex ); 450 } 451 catch ( IOException ex ) { 452 throw new HybsSystemException( ex ); 453 } 454 } 455 456 /** 457 * 行オブジェクトのリストを返します。 458 * 459 * @return List<RowInfo> 460 */ 461 public List<RowInfo> getRowInfoList() { 462 return rowInfoList; 463 } 464 465 /** 466 * ODSファイル全体のパースを行い、処理対象となるシートを検索します。 467 * 468 * @og.rev 5.5.7.2 (2012/10/09) sheetNos 追加による複数シートのマージ読み取りサポート 469 * 470 * @param doc Document 471 * @param sheetName String 472 * @param sheetNos String 473 */ 474// private void processBook( final Document doc, final String sheetName ) { 475 private void processBook( final Document doc, final String sheetName, final String sheetNos ) { 476 // table:tableを探す 477 NodeList nodetList = doc.getElementsByTagName( TABLE_TABLE_ELEM ); 478 int listLen = nodetList.getLength(); 479 480// Element sheet = null; 481 Element[] sheets = null ; // 5.5.7.2 (2012/10/09) 482 483 // 5.5.7.2 (2012/10/09) 複数シートのマージ読み取り。 sheetNos の指定が優先される。 484 if( sheetNos != null && sheetNos.length() > 0 ) { 485 String[] sheetList = StringUtil.csv2ArrayExt( sheetNos , listLen-1 ); // 最大シート番号は、シート数-1 486 sheets = new Element[sheetList.length]; 487 for( int i=0; i<sheetList.length; i++ ) { 488 sheets[i] = (Element)nodetList.item( Integer.parseInt( sheetList[i] ) ); 489 } 490 } 491 else if( sheetName != null && sheetName.length() > 0 ) { 492 Element sheet = null; 493 for ( int idx = 0; idx < listLen; idx++ ) { 494 Element st = (Element)nodetList.item( idx ); 495 if ( sheetName.equals( st.getAttribute( TABLE_NAME_ATTR ) ) ) { 496 sheet = st; 497 break; 498 } 499 } 500 if( sheet == null ) { 501 String errMsg = "対応するシートが存在しません。 sheetName=[" + sheetName + "]" ; 502 throw new HybsSystemException( errMsg ); 503 } 504 sheets = new Element[] { sheet }; 505 } 506 else { 507 Element sheet = (Element)nodetList.item(0); 508 sheets = new Element[] { sheet }; 509 } 510 511// // シート探し:シート名があれば、そのまま使用、なければ、最初のシートを対象とします。 512// for ( int idx = 0; idx < listLen; idx++ ) { 513// Element st = (Element)nodetList.item( idx ); 514// if ( ( sheetName == null || sheetName.length() == 0 ) || sheetName.equals( st.getAttribute( TABLE_NAME_ATTR ) ) ) { 515// sheet = st; 516// break; 517// } 518// } 519 // 指定のシートがなければ、エラー 520// if ( sheet == null ) { 521 if ( sheets == null ) { 522 String errMsg = "対応するシートが存在しません。 sheetNos=[" + sheetNos + "] or sheetName=[" + sheetName + "]"; 523 throw new HybsSystemException( errMsg ); 524 } 525 else { 526// processSheet( sheet ); 527 // 5.5.7.2 (2012/10/09) 複数シートのマージ読み取り。 528 for( int i=0; i<sheets.length; i++ ) { 529 processSheet( sheets[i] ); 530 } 531 } 532 } 533 534 /** 535 * ODSファイルのシート単位のパースを行い、行単位のオブジェクトを生成します。 536 * 537 * @param sheet Element 538 */ 539 private void processSheet( final Element sheet ) { 540 NodeList rows = sheet.getElementsByTagName( TABLE_TABLE_ROW_ELEM ); 541 int listLen = rows.getLength(); 542 int rowRepeat; 543 for ( int idx = 0; idx < listLen; idx++ ) { 544 Element row = (Element)rows.item( idx ); 545 // 行の内容が全く同じ場合、table:number-rows-repeatedタグにより省略される。 546 String repeatStr = row.getAttribute( TABLE_NUMBER_ROWS_REPEATED_ATTR ); 547 if ( repeatStr == null || repeatStr.length() == 0 ) { 548 rowRepeat = 1; 549 } 550 else { 551 rowRepeat = Integer.parseInt( repeatStr, 10 ); 552 } 553 554 processRow( row, rowRepeat ); 555 } 556 } 557 558 /** 559 * ODSファイルの行単位のパースを行い、カラム単位のオブジェクトを生成します。 560 * 561 * @og.rev 4.3.5.0 (2009/02/01) toArray するときに、サイズの初期値指定を追加 562 * @og.rev 5.1.8.0 (2010/07/01) セル内で書式設定されている場合に、テキストデータが取得されないバグを修正 563 * 564 * @param row Element 565 * @param rowRepeat int 566 */ 567 private void processRow( final Element row, final int rowRepeat ) { 568 NodeList cells = row.getElementsByTagName( TABLE_TABLE_CELL_ELEM ); 569 int listLen = cells.getLength(); 570 int colRepeat; 571 String cellText; 572 ArrayList<CellInfo> cellInfoList = new ArrayList<CellInfo>(); 573 for ( int idx = 0; idx < listLen; idx++ ) { 574 Element cell = (Element)cells.item( idx ); 575 // カラムの内容が全く同じ場合、table:number-columns-repeatedタグにより省略される。 576 String repeatStr = cell.getAttribute( TABLE_NUMBER_COLUMNS_REPEATED_ATTR ); 577 if ( repeatStr == null || repeatStr.length() == 0 ) { 578 colRepeat = 1; 579 } 580 else { 581 colRepeat = Integer.parseInt( repeatStr, 10 ); 582 } 583 584 // text:p 585 NodeList texts = cell.getElementsByTagName( TEXT_P_ELEM ); 586 if ( texts.getLength() == 0 ) { 587 cellText = ""; 588 } 589 else { 590 // 5.1.8.0 (2010/07/01) セル内で書式設定されている場合に、テキストデータが取得されないバグを修正 591// StringBuilder sb = new StringBuilder(); 592// NodeList textElems = texts.item( 0 ).getChildNodes(); 593// int textElemLen = textElems.getLength(); 594// for ( int idxt = 0; idxt < textElemLen; idxt++ ) { 595// Node textElem = textElems.item( idxt ); 596// if ( textElem.getNodeType() == Node.TEXT_NODE ) { 597// sb.append( textElem.getNodeValue() ); 598// } 599// } 600// cellText = sb.toString(); 601 cellText = texts.item( 0 ).getTextContent(); 602 } 603 cellInfoList.add( new CellInfo( colRepeat, cellText ) ); 604 } 605 606// if ( cellInfoList.size() > 0 ) { 607 if ( ! cellInfoList.isEmpty() ) { 608// rowInfoList.add( new RowInfo( rowRepeat, cellInfoList.toArray( new CellInfo[0] ) ) ); 609 // 4.3.5.0 (2009/02/01) toArray するときに、サイズの初期値指定を追加 610 rowInfoList.add( new RowInfo( rowRepeat, cellInfoList.toArray( new CellInfo[cellInfoList.size()] ) ) ); 611 } 612 } 613 } 614 615 /** 616 * ODSファイルの行情報を表す構造体 617 */ 618 private static final class RowInfo { 619 public final int rowRepeat; 620 public final CellInfo[] cellInfos; 621 622 RowInfo( final int rep, final CellInfo[] cell ) { 623 rowRepeat = rep; 624 cellInfos = cell; 625 } 626 } 627 628 /** 629 * ODSファイルのカラム情報を表す構造体 630 */ 631 private static final class CellInfo { 632 public final int colRepeat; 633 public final String text; 634 635 CellInfo( final int rep, final String tx ) { 636 colRepeat = rep; 637 text = tx; 638 } 639 } 640}