001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.generation;
018:
019: import org.apache.avalon.framework.configuration.Configurable;
020: import org.apache.avalon.framework.configuration.Configuration;
021: import org.apache.avalon.framework.configuration.ConfigurationException;
022: import org.apache.avalon.framework.parameters.Parameters;
023:
024: import org.apache.cocoon.ProcessingException;
025: import org.apache.cocoon.components.source.SourceUtil;
026: import org.apache.cocoon.environment.SourceResolver;
027: import org.apache.commons.lang.BooleanUtils;
028:
029: import org.apache.excalibur.source.Source;
030: import org.apache.excalibur.source.SourceException;
031: import org.apache.poi.hssf.usermodel.HSSFCell;
032: import org.apache.poi.hssf.usermodel.HSSFCellStyle;
033: import org.apache.poi.hssf.usermodel.HSSFFont;
034: import org.apache.poi.hssf.usermodel.HSSFRow;
035: import org.apache.poi.hssf.usermodel.HSSFSheet;
036: import org.apache.poi.hssf.usermodel.HSSFWorkbook;
037: import org.xml.sax.SAXException;
038: import org.xml.sax.helpers.AttributesImpl;
039:
040: import java.io.IOException;
041: import java.util.Iterator;
042: import java.util.Map;
043:
044: /**
045: * This generator generates - using Apache POI - a Gnumeric compliant XML
046: * Document from a Microsoft Excel Workbook.
047: *
048: * <h3>Sitemap Definition</h3>
049: * <map:generator type="xls" src="org.apache.cocoon.generation.HSSFGenerator">
050: * <uri>http://www.gnome.org/gnumeric/v7</uri>
051: * <prefix>gmr</prefix>
052: * <formatting>false</formatting>
053: * </map:generator>
054: *
055: * <h3>Sitemap Use</h3>
056: * <map:generate type="xls" src="spreadsheet.xls"/>
057: *
058: * <p>You can set the parameter <code>formatting</code> to <code>true</code>
059: * in order to receive not only the data but also the formatting information
060: * of the workbook.</p>
061: *
062: * @author <a href="patrick@arpage.ch">Patrick Herber</a>
063: * @version $Id: HSSFGenerator.java 433543 2006-08-22 06:22:54Z crossley $
064: */
065: public class HSSFGenerator extends AbstractGenerator implements
066: Configurable {
067:
068: public static final String NAMESPACE_PREFIX = "gmr";
069: public static final String NAMESPACE_URI = "http://www.gnome.org/gnumeric/v7";
070: private static final boolean FORMATTING = false;
071:
072: private static final String CONF_NAMESPACE_URI = "uri";
073: private static final String CONF_NAMESPACE_PREFIX = "prefix";
074: private static final String CONF_FORMATTING = "formatting";
075:
076: private String defaultUri;
077: private String defaultPrefix;
078: private boolean defaultFormatting;
079:
080: private String uri;
081: private String prefix;
082: private boolean formatting;
083: private final AttributesImpl attr;
084:
085: protected Source inputSource;
086:
087: public HSSFGenerator() {
088: this .attr = new AttributesImpl();
089: }
090:
091: public void configure(Configuration configuration)
092: throws ConfigurationException {
093: this .defaultUri = configuration.getChild(CONF_NAMESPACE_URI)
094: .getValue(NAMESPACE_URI);
095: this .defaultPrefix = configuration.getChild(
096: CONF_NAMESPACE_PREFIX).getValue(NAMESPACE_PREFIX);
097: this .defaultFormatting = configuration
098: .getChild(CONF_FORMATTING)
099: .getValueAsBoolean(FORMATTING);
100: }
101:
102: public void setup(SourceResolver resolver, Map objectModel,
103: String src, Parameters par) throws ProcessingException,
104: SAXException, IOException {
105: super .setup(resolver, objectModel, src, par);
106: this .uri = par
107: .getParameter(CONF_NAMESPACE_URI, this .defaultUri);
108: this .prefix = par.getParameter(CONF_NAMESPACE_PREFIX,
109: this .defaultPrefix);
110: this .formatting = par.getParameterAsBoolean(CONF_FORMATTING,
111: this .defaultFormatting);
112:
113: try {
114: this .inputSource = super .resolver.resolveURI(src);
115: } catch (SourceException se) {
116: throw SourceUtil.handle("Error resolving '" + src + "'.",
117: se);
118: }
119: }
120:
121: /**
122: * Recycle this component. All instance variables are set to
123: * <code>null</code>.
124: */
125: public void recycle() {
126: if (this .inputSource != null) {
127: super .resolver.release(this .inputSource);
128: this .inputSource = null;
129: }
130: this .attr.clear();
131: super .recycle();
132: }
133:
134: /**
135: * Generate XML data.
136: */
137: public void generate() throws SAXException, IOException {
138: HSSFWorkbook workbook = new HSSFWorkbook(this .inputSource
139: .getInputStream());
140: writeXML(workbook);
141: }
142:
143: /**
144: * Writes out the workbook data as XML, without formatting information
145: */
146: private void writeXML(HSSFWorkbook workbook) throws SAXException {
147: this .contentHandler.startDocument();
148: start("Workbook");
149: start("SheetNameIndex");
150: for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
151: start("SheetName");
152: data(workbook.getSheetName(i));
153: end("SheetName");
154: }
155: end("SheetNameIndex");
156: start("Sheets");
157: for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
158: HSSFSheet sheet = workbook.getSheetAt(i);
159: start("Sheet");
160: start("Name");
161: data(workbook.getSheetName(i));
162: end("Name");
163: start("MaxCol");
164: data(Integer.toString(getMaxCol(sheet)));
165: end("MaxCol");
166: start("MaxRow");
167: data(Integer.toString(sheet.getLastRowNum()));
168: end("MaxRow");
169: if (formatting) {
170: writeStyles(workbook, sheet);
171: }
172:
173: start("Cells");
174: final Iterator rows = sheet.rowIterator();
175: while (rows.hasNext()) {
176: final HSSFRow row = (HSSFRow) rows.next();
177: final Iterator cells = row.cellIterator();
178: while (cells.hasNext()) {
179: final HSSFCell cell = (HSSFCell) cells.next();
180: attribute("Row", Integer.toString(row.getRowNum()));
181: attribute("Col", Short.toString(cell.getCellNum()));
182: attribute("ValueType", getValueType(cell
183: .getCellType()));
184: start("Cell");
185: data(getValue(cell));
186: end("Cell");
187: }
188: }
189: end("Cells");
190:
191: end("Sheet");
192: }
193: end("Sheets");
194: end("Workbook");
195: this .contentHandler.endDocument();
196: }
197:
198: /**
199: * Returns the max column index of the given sheet
200: * @param sheet
201: * @return the max column index
202: */
203: private int getMaxCol(HSSFSheet sheet) {
204: int max = -1;
205: HSSFRow row = null;
206: Iterator rows = sheet.rowIterator();
207: while (rows.hasNext()) {
208: row = (HSSFRow) rows.next();
209: int lastNum = row.getLastCellNum();
210: if (lastNum > max) {
211: max = lastNum;
212: }
213: }
214: return max;
215: }
216:
217: /**
218: * Returns the Gnumeric cell type.
219: * @param cellType POI cell type
220: * @return the Gnumeric cell type.
221: */
222: private String getValueType(int cellType) {
223: switch (cellType) {
224: case HSSFCell.CELL_TYPE_BLANK:
225: return "10";
226: case HSSFCell.CELL_TYPE_BOOLEAN:
227: return "20";
228: case HSSFCell.CELL_TYPE_NUMERIC:
229: return "40";
230: case HSSFCell.CELL_TYPE_ERROR:
231: return "50";
232: case HSSFCell.CELL_TYPE_FORMULA:
233: case HSSFCell.CELL_TYPE_STRING:
234: default:
235: return "60";
236: }
237: }
238:
239: /**
240: * Returns the cell value.
241: * @param cell POI cell
242: * @return the cell value
243: */
244: private String getValue(HSSFCell cell) {
245: switch (cell.getCellType()) {
246: case HSSFCell.CELL_TYPE_BLANK:
247: return "";
248: case HSSFCell.CELL_TYPE_BOOLEAN:
249: return BooleanUtils.toStringTrueFalse(cell
250: .getBooleanCellValue());
251: case HSSFCell.CELL_TYPE_NUMERIC:
252: return Double.toString(cell.getNumericCellValue());
253: case HSSFCell.CELL_TYPE_ERROR:
254: return "#ERR" + cell.getErrorCellValue();
255: case HSSFCell.CELL_TYPE_FORMULA:
256: case HSSFCell.CELL_TYPE_STRING:
257: default:
258: return cell.getStringCellValue();
259: }
260: }
261:
262: /**
263: * Writes out the workbook data as XML, with formatting information
264: */
265: private void writeStyles(HSSFWorkbook workbook, HSSFSheet sheet)
266: throws SAXException {
267: start("Styles");
268: HSSFRow row = null;
269: HSSFCell cell = null;
270: Iterator cells = null;
271: Iterator rows = sheet.rowIterator();
272: while (rows.hasNext()) {
273: row = (HSSFRow) rows.next();
274: cells = row.cellIterator();
275: while (cells.hasNext()) {
276: cell = (HSSFCell) cells.next();
277: attribute("startRow", Integer.toString(row.getRowNum()));
278: attribute("endRow", Integer.toString(row.getRowNum()));
279: attribute("startCol", Short.toString(cell.getCellNum()));
280: attribute("endCol", Short.toString(cell.getCellNum()));
281: start("StyleRegion");
282: HSSFCellStyle style = cell.getCellStyle();
283: attribute("HAlign", Integer.toString(style
284: .getAlignment()));
285: attribute("VAlign", Integer.toString(style
286: .getVerticalAlignment()));
287: attribute("WrapText", ((style.getWrapText()) ? "1"
288: : "0"));
289: attribute("Orient", Integer.toString(style
290: .getRotation()));
291: attribute("Indent", Integer.toString(style
292: .getIndention()));
293: attribute("Locked", ((style.getLocked()) ? "1" : "0"));
294: attribute("Hidden", ((style.getHidden()) ? "1" : "0"));
295: attribute("Fore", workbook.getCustomPalette().getColor(
296: style.getFillForegroundColor()).getHexString());
297: attribute("Back", workbook.getCustomPalette().getColor(
298: style.getFillBackgroundColor()).getHexString());
299: attribute("PatternColor", Integer.toString(style
300: .getFillPattern())); // TODO
301: attribute("Format", "General"); // TODO
302: start("Style");
303: HSSFFont font = workbook
304: .getFontAt(style.getFontIndex());
305: attribute("Unit", Short.toString(font
306: .getFontHeightInPoints()));
307: attribute("Bold", Short.toString(font.getBoldweight()));
308: attribute("Italic", ((font.getItalic()) ? "1" : "0"));
309: attribute("Unterline", Integer.toString(font
310: .getUnderline()));
311: attribute("StrikeThrough", ((font.getStrikeout()) ? "1"
312: : "0"));
313: start("Font");
314: data(font.getFontName());
315: end("Font");
316: end("Style");
317: end("StyleRegion");
318: }
319: }
320: end("Styles");
321: }
322:
323: //
324: // Utility methods
325: //
326:
327: /**
328: * Adds an attribute with the given name and value.
329: */
330: private void attribute(String name, String value) {
331: attr.addAttribute("", name, name, "CDATA", value);
332: }
333:
334: /**
335: * Starts an element with the given local name.
336: * @param name local name of the element
337: * @throws SAXException
338: */
339: private void start(String name) throws SAXException {
340: super .contentHandler.startElement(uri, name, prefix + ":"
341: + name, attr);
342: attr.clear();
343: }
344:
345: /**
346: * Ends the given element.
347: * @param name local name of the element
348: * @throws SAXException
349: */
350: private void end(String name) throws SAXException {
351: super .contentHandler.endElement(uri, name, prefix + ":" + name);
352: }
353:
354: /**
355: * Writes the given element data.
356: * @param data
357: * @throws SAXException
358: */
359: private void data(String data) throws SAXException {
360: super .contentHandler.characters(data.toCharArray(), 0, data
361: .length());
362: }
363: }
|