You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ExcelToHtmlConverter.java 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.hssf.converter;
  16. import java.io.File;
  17. import java.io.IOException;
  18. import java.util.ArrayList;
  19. import java.util.LinkedHashMap;
  20. import java.util.List;
  21. import java.util.Map;
  22. import javax.xml.parsers.ParserConfigurationException;
  23. import javax.xml.transform.OutputKeys;
  24. import javax.xml.transform.Transformer;
  25. import javax.xml.transform.TransformerException;
  26. import javax.xml.transform.TransformerFactory;
  27. import javax.xml.transform.dom.DOMSource;
  28. import javax.xml.transform.stream.StreamResult;
  29. import org.apache.poi.hpsf.SummaryInformation;
  30. import org.apache.poi.hssf.usermodel.HSSFCell;
  31. import org.apache.poi.hssf.usermodel.HSSFCellStyle;
  32. import org.apache.poi.hssf.usermodel.HSSFFont;
  33. import org.apache.poi.hssf.usermodel.HSSFRichTextString;
  34. import org.apache.poi.hssf.usermodel.HSSFRow;
  35. import org.apache.poi.hssf.usermodel.HSSFSheet;
  36. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  37. import org.apache.poi.hssf.util.HSSFColor;
  38. import org.apache.poi.hwpf.converter.HtmlDocumentFacade;
  39. import org.apache.poi.ss.formula.eval.ErrorEval;
  40. import org.apache.poi.ss.usermodel.BorderStyle;
  41. import org.apache.poi.ss.util.CellRangeAddress;
  42. import org.apache.poi.util.Beta;
  43. import org.apache.poi.util.POILogFactory;
  44. import org.apache.poi.util.POILogger;
  45. import org.apache.poi.util.XMLHelper;
  46. import org.w3c.dom.Document;
  47. import org.w3c.dom.Element;
  48. import org.w3c.dom.Text;
  49. /**
  50. * Converts xls files (97-2007) to HTML file.
  51. *
  52. * @author Sergey Vladimirov (vlsergey {at} gmail {dot} com)
  53. */
  54. @Beta
  55. public class ExcelToHtmlConverter extends AbstractExcelConverter
  56. {
  57. private static final POILogger logger = POILogFactory
  58. .getLogger( ExcelToHtmlConverter.class );
  59. /**
  60. * Java main() interface to interact with {@link ExcelToHtmlConverter}
  61. *
  62. * <p>
  63. * Usage: ExcelToHtmlConverter infile outfile
  64. * </p>
  65. * Where infile is an input .xls file ( Word 97-2007) which will be rendered
  66. * as HTML into outfile
  67. * @throws TransformerException
  68. * @throws Exception
  69. */
  70. public static void main( String[] args )
  71. throws IOException, ParserConfigurationException, TransformerException
  72. {
  73. if ( args.length < 2 )
  74. {
  75. System.err
  76. .println( "Usage: ExcelToHtmlConverter <inputFile.xls> <saveTo.html>" );
  77. return;
  78. }
  79. System.out.println( "Converting " + args[0] );
  80. System.out.println( "Saving output to " + args[1] );
  81. Document doc = ExcelToHtmlConverter.process( new File( args[0] ) );
  82. DOMSource domSource = new DOMSource( doc );
  83. StreamResult streamResult = new StreamResult( new File(args[1]) );
  84. TransformerFactory tf = TransformerFactory.newInstance();
  85. Transformer serializer = tf.newTransformer();
  86. // TODO set encoding from a command argument
  87. serializer.setOutputProperty( OutputKeys.ENCODING, "UTF-8" );
  88. serializer.setOutputProperty( OutputKeys.INDENT, "no" );
  89. serializer.setOutputProperty( OutputKeys.METHOD, "html" );
  90. serializer.transform( domSource, streamResult );
  91. }
  92. /**
  93. * Converts Excel file (97-2007) into HTML file.
  94. *
  95. * @param xlsFile
  96. * file to process
  97. * @return DOM representation of result HTML
  98. * @throws IOException
  99. * @throws ParserConfigurationException
  100. */
  101. public static Document process( File xlsFile ) throws IOException, ParserConfigurationException
  102. {
  103. final HSSFWorkbook workbook = ExcelToHtmlUtils.loadXls( xlsFile );
  104. ExcelToHtmlConverter excelToHtmlConverter = new ExcelToHtmlConverter(
  105. XMLHelper.getDocumentBuilderFactory().newDocumentBuilder()
  106. .newDocument() );
  107. excelToHtmlConverter.processWorkbook( workbook );
  108. Document doc = excelToHtmlConverter.getDocument();
  109. workbook.close();
  110. return doc;
  111. }
  112. private String cssClassContainerCell = null;
  113. private String cssClassContainerDiv = null;
  114. private String cssClassPrefixCell = "c";
  115. private String cssClassPrefixDiv = "d";
  116. private String cssClassPrefixRow = "r";
  117. private String cssClassPrefixTable = "t";
  118. private Map<Short, String> excelStyleToClass = new LinkedHashMap<Short, String>();
  119. private final HtmlDocumentFacade htmlDocumentFacade;
  120. private boolean useDivsToSpan = false;
  121. public ExcelToHtmlConverter( Document doc )
  122. {
  123. htmlDocumentFacade = new HtmlDocumentFacade( doc );
  124. }
  125. public ExcelToHtmlConverter( HtmlDocumentFacade htmlDocumentFacade )
  126. {
  127. this.htmlDocumentFacade = htmlDocumentFacade;
  128. }
  129. protected String buildStyle( HSSFWorkbook workbook, HSSFCellStyle cellStyle )
  130. {
  131. StringBuilder style = new StringBuilder();
  132. style.append( "white-space:pre-wrap;" );
  133. ExcelToHtmlUtils.appendAlign( style, cellStyle.getAlignment() );
  134. switch (cellStyle.getFillPattern()) {
  135. // no fill
  136. case 0: break;
  137. case 1:
  138. final HSSFColor foregroundColor = cellStyle.getFillForegroundColorColor();
  139. if ( foregroundColor == null ) break;
  140. String fgCol = ExcelToHtmlUtils.getColor( foregroundColor );
  141. style.append( "background-color:" + fgCol + ";" );
  142. break;
  143. default:
  144. final HSSFColor backgroundColor = cellStyle.getFillBackgroundColorColor();
  145. if ( backgroundColor == null ) break;
  146. String bgCol = ExcelToHtmlUtils.getColor( backgroundColor );
  147. style.append( "background-color:" + bgCol + ";" );
  148. break;
  149. }
  150. buildStyle_border( workbook, style, "top", cellStyle.getBorderTop(),
  151. cellStyle.getTopBorderColor() );
  152. buildStyle_border( workbook, style, "right",
  153. cellStyle.getBorderRight(), cellStyle.getRightBorderColor() );
  154. buildStyle_border( workbook, style, "bottom",
  155. cellStyle.getBorderBottom(), cellStyle.getBottomBorderColor() );
  156. buildStyle_border( workbook, style, "left", cellStyle.getBorderLeft(),
  157. cellStyle.getLeftBorderColor() );
  158. HSSFFont font = cellStyle.getFont( workbook );
  159. buildStyle_font( workbook, style, font );
  160. return style.toString();
  161. }
  162. private void buildStyle_border( HSSFWorkbook workbook, StringBuilder style,
  163. String type, BorderStyle xlsBorder, short borderColor )
  164. {
  165. if ( xlsBorder == BorderStyle.NONE ) {
  166. return;
  167. }
  168. StringBuilder borderStyle = new StringBuilder();
  169. borderStyle.append( ExcelToHtmlUtils.getBorderWidth( xlsBorder ) );
  170. borderStyle.append( ' ' );
  171. borderStyle.append( ExcelToHtmlUtils.getBorderStyle( xlsBorder ) );
  172. final HSSFColor color = workbook.getCustomPalette().getColor(
  173. borderColor );
  174. if ( color != null )
  175. {
  176. borderStyle.append( ' ' );
  177. borderStyle.append( ExcelToHtmlUtils.getColor( color ) );
  178. }
  179. style.append( "border-" + type + ":" + borderStyle + ";" );
  180. }
  181. void buildStyle_font( HSSFWorkbook workbook, StringBuilder style,
  182. HSSFFont font )
  183. {
  184. switch ( font.getBoldweight() )
  185. {
  186. case HSSFFont.BOLDWEIGHT_BOLD:
  187. style.append( "font-weight:bold;" );
  188. break;
  189. case HSSFFont.BOLDWEIGHT_NORMAL:
  190. // by default, not not increase HTML size
  191. // style.append( "font-weight: normal; " );
  192. break;
  193. }
  194. final HSSFColor fontColor = workbook.getCustomPalette().getColor(
  195. font.getColor() );
  196. if ( fontColor != null )
  197. style.append( "color: " + ExcelToHtmlUtils.getColor( fontColor )
  198. + "; " );
  199. if ( font.getFontHeightInPoints() != 0 )
  200. style.append( "font-size:" + font.getFontHeightInPoints() + "pt;" );
  201. if ( font.getItalic() )
  202. {
  203. style.append( "font-style:italic;" );
  204. }
  205. }
  206. public String getCssClassPrefixCell()
  207. {
  208. return cssClassPrefixCell;
  209. }
  210. public String getCssClassPrefixDiv()
  211. {
  212. return cssClassPrefixDiv;
  213. }
  214. public String getCssClassPrefixRow()
  215. {
  216. return cssClassPrefixRow;
  217. }
  218. public String getCssClassPrefixTable()
  219. {
  220. return cssClassPrefixTable;
  221. }
  222. public Document getDocument()
  223. {
  224. return htmlDocumentFacade.getDocument();
  225. }
  226. protected String getStyleClassName( HSSFWorkbook workbook,
  227. HSSFCellStyle cellStyle )
  228. {
  229. final Short cellStyleKey = Short.valueOf( cellStyle.getIndex() );
  230. String knownClass = excelStyleToClass.get( cellStyleKey );
  231. if ( knownClass != null )
  232. return knownClass;
  233. String cssStyle = buildStyle( workbook, cellStyle );
  234. String cssClass = htmlDocumentFacade.getOrCreateCssClass(
  235. cssClassPrefixCell, cssStyle );
  236. excelStyleToClass.put( cellStyleKey, cssClass );
  237. return cssClass;
  238. }
  239. public boolean isUseDivsToSpan()
  240. {
  241. return useDivsToSpan;
  242. }
  243. protected boolean processCell( HSSFCell cell, Element tableCellElement,
  244. int normalWidthPx, int maxSpannedWidthPx, float normalHeightPt )
  245. {
  246. final HSSFCellStyle cellStyle = cell.getCellStyle();
  247. String value;
  248. switch ( cell.getCellType() )
  249. {
  250. case HSSFCell.CELL_TYPE_STRING:
  251. // XXX: enrich
  252. value = cell.getRichStringCellValue().getString();
  253. break;
  254. case HSSFCell.CELL_TYPE_FORMULA:
  255. switch ( cell.getCachedFormulaResultType() )
  256. {
  257. case HSSFCell.CELL_TYPE_STRING:
  258. HSSFRichTextString str = cell.getRichStringCellValue();
  259. if ( str != null && str.length() > 0 )
  260. {
  261. value = ( str.toString() );
  262. }
  263. else
  264. {
  265. value = ExcelToHtmlUtils.EMPTY;
  266. }
  267. break;
  268. case HSSFCell.CELL_TYPE_NUMERIC:
  269. double nValue = cell.getNumericCellValue();
  270. short df = cellStyle.getDataFormat();
  271. String dfs = cellStyle.getDataFormatString();
  272. value = _formatter.formatRawCellContents(nValue, df, dfs);
  273. break;
  274. case HSSFCell.CELL_TYPE_BOOLEAN:
  275. value = String.valueOf( cell.getBooleanCellValue() );
  276. break;
  277. case HSSFCell.CELL_TYPE_ERROR:
  278. value = ErrorEval.getText( cell.getErrorCellValue() );
  279. break;
  280. default:
  281. logger.log(
  282. POILogger.WARN,
  283. "Unexpected cell cachedFormulaResultType ("
  284. + cell.getCachedFormulaResultType() + ")" );
  285. value = ExcelToHtmlUtils.EMPTY;
  286. break;
  287. }
  288. break;
  289. case HSSFCell.CELL_TYPE_BLANK:
  290. value = ExcelToHtmlUtils.EMPTY;
  291. break;
  292. case HSSFCell.CELL_TYPE_NUMERIC:
  293. value = _formatter.formatCellValue( cell );
  294. break;
  295. case HSSFCell.CELL_TYPE_BOOLEAN:
  296. value = String.valueOf( cell.getBooleanCellValue() );
  297. break;
  298. case HSSFCell.CELL_TYPE_ERROR:
  299. value = ErrorEval.getText( cell.getErrorCellValue() );
  300. break;
  301. default:
  302. logger.log( POILogger.WARN,
  303. "Unexpected cell type (" + cell.getCellType() + ")" );
  304. return true;
  305. }
  306. final boolean noText = ExcelToHtmlUtils.isEmpty( value );
  307. final boolean wrapInDivs = !noText && isUseDivsToSpan() && !cellStyle.getWrapText();
  308. if ( cellStyle.getIndex() != 0 )
  309. {
  310. @SuppressWarnings("resource")
  311. HSSFWorkbook workbook = cell.getRow().getSheet().getWorkbook();
  312. String mainCssClass = getStyleClassName( workbook, cellStyle );
  313. if ( wrapInDivs ) {
  314. tableCellElement.setAttribute( "class", mainCssClass + " "
  315. + cssClassContainerCell );
  316. } else {
  317. tableCellElement.setAttribute( "class", mainCssClass );
  318. }
  319. if ( noText ) {
  320. /*
  321. * if cell style is defined (like borders, etc.) but cell text
  322. * is empty, add "&nbsp;" to output, so browser won't collapse
  323. * and ignore cell
  324. */
  325. value = "\u00A0";
  326. }
  327. }
  328. if ( isOutputLeadingSpacesAsNonBreaking() && value.startsWith( " " ) )
  329. {
  330. StringBuilder builder = new StringBuilder();
  331. for ( int c = 0; c < value.length(); c++ )
  332. {
  333. if ( value.charAt( c ) != ' ' )
  334. break;
  335. builder.append( '\u00a0' );
  336. }
  337. if ( value.length() != builder.length() )
  338. builder.append( value.substring( builder.length() ) );
  339. value = builder.toString();
  340. }
  341. Text text = htmlDocumentFacade.createText( value );
  342. if ( wrapInDivs )
  343. {
  344. Element outerDiv = htmlDocumentFacade.createBlock();
  345. outerDiv.setAttribute( "class", this.cssClassContainerDiv );
  346. Element innerDiv = htmlDocumentFacade.createBlock();
  347. StringBuilder innerDivStyle = new StringBuilder();
  348. innerDivStyle.append( "position:absolute;min-width:" );
  349. innerDivStyle.append( normalWidthPx );
  350. innerDivStyle.append( "px;" );
  351. if ( maxSpannedWidthPx != Integer.MAX_VALUE )
  352. {
  353. innerDivStyle.append( "max-width:" );
  354. innerDivStyle.append( maxSpannedWidthPx );
  355. innerDivStyle.append( "px;" );
  356. }
  357. innerDivStyle.append( "overflow:hidden;max-height:" );
  358. innerDivStyle.append( normalHeightPt );
  359. innerDivStyle.append( "pt;white-space:nowrap;" );
  360. ExcelToHtmlUtils.appendAlign( innerDivStyle, cellStyle.getAlignment() );
  361. htmlDocumentFacade.addStyleClass( outerDiv, cssClassPrefixDiv,
  362. innerDivStyle.toString() );
  363. innerDiv.appendChild( text );
  364. outerDiv.appendChild( innerDiv );
  365. tableCellElement.appendChild( outerDiv );
  366. }
  367. else
  368. {
  369. tableCellElement.appendChild( text );
  370. }
  371. return ExcelToHtmlUtils.isEmpty( value ) && (cellStyle.getIndex() == 0);
  372. }
  373. protected void processColumnHeaders( HSSFSheet sheet, int maxSheetColumns,
  374. Element table )
  375. {
  376. Element tableHeader = htmlDocumentFacade.createTableHeader();
  377. table.appendChild( tableHeader );
  378. Element tr = htmlDocumentFacade.createTableRow();
  379. if ( isOutputRowNumbers() )
  380. {
  381. // empty row at left-top corner
  382. tr.appendChild( htmlDocumentFacade.createTableHeaderCell() );
  383. }
  384. for ( int c = 0; c < maxSheetColumns; c++ )
  385. {
  386. if ( !isOutputHiddenColumns() && sheet.isColumnHidden( c ) )
  387. continue;
  388. Element th = htmlDocumentFacade.createTableHeaderCell();
  389. String text = getColumnName( c );
  390. th.appendChild( htmlDocumentFacade.createText( text ) );
  391. tr.appendChild( th );
  392. }
  393. tableHeader.appendChild( tr );
  394. }
  395. /**
  396. * Creates COLGROUP element with width specified for all columns. (Except
  397. * first if <tt>{@link #isOutputRowNumbers()}==true</tt>)
  398. */
  399. protected void processColumnWidths( HSSFSheet sheet, int maxSheetColumns,
  400. Element table )
  401. {
  402. // draw COLS after we know max column number
  403. Element columnGroup = htmlDocumentFacade.createTableColumnGroup();
  404. if ( isOutputRowNumbers() )
  405. {
  406. columnGroup.appendChild( htmlDocumentFacade.createTableColumn() );
  407. }
  408. for ( int c = 0; c < maxSheetColumns; c++ )
  409. {
  410. if ( !isOutputHiddenColumns() && sheet.isColumnHidden( c ) )
  411. continue;
  412. Element col = htmlDocumentFacade.createTableColumn();
  413. col.setAttribute( "width",
  414. String.valueOf( getColumnWidth( sheet, c ) ) );
  415. columnGroup.appendChild( col );
  416. }
  417. table.appendChild( columnGroup );
  418. }
  419. protected void processDocumentInformation(
  420. SummaryInformation summaryInformation )
  421. {
  422. if ( ExcelToHtmlUtils.isNotEmpty( summaryInformation.getTitle() ) )
  423. htmlDocumentFacade.setTitle( summaryInformation.getTitle() );
  424. if ( ExcelToHtmlUtils.isNotEmpty( summaryInformation.getAuthor() ) )
  425. htmlDocumentFacade.addAuthor( summaryInformation.getAuthor() );
  426. if ( ExcelToHtmlUtils.isNotEmpty( summaryInformation.getKeywords() ) )
  427. htmlDocumentFacade.addKeywords( summaryInformation.getKeywords() );
  428. if ( ExcelToHtmlUtils.isNotEmpty( summaryInformation.getComments() ) )
  429. htmlDocumentFacade
  430. .addDescription( summaryInformation.getComments() );
  431. }
  432. /**
  433. * @return maximum 1-base index of column that were rendered, zero if none
  434. */
  435. protected int processRow( CellRangeAddress[][] mergedRanges, HSSFRow row,
  436. Element tableRowElement )
  437. {
  438. final HSSFSheet sheet = row.getSheet();
  439. final short maxColIx = row.getLastCellNum();
  440. if ( maxColIx <= 0 )
  441. return 0;
  442. final List<Element> emptyCells = new ArrayList<Element>( maxColIx );
  443. if ( isOutputRowNumbers() )
  444. {
  445. Element tableRowNumberCellElement = htmlDocumentFacade
  446. .createTableHeaderCell();
  447. processRowNumber( row, tableRowNumberCellElement );
  448. emptyCells.add( tableRowNumberCellElement );
  449. }
  450. int maxRenderedColumn = 0;
  451. for ( int colIx = 0; colIx < maxColIx; colIx++ )
  452. {
  453. if ( !isOutputHiddenColumns() && sheet.isColumnHidden( colIx ) )
  454. continue;
  455. CellRangeAddress range = ExcelToHtmlUtils.getMergedRange(
  456. mergedRanges, row.getRowNum(), colIx );
  457. if ( range != null
  458. && ( range.getFirstColumn() != colIx || range.getFirstRow() != row
  459. .getRowNum() ) )
  460. continue;
  461. HSSFCell cell = row.getCell( colIx );
  462. int divWidthPx = 0;
  463. if ( isUseDivsToSpan() )
  464. {
  465. divWidthPx = getColumnWidth( sheet, colIx );
  466. boolean hasBreaks = false;
  467. for ( int nextColumnIndex = colIx + 1; nextColumnIndex < maxColIx; nextColumnIndex++ )
  468. {
  469. if ( !isOutputHiddenColumns()
  470. && sheet.isColumnHidden( nextColumnIndex ) )
  471. continue;
  472. if ( row.getCell( nextColumnIndex ) != null
  473. && !isTextEmpty( row.getCell( nextColumnIndex ) ) )
  474. {
  475. hasBreaks = true;
  476. break;
  477. }
  478. divWidthPx += getColumnWidth( sheet, nextColumnIndex );
  479. }
  480. if ( !hasBreaks )
  481. divWidthPx = Integer.MAX_VALUE;
  482. }
  483. Element tableCellElement = htmlDocumentFacade.createTableCell();
  484. if ( range != null )
  485. {
  486. if ( range.getFirstColumn() != range.getLastColumn() )
  487. tableCellElement.setAttribute(
  488. "colspan",
  489. String.valueOf( range.getLastColumn()
  490. - range.getFirstColumn() + 1 ) );
  491. if ( range.getFirstRow() != range.getLastRow() )
  492. tableCellElement.setAttribute(
  493. "rowspan",
  494. String.valueOf( range.getLastRow()
  495. - range.getFirstRow() + 1 ) );
  496. }
  497. boolean emptyCell;
  498. if ( cell != null )
  499. {
  500. emptyCell = processCell( cell, tableCellElement,
  501. getColumnWidth( sheet, colIx ), divWidthPx,
  502. row.getHeight() / 20f );
  503. }
  504. else
  505. {
  506. emptyCell = true;
  507. }
  508. if ( emptyCell )
  509. {
  510. emptyCells.add( tableCellElement );
  511. }
  512. else
  513. {
  514. for ( Element emptyCellElement : emptyCells )
  515. {
  516. tableRowElement.appendChild( emptyCellElement );
  517. }
  518. emptyCells.clear();
  519. tableRowElement.appendChild( tableCellElement );
  520. maxRenderedColumn = colIx;
  521. }
  522. }
  523. return maxRenderedColumn + 1;
  524. }
  525. protected void processRowNumber( HSSFRow row,
  526. Element tableRowNumberCellElement )
  527. {
  528. tableRowNumberCellElement.setAttribute( "class", "rownumber" );
  529. Text text = htmlDocumentFacade.createText( getRowName( row ) );
  530. tableRowNumberCellElement.appendChild( text );
  531. }
  532. protected void processSheet( HSSFSheet sheet )
  533. {
  534. processSheetHeader( htmlDocumentFacade.getBody(), sheet );
  535. final int physicalNumberOfRows = sheet.getPhysicalNumberOfRows();
  536. if ( physicalNumberOfRows <= 0 )
  537. return;
  538. Element table = htmlDocumentFacade.createTable();
  539. htmlDocumentFacade.addStyleClass( table, cssClassPrefixTable,
  540. "border-collapse:collapse;border-spacing:0;" );
  541. Element tableBody = htmlDocumentFacade.createTableBody();
  542. final CellRangeAddress[][] mergedRanges = ExcelToHtmlUtils
  543. .buildMergedRangesMap( sheet );
  544. final List<Element> emptyRowElements = new ArrayList<Element>(
  545. physicalNumberOfRows );
  546. int maxSheetColumns = 1;
  547. for ( int r = sheet.getFirstRowNum(); r <= sheet.getLastRowNum(); r++ )
  548. {
  549. HSSFRow row = sheet.getRow( r );
  550. if ( row == null )
  551. continue;
  552. if ( !isOutputHiddenRows() && row.getZeroHeight() )
  553. continue;
  554. Element tableRowElement = htmlDocumentFacade.createTableRow();
  555. htmlDocumentFacade.addStyleClass( tableRowElement,
  556. cssClassPrefixRow, "height:" + ( row.getHeight() / 20f )
  557. + "pt;" );
  558. int maxRowColumnNumber = processRow( mergedRanges, row,
  559. tableRowElement );
  560. if ( maxRowColumnNumber == 0 )
  561. {
  562. emptyRowElements.add( tableRowElement );
  563. }
  564. else
  565. {
  566. if ( !emptyRowElements.isEmpty() )
  567. {
  568. for ( Element emptyRowElement : emptyRowElements )
  569. {
  570. tableBody.appendChild( emptyRowElement );
  571. }
  572. emptyRowElements.clear();
  573. }
  574. tableBody.appendChild( tableRowElement );
  575. }
  576. maxSheetColumns = Math.max( maxSheetColumns, maxRowColumnNumber );
  577. }
  578. processColumnWidths( sheet, maxSheetColumns, table );
  579. if ( isOutputColumnHeaders() )
  580. {
  581. processColumnHeaders( sheet, maxSheetColumns, table );
  582. }
  583. table.appendChild( tableBody );
  584. htmlDocumentFacade.getBody().appendChild( table );
  585. }
  586. protected void processSheetHeader( Element htmlBody, HSSFSheet sheet )
  587. {
  588. Element h2 = htmlDocumentFacade.createHeader2();
  589. h2.appendChild( htmlDocumentFacade.createText( sheet.getSheetName() ) );
  590. htmlBody.appendChild( h2 );
  591. }
  592. public void processWorkbook( HSSFWorkbook workbook )
  593. {
  594. final SummaryInformation summaryInformation = workbook
  595. .getSummaryInformation();
  596. if ( summaryInformation != null )
  597. {
  598. processDocumentInformation( summaryInformation );
  599. }
  600. if ( isUseDivsToSpan() )
  601. {
  602. // prepare CSS classes for later usage
  603. this.cssClassContainerCell = htmlDocumentFacade
  604. .getOrCreateCssClass( cssClassPrefixCell,
  605. "padding:0;margin:0;align:left;vertical-align:top;" );
  606. this.cssClassContainerDiv = htmlDocumentFacade.getOrCreateCssClass(
  607. cssClassPrefixDiv, "position:relative;" );
  608. }
  609. for ( int s = 0; s < workbook.getNumberOfSheets(); s++ )
  610. {
  611. HSSFSheet sheet = workbook.getSheetAt( s );
  612. processSheet( sheet );
  613. }
  614. htmlDocumentFacade.updateStylesheet();
  615. }
  616. public void setCssClassPrefixCell( String cssClassPrefixCell )
  617. {
  618. this.cssClassPrefixCell = cssClassPrefixCell;
  619. }
  620. public void setCssClassPrefixDiv( String cssClassPrefixDiv )
  621. {
  622. this.cssClassPrefixDiv = cssClassPrefixDiv;
  623. }
  624. public void setCssClassPrefixRow( String cssClassPrefixRow )
  625. {
  626. this.cssClassPrefixRow = cssClassPrefixRow;
  627. }
  628. public void setCssClassPrefixTable( String cssClassPrefixTable )
  629. {
  630. this.cssClassPrefixTable = cssClassPrefixTable;
  631. }
  632. /**
  633. * Allows converter to wrap content into two additional DIVs with tricky
  634. * styles, so it will wrap across empty cells (like in Excel).
  635. * <p>
  636. * <b>Warning:</b> after enabling this mode do not serialize result HTML
  637. * with INDENT=YES option, because line breaks will make additional
  638. * (unwanted) changes
  639. */
  640. public void setUseDivsToSpan( boolean useDivsToSpan )
  641. {
  642. this.useDivsToSpan = useDivsToSpan;
  643. }
  644. }