/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cocoon.generation; import org.apache.avalon.framework.configuration.Configurable; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.avalon.framework.parameters.Parameters; import org.apache.cocoon.ProcessingException; import org.apache.cocoon.components.source.SourceUtil; import org.apache.cocoon.environment.SourceResolver; import org.apache.commons.lang.BooleanUtils; import org.apache.excalibur.source.Source; import org.apache.excalibur.source.SourceException; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.usermodel.HSSFFont; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; import java.io.IOException; import java.util.Iterator; import java.util.Map; /** * This generator generates - using Apache POI - a Gnumeric compliant XML * Document from a Microsoft Excel Workbook. * * <h3>Sitemap Definition</h3> * <map:generator type="xls" src="org.apache.cocoon.generation.HSSFGenerator"> * <uri>http://www.gnome.org/gnumeric/v7</uri> * <prefix>gmr</prefix> * <formatting>false</formatting> * </map:generator> * * <h3>Sitemap Use</h3> * <map:generate type="xls" src="spreadsheet.xls"/> * * <p>You can set the parameter <code>formatting</code> to <code>true</code> * in order to receive not only the data but also the formatting information * of the workbook.</p> * * @author <a href="patrick@arpage.ch">Patrick Herber</a> * @version $Id$ */ public class HSSFGenerator extends AbstractGenerator implements Configurable { public static final String NAMESPACE_PREFIX = "gmr"; public static final String NAMESPACE_URI = "http://www.gnome.org/gnumeric/v7"; private static final boolean FORMATTING = false; private static final String CONF_NAMESPACE_URI = "uri"; private static final String CONF_NAMESPACE_PREFIX = "prefix"; private static final String CONF_FORMATTING = "formatting"; private String defaultUri; private String defaultPrefix; private boolean defaultFormatting; private String uri; private String prefix; private boolean formatting; private final AttributesImpl attr; protected Source inputSource; public HSSFGenerator() { this.attr = new AttributesImpl(); } public void configure(Configuration configuration) throws ConfigurationException { this.defaultUri = configuration.getChild(CONF_NAMESPACE_URI).getValue(NAMESPACE_URI); this.defaultPrefix = configuration.getChild(CONF_NAMESPACE_PREFIX).getValue(NAMESPACE_PREFIX); this.defaultFormatting = configuration.getChild(CONF_FORMATTING).getValueAsBoolean(FORMATTING); } public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) throws ProcessingException, SAXException, IOException { super.setup(resolver, objectModel, src, par); this.uri = par.getParameter(CONF_NAMESPACE_URI, this.defaultUri); this.prefix = par.getParameter(CONF_NAMESPACE_PREFIX, this.defaultPrefix); this.formatting = par.getParameterAsBoolean(CONF_FORMATTING, this.defaultFormatting); try { this.inputSource = super.resolver.resolveURI(src); } catch (SourceException se) { throw SourceUtil.handle("Error resolving '" + src + "'.", se); } } /** * Recycle this component. All instance variables are set to * <code>null</code>. */ public void recycle() { if (this.inputSource != null) { super.resolver.release(this.inputSource); this.inputSource = null; } this.attr.clear(); super.recycle(); } /** * Generate XML data. */ public void generate() throws SAXException, IOException { HSSFWorkbook workbook = new HSSFWorkbook(this.inputSource.getInputStream()); writeXML(workbook); } /** * Writes out the workbook data as XML, without formatting information */ private void writeXML(HSSFWorkbook workbook) throws SAXException { this.contentHandler.startDocument(); start("Workbook"); start("SheetNameIndex"); for (int i = 0; i < workbook.getNumberOfSheets(); i++) { start("SheetName"); data(workbook.getSheetName(i)); end("SheetName"); } end("SheetNameIndex"); start("Sheets"); for (int i = 0; i < workbook.getNumberOfSheets(); i++) { HSSFSheet sheet = workbook.getSheetAt(i); start("Sheet"); start("Name"); data(workbook.getSheetName(i)); end("Name"); start("MaxCol"); data(Integer.toString(getMaxCol(sheet))); end("MaxCol"); start("MaxRow"); data(Integer.toString(sheet.getLastRowNum())); end("MaxRow"); if (formatting) { writeStyles(workbook, sheet); } start("Cells"); final Iterator rows = sheet.rowIterator(); while (rows.hasNext()) { final HSSFRow row = (HSSFRow) rows.next(); final Iterator cells = row.cellIterator(); while (cells.hasNext()) { final HSSFCell cell = (HSSFCell) cells.next(); attribute("Row", Integer.toString(row.getRowNum())); attribute("Col", Short.toString(cell.getCellNum())); attribute("ValueType", getValueType(cell.getCellType())); start("Cell"); data(getValue(cell)); end("Cell"); } } end("Cells"); end("Sheet"); } end("Sheets"); end("Workbook"); this.contentHandler.endDocument(); } /** * Returns the max column index of the given sheet * @param sheet * @return the max column index */ private int getMaxCol(HSSFSheet sheet) { int max = -1; HSSFRow row = null; Iterator rows = sheet.rowIterator(); while (rows.hasNext()) { row = (HSSFRow) rows.next(); int lastNum = row.getLastCellNum(); if (lastNum > max) { max = lastNum; } } return max; } /** * Returns the Gnumeric cell type. * @param cellType POI cell type * @return the Gnumeric cell type. */ private String getValueType(int cellType) { switch (cellType) { case HSSFCell.CELL_TYPE_BLANK: return "10"; case HSSFCell.CELL_TYPE_BOOLEAN: return "20"; case HSSFCell.CELL_TYPE_NUMERIC: return "40"; case HSSFCell.CELL_TYPE_ERROR: return "50"; case HSSFCell.CELL_TYPE_FORMULA: case HSSFCell.CELL_TYPE_STRING: default: return "60"; } } /** * Returns the cell value. * @param cell POI cell * @return the cell value */ private String getValue(HSSFCell cell) { switch (cell.getCellType()) { case HSSFCell.CELL_TYPE_BLANK: return ""; case HSSFCell.CELL_TYPE_BOOLEAN: return BooleanUtils.toStringTrueFalse(cell.getBooleanCellValue()); case HSSFCell.CELL_TYPE_NUMERIC: return Double.toString(cell.getNumericCellValue()); case HSSFCell.CELL_TYPE_ERROR: return "#ERR" + cell.getErrorCellValue(); case HSSFCell.CELL_TYPE_FORMULA: case HSSFCell.CELL_TYPE_STRING: default: return cell.getStringCellValue(); } } /** * Writes out the workbook data as XML, with formatting information */ private void writeStyles(HSSFWorkbook workbook, HSSFSheet sheet) throws SAXException { start("Styles"); HSSFRow row = null; HSSFCell cell = null; Iterator cells = null; Iterator rows = sheet.rowIterator(); while (rows.hasNext()) { row = (HSSFRow) rows.next(); cells = row.cellIterator(); while (cells.hasNext()) { cell = (HSSFCell) cells.next(); attribute("startRow", Integer.toString(row.getRowNum())); attribute("endRow", Integer.toString(row.getRowNum())); attribute("startCol", Short.toString(cell.getCellNum())); attribute("endCol", Short.toString(cell.getCellNum())); start("StyleRegion"); HSSFCellStyle style = cell.getCellStyle(); attribute("HAlign", Integer.toString(style.getAlignment())); attribute("VAlign", Integer.toString(style.getVerticalAlignment())); attribute("WrapText", ((style.getWrapText()) ? "1" : "0")); attribute("Orient", Integer.toString(style.getRotation())); attribute("Indent", Integer.toString(style.getIndention())); attribute("Locked", ((style.getLocked()) ? "1" : "0")); attribute("Hidden", ((style.getHidden()) ? "1" : "0")); attribute("Fore", workbook.getCustomPalette().getColor(style.getFillForegroundColor()).getHexString()); attribute("Back", workbook.getCustomPalette().getColor(style.getFillBackgroundColor()).getHexString()); attribute("PatternColor", Integer.toString(style.getFillPattern())); // TODO attribute("Format", "General"); // TODO start("Style"); HSSFFont font = workbook.getFontAt(style.getFontIndex()); attribute("Unit", Short.toString(font.getFontHeightInPoints())); attribute("Bold", Short.toString(font.getBoldweight())); attribute("Italic", ((font.getItalic()) ? "1" : "0")); attribute("Unterline", Integer.toString(font.getUnderline())); attribute("StrikeThrough", ((font.getStrikeout()) ? "1" : "0")); start("Font"); data(font.getFontName()); end("Font"); end("Style"); end("StyleRegion"); } } end("Styles"); } // // Utility methods // /** * Adds an attribute with the given name and value. */ private void attribute(String name, String value) { attr.addAttribute("", name, name, "CDATA", value); } /** * Starts an element with the given local name. * @param name local name of the element * @throws SAXException */ private void start(String name) throws SAXException { super.contentHandler.startElement(uri, name, prefix + ":" + name, attr); attr.clear(); } /** * Ends the given element. * @param name local name of the element * @throws SAXException */ private void end(String name) throws SAXException { super.contentHandler.endElement(uri, name, prefix + ":" + name); } /** * Writes the given element data. * @param data * @throws SAXException */ private void data(String data) throws SAXException { super.contentHandler.characters(data.toCharArray(), 0, data.length()); } }