package org.geoserver.wfs.response; import java.io.IOException; import java.io.Writer; import java.util.Calendar; import java.util.Date; import org.apache.poi.ss.usermodel.DateUtil; import org.apache.poi.ss.util.CellReference; import org.apache.xerces.util.XMLChar; /** * Spreadsheet writer to directly generate OOXML spreadsheets instead of builing them in the Apache * POI object model, which eats up tons of memory. Taken from existing example by Yegor Kozlov * * @see <a * href="http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xssf/usermodel/examples/BigGridDemo.java">Code * by Yegor Kozlov</a> * * @author Shane StClair, Axiom Consulting and Design, shane@axiomalaska.com */ public class SpreadsheetWriter { private final Writer _out; private int _rownum; private String xmlEncoding = "UTF-8"; public SpreadsheetWriter(Writer out) { _out = out; } public SpreadsheetWriter(Writer out, String xmlEncoding) { _out = out; this.xmlEncoding = xmlEncoding; } public void beginSheet() throws IOException { _out.write("<?xml version=\"1.0\" encoding=\"" + xmlEncoding + "\"?>" + "<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">"); _out.write("<sheetData>\n"); } public void endSheet() throws IOException { _out.write("</sheetData>"); _out.write("</worksheet>"); } /** * Insert a new row * * @param rownum * 0-based row number */ public void insertRow(int rownum) throws IOException { _out.write("<row r=\"" + (rownum + 1) + "\">\n"); this._rownum = rownum; } /** * Insert row end marker */ public void endRow() throws IOException { _out.write("</row>\n"); } public void createCell(int columnIndex, String value, int styleIndex) throws IOException { String ref = new CellReference(_rownum, columnIndex).formatAsString(); _out.write("<c r=\"" + ref + "\" t=\"inlineStr\""); if (styleIndex != -1) _out.write(" s=\"" + styleIndex + "\""); _out.write(">"); _out.write("<is><t>" + santizeForXml(value) + "</t></is>"); _out.write("</c>"); } public void createCell(int columnIndex, String value) throws IOException { createCell(columnIndex, value, -1); } public void createCell(int columnIndex, double value, int styleIndex) throws IOException { String ref = new CellReference(_rownum, columnIndex).formatAsString(); _out.write("<c r=\"" + ref + "\" t=\"n\""); if (styleIndex != -1) _out.write(" s=\"" + styleIndex + "\""); _out.write(">"); _out.write("<v>" + value + "</v>"); _out.write("</c>"); } public void createCell(int columnIndex, double value) throws IOException { createCell(columnIndex, value, -1); } public void createCell(int columnIndex, boolean value) throws IOException { createCell(columnIndex, value, -1); } public void createCell(int columnIndex, boolean value, int styleIndex) throws IOException { String ref = new CellReference(_rownum, columnIndex).formatAsString(); _out.write("<c r=\"" + ref + "\" t=\"b\""); if (styleIndex != -1) _out.write(" s=\"" + styleIndex + "\""); _out.write(">"); _out.write("<v>" + (value ? 1 : 0) + "</v>"); _out.write("</c>"); } public void createCell(int columnIndex, Calendar value, int styleIndex) throws IOException { createCell(columnIndex, DateUtil.getExcelDate(value, false), styleIndex); } public void createCell(int columnIndex, Date value, int styleIndex) throws IOException { createCell(columnIndex, DateUtil.getExcelDate(value, false), styleIndex); } private String cData(String str) { return "<![CDATA[" + str + "]]>"; } private String santizeForXml(String str) { StringBuilder strBuilder = new StringBuilder(); boolean stringHasSpecial = false; for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); if (!XMLChar.isInvalid(c)) { strBuilder.append(c); stringHasSpecial = stringHasSpecial || charIsSpecial(c); } } if (stringHasSpecial) { return cData(strBuilder.toString()); } return strBuilder.toString(); } private boolean charIsSpecial(char c) { if (c == '&' || c == '<' || c == '>') return true; return false; } }