Tidy up the xssf models stuff, by pushing more of the logic onto XSSFWorkbook

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@637688 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2008-03-16 23:30:51 +00:00
parent fe2cd2d286
commit 86bac45ee8
6 changed files with 151 additions and 129 deletions

View File

@ -39,9 +39,4 @@ public interface SharedStringSource {
* @return The 0-based position of the newly added string. * @return The 0-based position of the newly added string.
*/ */
public int putSharedString(String s); public int putSharedString(String s);
/**
* Write back out
*/
public void save() throws IOException;
} }

View File

@ -16,14 +16,10 @@
==================================================================== */ ==================================================================== */
package org.apache.poi.ss.usermodel; package org.apache.poi.ss.usermodel;
import java.io.IOException;
public interface StylesSource { public interface StylesSource {
public String getNumberFormatAt(long idx); public String getNumberFormatAt(long idx);
public long putNumberFormat(String fmt); public long putNumberFormat(String fmt);
/** public Font getFontAt(long idx);
* Write back out public long putFont(Font font);
*/
public void save() throws IOException;
} }

View File

@ -25,7 +25,6 @@ import java.util.LinkedList;
import org.apache.poi.ss.usermodel.SharedStringSource; import org.apache.poi.ss.usermodel.SharedStringSource;
import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions; import org.apache.xmlbeans.XmlOptions;
import org.openxml4j.opc.PackagePart;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRst; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRst;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSst; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSst;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.SstDocument; import org.openxmlformats.schemas.spreadsheetml.x2006.main.SstDocument;
@ -34,32 +33,28 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.SstDocument;
/** /**
* Table of strings shared across all sheets in a workbook. * Table of strings shared across all sheets in a workbook.
* *
* FIXME: I don't like having a dependency on PackagePart (from OpenXML4J) in model classes.
* I'd rather let Workbook keep track of all part-document relationships and keep all other
* classes clean. -- Ugo
*
* @version $Id$ * @version $Id$
*/ */
public class SharedStringsTable implements SharedStringSource, XSSFModel { public class SharedStringsTable implements SharedStringSource, XSSFModel {
private final LinkedList<String> strings = new LinkedList<String>(); private final LinkedList<String> strings = new LinkedList<String>();
private SstDocument doc;
private PackagePart part;
/** /**
* Create a new SharedStringsTable by reading it from a PackagePart. * Create a new SharedStringsTable, by reading it
* from the InputStream of a PackagePart.
* *
* @param part The PackagePart to read. * @param is The input stream containing the XML document.
* @throws IOException if an error occurs while reading. * @throws IOException if an error occurs while reading.
*/ */
public SharedStringsTable(PackagePart part) throws IOException { public SharedStringsTable(InputStream is) throws IOException {
this.part = part;
InputStream is = part.getInputStream();
try {
readFrom(is); readFrom(is);
} finally {
if (is != null) is.close();
} }
/**
* Create a new, empty SharedStringsTable
*/
public SharedStringsTable() {
doc = SstDocument.Factory.newInstance();
} }
/** /**
@ -70,7 +65,7 @@ public class SharedStringsTable implements SharedStringSource, XSSFModel {
*/ */
public void readFrom(InputStream is) throws IOException { public void readFrom(InputStream is) throws IOException {
try { try {
SstDocument doc = SstDocument.Factory.parse(is); doc = SstDocument.Factory.parse(is);
for (CTRst rst : doc.getSst().getSiArray()) { for (CTRst rst : doc.getSst().getSiArray()) {
strings.add(rst.getT()); strings.add(rst.getT());
} }
@ -91,20 +86,6 @@ public class SharedStringsTable implements SharedStringSource, XSSFModel {
return strings.size() - 1; return strings.size() - 1;
} }
/**
* Save this table to its own PackagePart.
*
* @throws IOException if an error occurs while writing.
*/
public void save() throws IOException {
OutputStream out = this.part.getOutputStream();
try {
writeTo(out);
} finally {
out.close();
}
}
/** /**
* Write this table out as XML. * Write this table out as XML.
* *

View File

@ -25,13 +25,14 @@ import java.util.Hashtable;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Map.Entry; import java.util.Map.Entry;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.StylesSource; import org.apache.poi.ss.usermodel.StylesSource;
import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions; import org.apache.xmlbeans.XmlOptions;
import org.openxml4j.opc.PackagePart;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBorder; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBorder;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFill; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFill;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFont; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFont;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTFonts;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTNumFmt; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTNumFmt;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTNumFmts; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTNumFmts;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.StyleSheetDocument;; import org.openxmlformats.schemas.spreadsheetml.x2006.main.StyleSheetDocument;;
@ -40,10 +41,6 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.StyleSheetDocument;;
/** /**
* Table of styles shared across all sheets in a workbook. * Table of styles shared across all sheets in a workbook.
* *
* FIXME: I don't like having a dependency on PackagePart (from OpenXML4J) in model classes.
* I'd rather let Workbook keep track of all part-document relationships and keep all other
* classes clean. -- Ugo
*
* @version $Id: SharedStringsTable.java 612495 2008-01-16 16:08:22Z ugo $ * @version $Id: SharedStringsTable.java 612495 2008-01-16 16:08:22Z ugo $
*/ */
public class StylesTable implements StylesSource, XSSFModel { public class StylesTable implements StylesSource, XSSFModel {
@ -52,23 +49,28 @@ public class StylesTable implements StylesSource, XSSFModel {
private final LinkedList<CTFill> fills = new LinkedList<CTFill>(); private final LinkedList<CTFill> fills = new LinkedList<CTFill>();
private final LinkedList<CTBorder> borders = new LinkedList<CTBorder>(); private final LinkedList<CTBorder> borders = new LinkedList<CTBorder>();
private PackagePart part; /**
* The first style id available for use as a custom style
*/
public static final long FIRST_CUSTOM_STYLE_ID = 165;
private StyleSheetDocument doc; private StyleSheetDocument doc;
/** /**
* Create a new StylesTable by reading it from a PackagePart. * Create a new StylesTable, by reading it from
* the InputStream of a a PackagePart.
* *
* @param part The PackagePart to read. * @param is The input stream containing the XML document.
* @throws IOException if an error occurs while reading. * @throws IOException if an error occurs while reading.
*/ */
public StylesTable(PackagePart part) throws IOException { public StylesTable(InputStream is) throws IOException {
this.part = part;
InputStream is = part.getInputStream();
try {
readFrom(is); readFrom(is);
} finally {
if (is != null) is.close();
} }
/**
* Create a new, empty StylesTable
*/
public StylesTable() {
doc = StyleSheetDocument.Factory.newInstance();
} }
/** /**
@ -106,7 +108,6 @@ public class StylesTable implements StylesSource, XSSFModel {
public String getNumberFormatAt(long idx) { public String getNumberFormatAt(long idx) {
return numberFormats.get(idx); return numberFormats.get(idx);
} }
public synchronized long putNumberFormat(String fmt) { public synchronized long putNumberFormat(String fmt) {
if (numberFormats.containsValue(fmt)) { if (numberFormats.containsValue(fmt)) {
// Find the key, and return that // Find the key, and return that
@ -120,7 +121,7 @@ public class StylesTable implements StylesSource, XSSFModel {
} }
// Find a spare key, and add that // Find a spare key, and add that
long newKey = 1; long newKey = FIRST_CUSTOM_STYLE_ID;
while(numberFormats.containsKey(newKey)) { while(numberFormats.containsKey(newKey)) {
newKey++; newKey++;
} }
@ -128,6 +129,15 @@ public class StylesTable implements StylesSource, XSSFModel {
return newKey; return newKey;
} }
public Font getFontAt(long idx) {
// TODO
return null;
}
public synchronized long putFont(Font font) {
// TODO
return -1;
}
/** /**
* For unit testing only * For unit testing only
*/ */
@ -154,20 +164,6 @@ public class StylesTable implements StylesSource, XSSFModel {
} }
/**
* Save this table to its own PackagePart.
*
* @throws IOException if an error occurs while writing.
*/
public void save() throws IOException {
OutputStream out = this.part.getOutputStream();
try {
writeTo(out);
} finally {
out.close();
}
}
/** /**
* Write this table out as XML. * Write this table out as XML.
* *
@ -193,7 +189,12 @@ public class StylesTable implements StylesSource, XSSFModel {
doc.getStyleSheet().setNumFmts(formats); doc.getStyleSheet().setNumFmts(formats);
// Fonts // Fonts
// TODO CTFonts fnts = CTFonts.Factory.newInstance();
fnts.setCount(fonts.size());
fnts.setFontArray(
fonts.toArray(new CTFont[fonts.size()])
);
doc.getStyleSheet().setFonts(fnts);
// Fills // Fills
// TODO // TODO

View File

@ -18,7 +18,9 @@
package org.apache.poi.xssf.usermodel; package org.apache.poi.xssf.usermodel;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -65,22 +67,6 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument;
public class XSSFWorkbook extends POIXMLDocument implements Workbook { public class XSSFWorkbook extends POIXMLDocument implements Workbook {
public static class XSSFRelation {
private String TYPE;
private String REL;
private String DEFAULT_NAME;
private Class<? extends XSSFModel> CLASS;
private XSSFRelation(String TYPE, String REL, String DEFAULT_NAME, Class<? extends XSSFModel> CLASS) {
this.TYPE = TYPE;
this.REL = REL;
this.DEFAULT_NAME = DEFAULT_NAME;
this.CLASS = CLASS;
}
public String getContentType() { return TYPE; }
public String getRelation() { return REL; }
public String getDefaultFileName() { return DEFAULT_NAME; }
}
public static final XSSFRelation WORKSHEET = new XSSFRelation( public static final XSSFRelation WORKSHEET = new XSSFRelation(
"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet",
@ -112,6 +98,70 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
null null
); );
public static class XSSFRelation {
private String TYPE;
private String REL;
private String DEFAULT_NAME;
private Class<? extends XSSFModel> CLASS;
private XSSFRelation(String TYPE, String REL, String DEFAULT_NAME, Class<? extends XSSFModel> CLASS) {
this.TYPE = TYPE;
this.REL = REL;
this.DEFAULT_NAME = DEFAULT_NAME;
this.CLASS = CLASS;
}
public String getContentType() { return TYPE; }
public String getRelation() { return REL; }
public String getDefaultFileName() { return DEFAULT_NAME; }
/**
* Load, off the specified core part
*/
private XSSFModel load(PackagePart corePart) throws Exception {
Constructor<? extends XSSFModel> c = CLASS.getConstructor(InputStream.class);
XSSFModel model = null;
PackageRelationshipCollection prc =
corePart.getRelationshipsByType(REL);
Iterator<PackageRelationship> it = prc.iterator();
if(it.hasNext()) {
PackageRelationship rel = it.next();
PackagePartName relName = PackagingURIHelper.createPartName(rel.getTargetURI());
PackagePart part = corePart.getPackage().getPart(relName);
InputStream is = part.getInputStream();
try {
model = c.newInstance(is);
} finally {
is.close();
}
} else {
log.log(POILogger.WARN, "No part " + DEFAULT_NAME + " found");
}
return model;
}
/**
* Save, with the default name
*/
private void save(XSSFModel model, PackagePart corePart) throws IOException {
save(model, corePart, DEFAULT_NAME);
}
/**
* Save, with the specified name
*/
private void save(XSSFModel model, PackagePart corePart, String name) throws IOException {
PackagePartName ppName = null;
try {
ppName = PackagingURIHelper.createPartName(name);
} catch(InvalidFormatException e) {
throw new IllegalStateException(e);
}
corePart.addRelationship(ppName, TargetMode.INTERNAL, REL);
PackagePart part = corePart.getPackage().createPart(ppName, TYPE);
OutputStream out = part.getOutputStream();
model.writeTo(out);
out.close();
}
}
private CTWorkbook workbook; private CTWorkbook workbook;
private List<XSSFSheet> sheets = new LinkedList<XSSFSheet>(); private List<XSSFSheet> sheets = new LinkedList<XSSFSheet>();
@ -138,34 +188,22 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
WorkbookDocument doc = WorkbookDocument.Factory.parse(getCorePart().getInputStream()); WorkbookDocument doc = WorkbookDocument.Factory.parse(getCorePart().getInputStream());
this.workbook = doc.getWorkbook(); this.workbook = doc.getWorkbook();
PackageRelationshipCollection prc; try {
Iterator<PackageRelationship> it;
// Load shared strings // Load shared strings
prc = getCorePart().getRelationshipsByType(SHARED_STRINGS.getRelation()); this.sharedStringSource = (SharedStringSource)
it = prc.iterator(); SHARED_STRINGS.load(getCorePart());
if (it.hasNext()) {
PackageRelationship rel = it.next();
PackagePart part = getTargetPart(rel);
this.sharedStringSource = new SharedStringsTable(part);
} else {
log.log(POILogger.WARN, "No shared strings part found");
}
// Load styles source // Load styles source
prc = getCorePart().getRelationshipsByType(STYLES.getRelation()); this.stylesSource = (StylesSource)
it = prc.iterator(); STYLES.load(getCorePart());
if (it.hasNext()) { } catch(Exception e) {
PackageRelationship rel = it.next(); throw new IOException(e.getMessage());
PackagePart part = getTargetPart(rel);
this.stylesSource = new StylesTable(part);
} else {
log.log(POILogger.WARN, "No styles part found");
} }
// Load individual sheets // Load individual sheets
for (CTSheet ctSheet : this.workbook.getSheets().getSheetArray()) { for (CTSheet ctSheet : this.workbook.getSheets().getSheetArray()) {
PackagePart part = getPackagePart(ctSheet); PackagePart part = getPackagePart(ctSheet);
if (part == null) { if (part == null) {
log.log(POILogger.WARN, "Sheet with name " + ctSheet.getName() + " was defined, but didn't exist, skipping");
continue; continue;
} }
WorksheetDocument worksheetDoc = WorksheetDocument.Factory.parse(part.getInputStream()); WorksheetDocument worksheetDoc = WorksheetDocument.Factory.parse(part.getInputStream());
@ -572,21 +610,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
// Write shared strings and styles // Write shared strings and styles
if(sharedStringSource != null) { if(sharedStringSource != null) {
SharedStringsTable sst = (SharedStringsTable)sharedStringSource; SharedStringsTable sst = (SharedStringsTable)sharedStringSource;
PackagePartName sstName = PackagingURIHelper.createPartName(SHARED_STRINGS.getDefaultFileName()); SHARED_STRINGS.save(sst, corePart);
corePart.addRelationship(sstName, TargetMode.INTERNAL, SHARED_STRINGS.getRelation());
PackagePart sstPart = pkg.createPart(sstName, SHARED_STRINGS.getContentType());
out = sstPart.getOutputStream();
sst.writeTo(out);
out.close();
} }
if(stylesSource != null) { if(stylesSource != null) {
StylesTable st = (StylesTable)stylesSource; StylesTable st = (StylesTable)stylesSource;
PackagePartName stName = PackagingURIHelper.createPartName(STYLES.getDefaultFileName()); STYLES.save(st, corePart);
corePart.addRelationship(stName, TargetMode.INTERNAL, STYLES.getRelation());
PackagePart stPart = pkg.createPart(stName, STYLES.getContentType());
out = stPart.getOutputStream();
st.writeTo(out);
out.close();
} }
// All done // All done

View File

@ -31,6 +31,15 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;
public class TestXSSFWorkbook extends TestCase { public class TestXSSFWorkbook extends TestCase {
public TestXSSFWorkbook(String name) {
super(name);
// Use system out logger
System.setProperty(
"org.apache.poi.util.POILogger",
"org.apache.poi.util.SystemOutLogger"
);
}
public void testGetSheetIndex() { public void testGetSheetIndex() {
XSSFWorkbook workbook = new XSSFWorkbook(); XSSFWorkbook workbook = new XSSFWorkbook();
@ -127,7 +136,7 @@ public class TestXSSFWorkbook extends TestCase {
Sheet sheet2 = workbook.createSheet("sheet2"); Sheet sheet2 = workbook.createSheet("sheet2");
Sheet sheet3 = workbook.createSheet("sheet3"); Sheet sheet3 = workbook.createSheet("sheet3");
File file = File.createTempFile("poi-", ".xlsx"); File file = File.createTempFile("poi-", ".xlsx");
System.out.println("Saving to " + file.getAbsolutePath()); System.out.println("Saving newly created file to " + file.getAbsolutePath());
OutputStream out = new FileOutputStream(file); OutputStream out = new FileOutputStream(file);
workbook.write(out); workbook.write(out);
out.close(); out.close();
@ -194,5 +203,17 @@ public class TestXSSFWorkbook extends TestCase {
assertEquals(2, st._getFillsSize()); assertEquals(2, st._getFillsSize());
// Has 1 border // Has 1 border
assertEquals(1, st._getBordersSize()); assertEquals(1, st._getBordersSize());
// Add two more styles
assertEquals(StylesTable.FIRST_CUSTOM_STYLE_ID + 8,
st.putNumberFormat("testFORMAT"));
assertEquals(StylesTable.FIRST_CUSTOM_STYLE_ID + 8,
st.putNumberFormat("testFORMAT"));
assertEquals(StylesTable.FIRST_CUSTOM_STYLE_ID + 9,
st.putNumberFormat("testFORMAT2"));
assertEquals(10, st._getNumberFormatSize());
// Save, load back in again, and check
// TODO
} }
} }