refactored POIXMLDocument to be a composite of POIXMLDocumentPart, this way XSSFWorkbook is a root of a tree: XSSFSheets are children, XSSFDrawings are children of worksheets, etc,

Also, performed major cleanup of core XSSF classes and test cases

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@700472 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yegor Kozlov 2008-09-30 13:57:36 +00:00
parent 57e7f5f10f
commit baa56c4fc8
26 changed files with 2926 additions and 2160 deletions

View File

@ -29,7 +29,7 @@ public class CreateNewSpreadsheet {
CreationHelper createHelper = wb.getCreationHelper(); CreationHelper createHelper = wb.getCreationHelper();
XSSFSheet s1 = wb.createSheet("Sheet One"); XSSFSheet s1 = wb.createSheet("Sheet One");
XSSFSheet s2 = wb.createSheet("Sheet One"); XSSFSheet s2 = wb.createSheet("Sheet Two");
// Create a few cells // Create a few cells
s1.createRow(0); s1.createRow(0);

View File

@ -376,9 +376,6 @@ public interface Workbook {
Palette getCustomPalette(); Palette getCustomPalette();
/** Test only. Do not use */
void insertChartRecord();
/** /**
* Adds a picture to the workbook. * Adds a picture to the workbook.
* *
@ -392,7 +389,7 @@ public interface Workbook {
/** /**
* Gets all pictures from the Workbook. * Gets all pictures from the Workbook.
* *
* @return the list of pictures (a list of {@link HSSFPictureData} objects.) * @return the list of pictures (a list of {@link PictureData} objects.)
*/ */
List getAllPictures(); List getAllPictures();

View File

@ -16,26 +16,20 @@
==================================================================== */ ==================================================================== */
package org.apache.poi; package org.apache.poi;
import java.io.IOException; import java.io.*;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import org.apache.poi.poifs.common.POIFSConstants; import org.apache.poi.poifs.common.POIFSConstants;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.PackageHelper;
import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlException;
import org.openxml4j.exceptions.InvalidFormatException; import org.openxml4j.exceptions.InvalidFormatException;
import org.openxml4j.exceptions.OpenXML4JException; import org.openxml4j.exceptions.OpenXML4JException;
import org.openxml4j.opc.*;
import org.openxml4j.opc.Package; import org.openxml4j.opc.Package;
import org.openxml4j.opc.PackagePart;
import org.openxml4j.opc.PackagePartName;
import org.openxml4j.opc.PackageRelationship;
import org.openxml4j.opc.PackageRelationshipCollection;
import org.openxml4j.opc.PackageRelationshipTypes;
import org.openxml4j.opc.PackagingURIHelper;
public abstract class POIXMLDocument { public class POIXMLDocument extends POIXMLDocumentPart{
public static final String CORE_PROPERTIES_REL_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"; public static final String CORE_PROPERTIES_REL_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
public static final String EXTENDED_PROPERTIES_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties"; public static final String EXTENDED_PROPERTIES_REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
@ -61,27 +55,16 @@ public abstract class POIXMLDocument {
/** /**
* The embedded OLE2 files in the OPC package * The embedded OLE2 files in the OPC package
*/ */
protected List<PackagePart> embedds = new LinkedList<PackagePart>(); protected List<PackagePart> embedds;
protected POIXMLDocument() {} protected POIXMLDocument() {
super(null, null);
embedds = new LinkedList<PackagePart>();
}
protected POIXMLDocument(Package pkg) throws IOException { protected POIXMLDocument(Package pkg) throws IOException {
try { this();
this.pkg = pkg; initialize(pkg);
PackageRelationship coreDocRelationship = this.pkg.getRelationshipsByType(
PackageRelationshipTypes.CORE_DOCUMENT).getRelationship(0);
// Get core part
this.corePart = this.pkg.getPart(coreDocRelationship);
// Verify it's there
if(corePart == null) {
throw new IllegalArgumentException("No core part found for this document! Nothing with " + coreDocRelationship.getRelationshipType() + " present as a relation.");
}
} catch (OpenXML4JException e) {
throw new IOException(e.toString());
}
} }
protected POIXMLDocument(String path) throws IOException { protected POIXMLDocument(String path) throws IOException {
@ -100,15 +83,27 @@ public abstract class POIXMLDocument {
throw new IOException(e.toString()); throw new IOException(e.toString());
} }
} }
public static Package openPackage(InputStream is) throws IOException {
protected void initialize(Package pkg) throws IOException {
try { try {
return Package.open(is); this.pkg = pkg;
} catch (InvalidFormatException e) {
PackageRelationship coreDocRelationship = this.pkg.getRelationshipsByType(
PackageRelationshipTypes.CORE_DOCUMENT).getRelationship(0);
// Get core part
this.corePart = super.packagePart = this.pkg.getPart(coreDocRelationship);
// Verify it's there
if(corePart == null) {
throw new IllegalArgumentException("No core part found for this document! Nothing with " + coreDocRelationship.getRelationshipType() + " present as a relation.");
}
} catch (OpenXML4JException e) {
throw new IOException(e.toString()); throw new IOException(e.toString());
} }
} }
protected Package getPackage() { public Package getPackage() {
return this.pkg; return this.pkg;
} }

View File

@ -0,0 +1,203 @@
/* ====================================================================
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.poi;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import org.apache.xmlbeans.XmlOptions;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.POILogFactory;
import org.openxml4j.exceptions.OpenXML4JException;
import org.openxml4j.opc.*;
/**
* Represents an entry of a OOXML package.
*
* <p>
* Each POIXMLDocumentPart keeps a reference to the underlying a {@link org.openxml4j.opc.PackagePart}.
* </p>
*
* @author Yegor Kozlov
*/
public class POIXMLDocumentPart {
private static POILogger logger = POILogFactory.getLogger(POIXMLDocumentPart.class);
public static XmlOptions DEFAULT_XML_OPTIONS;
static {
DEFAULT_XML_OPTIONS = new XmlOptions();
DEFAULT_XML_OPTIONS.setSaveOuter();
DEFAULT_XML_OPTIONS.setUseDefaultNamespace();
}
protected PackagePart packagePart;
protected PackageRelationship packageRel;
protected POIXMLDocumentPart parent;
protected List<POIXMLDocumentPart> relations;
public POIXMLDocumentPart(PackagePart part, PackageRelationship rel){
relations = new LinkedList<POIXMLDocumentPart>();
this.packagePart = part;
this.packageRel = rel;
}
/**
* Provides access to the underlying PackagePart
*
* @return the underlying PackagePart
*/
public PackagePart getPackagePart(){
return packagePart;
}
/**
* Provides access to the PackageRelationship that identifies this POIXMLDocumentPart
*
* @return the PackageRelationship that identifies this POIXMLDocumentPart
*/
public PackageRelationship getPackageRelationship(){
return packageRel;
}
/**
* Returns the list of child relations for this POIXMLDocumentPart
*
* @return child relations
*/
public List<POIXMLDocumentPart> getRelations(){
return relations;
}
/**
* Add a new child POIXMLDocumentPart
*
* @param part the child to add
*/
protected void addRelation(POIXMLDocumentPart part){
relations.add(part);
}
/**
* Returns the parent POIXMLDocumentPart. All parts except root have not-null parent.
*
* @return the parent POIXMLDocumentPart or <code>null</code> for the root element.
*/
public POIXMLDocumentPart getParent(){
return parent;
}
@Override
public String toString(){
return packagePart.toString();
}
/**
* Save the content in the underlying package part.
* Default implemenation is empty meaning that the package part is left unmodified.
*
* Sub-classes should override and add logic to marshal the "model" into Ooxml4J.
*
* For example, the code saving a generic XML entry may look as follows:
* <pre><code>
* protected void commit() throws IOException {
* PackagePart part = getPackagePart();
* OutputStream out = part.getOutputStream();
* XmlObject bean = getXmlBean(); //the "model" which holds changes in memory
* bean.save(out, DEFAULT_XML_OPTIONS);
* out.close();
* </code></pre>
*
*/
protected void commit() throws IOException {
}
/**
* Save changes in the underlying OOXML package.
*/
protected void save() throws IOException{
commit();
for(POIXMLDocumentPart p : relations){
p.save();
}
}
/**
* Create a new child POIXMLDocumentPart
*
* @param descriptor the part descriptor
* @param cls the Class object identifying the type of instance to create
* @return the created child POIXMLDocumentPart
*/
protected POIXMLDocumentPart createRelationship(POIXMLRelation descriptor, Class<? extends POIXMLDocumentPart> cls){
return createRelationship(descriptor, cls, -1);
}
/**
* Create a new child POIXMLDocumentPart
*
* @param descriptor the part descriptor
* @param cls the Class object identifying the type of instance to create
* @param idx part number
* @return the created child POIXMLDocumentPart
*/
protected POIXMLDocumentPart createRelationship(POIXMLRelation descriptor, Class<? extends POIXMLDocumentPart> cls, int idx){
try {
PackagePartName ppName = PackagingURIHelper.createPartName(descriptor.getFileName(idx));
PackageRelationship rel =
packagePart.addRelationship(ppName, TargetMode.INTERNAL, descriptor.getRelation());
PackagePart part = packagePart.getPackage().createPart(ppName, descriptor.getContentType());
POIXMLDocumentPart doc = cls.newInstance();
doc.packageRel = rel;
doc.packagePart = part;
addRelation(doc);
return doc;
} catch (Exception e){
throw new POIXMLException(e);
}
}
/**
* Iterate through the underlying PackagePart and create child POIXMLFactory instances
* using the specified factory
*
* @param factory the factory object that creates POIXMLFactory instances
*/
protected void read(POIXMLFactory factory) throws OpenXML4JException {
PackageRelationshipCollection rels = packagePart.getRelationships();
for (PackageRelationship rel : rels) {
if(rel.getTargetMode() == TargetMode.INTERNAL){
PackagePartName relName = PackagingURIHelper.createPartName(rel.getTargetURI());
PackagePart p = packagePart.getPackage().getPart(relName);
if(p == null) {
logger.log(POILogger.ERROR, "Skipped invalid entry " + rel.getTargetURI());
continue;
}
POIXMLDocumentPart childPart = factory.create(rel, p);
childPart.parent = this;
addRelation(childPart);
if(p.hasRelationships()) childPart.read(factory);
}
}
}
}

View File

@ -0,0 +1,69 @@
/* ====================================================================
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.poi;
/**
* Indicates a generic OOXML error.
*
* @author Yegor Kozlov
*/
public class POIXMLException extends RuntimeException{
/**
* Create a new <code>POIXMLException</code> with no
* detail mesage.
*/
public POIXMLException() {
super();
}
/**
* Create a new <code>POIXMLException</code> with
* the <code>String</code> specified as an error message.
*
* @param msg The error message for the exception.
*/
public POIXMLException(String msg) {
super(msg);
}
/**
* Create a new <code>POIXMLException</code> with
* the <code>String</code> specified as an error message and the cause.
*
* @param msg The error message for the exception.
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A <tt>null</tt> value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
*/
public POIXMLException(String msg, Throwable cause) {
super(msg, cause);
}
/**
* Create a new <code>POIXMLException</code> with
* the specified cause.
*
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A <tt>null</tt> value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
*/
public POIXMLException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,40 @@
/* ====================================================================
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.poi;
import org.openxml4j.opc.PackageRelationship;
import org.openxml4j.opc.PackagePart;
/**
* Defines a factory API that enables sub-classes to create instances of <code>POIXMLDocumentPart</code>
*
* @author Yegor Kozlov
*/
public class POIXMLFactory {
/**
* Creates a new instance of a {@link POIXMLDocumentPart}
*
* @param rel the package part relationship
* @param part the PackagePart representing the created instance
* @return A new instance of a POIXMLDocumentPart.
*/
public POIXMLDocumentPart create(PackageRelationship rel, PackagePart part){
return new POIXMLDocumentPart(part, rel);
}
}

View File

@ -0,0 +1,54 @@
/* ====================================================================
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.poi;
/**
* Represents a descriptor of a OOXML relation.
*
* @author Yegor Kozlov
*/
public class POIXMLRelation {
protected String _type;
protected String _relation;
protected String _defaultName;
/**
* Instantiates a POIXMLRelation.
*/
protected POIXMLRelation(String type, String rel, String defaultName) {
_type = type;
_relation = rel;
_defaultName = defaultName;
}
public String getContentType() { return _type; }
public String getRelation() { return _relation; }
public String getDefaultFileName() { return _defaultName; }
/**
* Returns the filename for the nth one of these,
* eg /xl/comments4.xml
*/
public String getFileName(int index) {
if(_defaultName.indexOf("#") == -1) {
// Generic filename in all cases
return getDefaultFileName();
}
return _defaultName.replace("#", Integer.toString(index));
}
}

View File

@ -0,0 +1,150 @@
/* ====================================================================
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.poi.util;
import org.openxml4j.opc.*;
import org.openxml4j.opc.Package;
import org.openxml4j.opc.internal.PackagePropertiesPart;
import org.openxml4j.opc.internal.marshallers.PackagePropertiesMarshaller;
import org.openxml4j.exceptions.OpenXML4JException;
import org.apache.poi.util.IOUtils;
import java.io.*;
import java.util.ArrayList;
import java.lang.reflect.Method;
/**
* Provides handy methods to work with OOXML packages
*
* @author Yegor Kozlov
*/
public class PackageHelper {
/**
* Clone the specified package.
*
* @param pkg the package to clone
* @return the cloned package
*/
public static Package clone(Package pkg) throws OpenXML4JException, IOException {
return clone(pkg, createTempFile());
}
/**
* Clone the specified package.
*
* @param pkg the package to clone
* @param file the destination file
* @return the cloned package
*/
public static Package clone(Package pkg, File file) throws OpenXML4JException, IOException {
String path = file.getAbsolutePath();
Package dest = Package.create(path);
PackageRelationshipCollection rels = pkg.getRelationships();
for (PackageRelationship rel : rels) {
PackagePart part = pkg.getPart(rel);
PackagePart part_tgt;
if (rel.getRelationshipType().equals(PackageRelationshipTypes.CORE_PROPERTIES)) {
copyProperties(pkg.getPackageProperties(), dest.getPackageProperties());
continue;
} else {
dest.addRelationship(part.getPartName(), rel.getTargetMode(), rel.getRelationshipType());
part_tgt = dest.createPart(part.getPartName(), part.getContentType());
}
OutputStream out = part_tgt.getOutputStream();
IOUtils.copy(part.getInputStream(), out);
out.close();
if(part.hasRelationships()) {
copy(pkg, part, dest, part_tgt);
}
}
dest.close();
//the temp file will be deleted when JVM terminates
new File(path).deleteOnExit();
return Package.open(path);
}
/**
*
* @return
* @throws IOException
*/
public static File createTempFile() throws IOException {
File file = File.createTempFile("poi-ooxml-", ".tmp");
//there is no way to pass an existing file to Package.create(file),
//delete first, the file will be re-created in Packe.create(file)
file.delete();
file.deleteOnExit();
return file;
}
/**
* Recursively copy package parts to the destination package
*/
private static void copy(Package pkg, PackagePart part, Package tgt, PackagePart part_tgt) throws OpenXML4JException, IOException {
PackageRelationshipCollection rels = part.getRelationships();
if(rels != null) for (PackageRelationship rel : rels) {
PackagePart p;
if(rel.getTargetMode() == TargetMode.EXTERNAL){
part_tgt.addExternalRelationship(rel.getTargetURI().toString(), rel.getRelationshipType(), rel.getId());
//external relations don't have associated package parts
continue;
} else {
PackagePartName relName = PackagingURIHelper.createPartName(rel.getTargetURI());
p = pkg.getPart(relName);
}
part_tgt.addRelationship(p.getPartName(), rel.getTargetMode(), rel.getRelationshipType(), rel.getId());
PackagePart dest;
if(!tgt.containPart(p.getPartName())){
dest = tgt.createPart(p.getPartName(), p.getContentType());
OutputStream out = dest.getOutputStream();
IOUtils.copy(p.getInputStream(), out);
out.close();
copy(pkg, p, tgt, dest);
}
}
}
/**
* Copy core package properties
*
* @param src source properties
* @param tgt target properties
*/
private static void copyProperties(PackageProperties src, PackageProperties tgt){
tgt.setCategoryProperty(src.getCategoryProperty().getValue());
tgt.setContentStatusProperty(src.getContentStatusProperty().getValue());
tgt.setContentTypeProperty(src.getContentTypeProperty().getValue());
tgt.setCreatorProperty(src.getCreatorProperty().getValue());
tgt.setDescriptionProperty(src.getDescriptionProperty().getValue());
tgt.setIdentifierProperty(src.getIdentifierProperty().getValue());
tgt.setKeywordsProperty(src.getKeywordsProperty().getValue());
tgt.setLanguageProperty(src.getLanguageProperty().getValue());
tgt.setRevisionProperty(src.getRevisionProperty().getValue());
tgt.setSubjectProperty(src.getSubjectProperty().getValue());
tgt.setTitleProperty(src.getTitleProperty().getValue());
tgt.setVersionProperty(src.getVersionProperty().getValue());
}
}

View File

@ -21,10 +21,7 @@ import org.w3c.dom.Document;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import java.io.FileOutputStream; import java.io.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipFile; import java.util.zip.ZipFile;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.Enumeration; import java.util.Enumeration;
@ -70,6 +67,7 @@ public class XSSFDump {
FileOutputStream out = new FileOutputStream(f); FileOutputStream out = new FileOutputStream(f);
if(entry.getName().endsWith(".xml") || entry.getName().endsWith(".vml") || entry.getName().endsWith(".rels")){ if(entry.getName().endsWith(".xml") || entry.getName().endsWith(".vml") || entry.getName().endsWith(".rels")){
try {
//pass the xml through the Xerces serializer to produce nicely formatted output //pass the xml through the Xerces serializer to produce nicely formatted output
Document doc = builder.parse(zip.getInputStream(entry)); Document doc = builder.parse(zip.getInputStream(entry));
@ -79,15 +77,22 @@ public class XSSFDump {
XMLSerializer serial = new XMLSerializer( out, format ); XMLSerializer serial = new XMLSerializer( out, format );
serial.asDOMSerializer(); serial.asDOMSerializer();
serial.serialize( doc.getDocumentElement() ); serial.serialize( doc.getDocumentElement() );
} catch (Exception e){
System.err.println("Failed to parse " + entry.getName() + ", dumping raw content");
dump(zip.getInputStream(entry), out);
}
} else { } else {
int pos; dump(zip.getInputStream(entry), out);
byte[] chunk = new byte[2048];
InputStream is = zip.getInputStream(entry);
while((pos = is.read(chunk)) > 0) out.write(chunk, 0, pos);
} }
out.close(); out.close();
} }
} }
protected static void dump(InputStream is, OutputStream out) throws IOException{
int pos;
byte[] chunk = new byte[2048];
while((pos = is.read(chunk)) > 0) out.write(chunk, 0, pos);
}
} }

View File

@ -31,6 +31,7 @@ public class XSSFSave {
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
XSSFWorkbook wb = new XSSFWorkbook(args[i]); XSSFWorkbook wb = new XSSFWorkbook(args[i]);
System.out.println("wb.getNumberOfSheets(): " + wb.getNumberOfSheets());
int sep = args[i].lastIndexOf('.'); int sep = args[i].lastIndexOf('.');
String outfile = args[i].substring(0, sep) + "-save.xlsx"; String outfile = args[i].substring(0, sep) + "-save.xlsx";
FileOutputStream out = new FileOutputStream(outfile); FileOutputStream out = new FileOutputStream(outfile);

View File

@ -23,6 +23,7 @@ import java.io.OutputStream;
import org.apache.poi.ss.usermodel.CommentsSource; import org.apache.poi.ss.usermodel.CommentsSource;
import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.usermodel.XSSFComment; import org.apache.poi.xssf.usermodel.XSSFComment;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions; import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTAuthors; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTAuthors;
@ -30,23 +31,33 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCommentList; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCommentList;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComments; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComments;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CommentsDocument; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CommentsDocument;
import org.openxml4j.opc.PackagePart;
import org.openxml4j.opc.PackageRelationship;
public class CommentsTable implements CommentsSource, XSSFModel { public class CommentsTable extends POIXMLDocumentPart implements CommentsSource, XSSFModel {
private CTComments comments; private CTComments comments;
public CommentsTable(InputStream is) throws IOException { public CommentsTable(InputStream is) throws IOException {
super(null, null);
readFrom(is); readFrom(is);
} }
public CommentsTable() { public CommentsTable() {
super(null, null);
comments = CTComments.Factory.newInstance(); comments = CTComments.Factory.newInstance();
} }
/** /**
* For unit testing only! * For unit testing only!
*/ */
public CommentsTable(CTComments comments) { public CommentsTable(CTComments comments) {
super(null, null);
this.comments = comments; this.comments = comments;
} }
public CommentsTable(PackagePart part, PackageRelationship rel) throws IOException {
super(part, rel);
readFrom(part.getInputStream());
}
public void readFrom(InputStream is) throws IOException { public void readFrom(InputStream is) throws IOException {
try { try {
CommentsDocument doc = CommentsDocument.Factory.parse(is); CommentsDocument doc = CommentsDocument.Factory.parse(is);
@ -68,6 +79,14 @@ public class CommentsTable implements CommentsSource, XSSFModel {
doc.save(out, options); doc.save(out, options);
} }
@Override
protected void commit() throws IOException {
PackagePart part = getPackagePart();
OutputStream out = part.getOutputStream();
writeTo(out);
out.close();
}
public int getNumberOfComments() { public int getNumberOfComments() {
return comments.getCommentList().sizeOfCommentArray(); return comments.getCommentList().sizeOfCommentArray();
} }

View File

@ -27,9 +27,13 @@ import java.util.Map;
import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions; import org.apache.xmlbeans.XmlOptions;
import org.apache.poi.POIXMLDocumentPart;
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;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
import org.openxml4j.opc.PackagePart;
import org.openxml4j.opc.PackageRelationship;
/** /**
@ -56,7 +60,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.SstDocument;
* @author Nick Birch * @author Nick Birch
* @author Yegor Kozlov * @author Yegor Kozlov
*/ */
public class SharedStringsTable implements SharedStringSource, XSSFModel { public class SharedStringsTable extends POIXMLDocumentPart implements XSSFModel, SharedStringSource {
/** /**
* Array of individual string items in the Shared String table. * Array of individual string items in the Shared String table.
@ -89,13 +93,17 @@ public class SharedStringsTable implements SharedStringSource, XSSFModel {
* @throws IOException if an error occurs while reading. * @throws IOException if an error occurs while reading.
*/ */
public SharedStringsTable(InputStream is) throws IOException { public SharedStringsTable(InputStream is) throws IOException {
super(null, null);
readFrom(is); readFrom(is);
} }
/**
* Create a new, empty SharedStringsTable
*/
public SharedStringsTable() { public SharedStringsTable() {
count = uniqueCount = 0; super(null, null);
}
public SharedStringsTable(PackagePart part, PackageRelationship rel) throws IOException {
super(part, rel);
readFrom(part.getInputStream());
} }
/** /**
@ -204,4 +212,12 @@ public class SharedStringsTable implements SharedStringSource, XSSFModel {
sst.setSiArray(ctr); sst.setSiArray(ctr);
doc.save(out, options); doc.save(out, options);
} }
@Override
protected void commit() throws IOException {
PackagePart part = getPackagePart();
OutputStream out = part.getOutputStream();
writeTo(out);
out.close();
}
} }

View File

@ -36,6 +36,7 @@ import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFFont; import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.extensions.XSSFCellBorder; import org.apache.poi.xssf.usermodel.extensions.XSSFCellBorder;
import org.apache.poi.xssf.usermodel.extensions.XSSFCellFill; import org.apache.poi.xssf.usermodel.extensions.XSSFCellFill;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlOptions; import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBorder; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBorder;
@ -54,13 +55,16 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTStylesheet;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXf; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXf;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPatternType; import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPatternType;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.StyleSheetDocument; import org.openxmlformats.schemas.spreadsheetml.x2006.main.StyleSheetDocument;
import org.openxml4j.opc.PackagePart;
import org.openxml4j.opc.PackageRelationship;
/** /**
* Table of styles shared across all sheets in a workbook. * Table of styles shared across all sheets in a workbook.
* *
* @author ugo * @author ugo
*/ */
public class StylesTable implements StylesSource, XSSFModel { public class StylesTable extends POIXMLDocumentPart implements StylesSource, XSSFModel {
private final Hashtable<Long,String> numberFormats = new Hashtable<Long,String>(); private final Hashtable<Long,String> numberFormats = new Hashtable<Long,String>();
private final List<CTFont> fonts = new ArrayList<CTFont>(); private final List<CTFont> fonts = new ArrayList<CTFont>();
private final List<CTFill> fills = new LinkedList<CTFill>(); private final List<CTFill> fills = new LinkedList<CTFill>();
@ -85,18 +89,25 @@ public class StylesTable implements StylesSource, XSSFModel {
* @throws IOException if an error occurs while reading. * @throws IOException if an error occurs while reading.
*/ */
public StylesTable(InputStream is) throws IOException { public StylesTable(InputStream is) throws IOException {
super(null, null);
readFrom(is); readFrom(is);
} }
/** /**
* Create a new, empty StylesTable * Create a new, empty StylesTable
*/ */
public StylesTable() { public StylesTable() {
super(null, null);
doc = StyleSheetDocument.Factory.newInstance(); doc = StyleSheetDocument.Factory.newInstance();
doc.addNewStyleSheet(); doc.addNewStyleSheet();
// Initialization required in order to make the document readable by MSExcel // Initialization required in order to make the document readable by MSExcel
initialize(); initialize();
} }
public StylesTable(PackagePart part, PackageRelationship rel) throws IOException {
super(part, rel);
readFrom(part.getInputStream());
}
/** /**
* Read this shared styles table from an XML file. * Read this shared styles table from an XML file.
* *
@ -365,6 +376,14 @@ public class StylesTable implements StylesSource, XSSFModel {
doc.save(out, options); doc.save(out, options);
} }
@Override
protected void commit() throws IOException {
PackagePart part = getPackagePart();
OutputStream out = part.getOutputStream();
writeTo(out);
out.close();
}
private long putBorder(XSSFCellBorder border, List<CTBorder> borders) { private long putBorder(XSSFCellBorder border, List<CTBorder> borders) {
return border.putBorder((LinkedList<CTBorder>) borders); // TODO - use List instead of LinkedList return border.putBorder((LinkedList<CTBorder>) borders); // TODO - use List instead of LinkedList
} }

View File

@ -23,26 +23,22 @@ import org.apache.poi.ss.usermodel.RichTextString;
public class XSSFCreationHelper implements CreationHelper { public class XSSFCreationHelper implements CreationHelper {
private XSSFWorkbook workbook; private XSSFWorkbook workbook;
private XSSFDataFormat dataFormat;
XSSFCreationHelper(XSSFWorkbook wb) { XSSFCreationHelper(XSSFWorkbook wb) {
workbook = wb; workbook = wb;
// Create the things we only ever need one of
dataFormat = new XSSFDataFormat(workbook.getStylesSource());
} }
/** /**
* Creates a new XSSFRichTextString for you. * Creates a new XSSFRichTextString for you.
*/ */
public RichTextString createRichTextString(String text) { public XSSFRichTextString createRichTextString(String text) {
return new XSSFRichTextString(text); return new XSSFRichTextString(text);
} }
public DataFormat createDataFormat() { public XSSFDataFormat createDataFormat() {
return dataFormat; return workbook.createDataFormat();
} }
public Hyperlink createHyperlink(int type) { public XSSFHyperlink createHyperlink(int type) {
return new XSSFHyperlink(type); return new XSSFHyperlink(type);
} }
} }

View File

@ -0,0 +1,57 @@
/* ====================================================================
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.poi.xssf.usermodel;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLFactory;
import org.apache.poi.POIXMLException;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.model.CommentsTable;
import org.openxml4j.opc.PackageRelationship;
import org.openxml4j.opc.PackagePart;
import java.util.Map;
import java.util.HashMap;
import java.lang.reflect.Constructor;
/**
* Instantiates sub-classes of POIXMLDocumentPart depending on their relationship type
*
* @author Yegor Kozlov
*/
public class XSSFFactory extends POIXMLFactory {
protected static Map<String, Class> parts = new HashMap<String, Class>();
static {
parts.put(XSSFRelation.WORKSHEET.getRelation(), XSSFSheet.class);
parts.put(XSSFRelation.SHARED_STRINGS.getRelation(), SharedStringsTable.class);
parts.put(XSSFRelation.STYLES.getRelation(), StylesTable.class);
parts.put(XSSFRelation.SHEET_COMMENTS.getRelation(), CommentsTable.class);
}
public POIXMLDocumentPart create(PackageRelationship rel, PackagePart p){
Class cls = parts.get(rel.getRelationshipType());
if(cls == null) return super.create(rel, p);
try {
Constructor<? extends POIXMLDocumentPart> constructor = cls.getConstructor(PackagePart.class, PackageRelationship.class);
return constructor.newInstance(p, rel);
} catch (Exception e){
throw new POIXMLException(e);
}
}
}

View File

@ -26,6 +26,7 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import org.apache.poi.POIXMLDocument; import org.apache.poi.POIXMLDocument;
import org.apache.poi.POIXMLRelation;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
import org.apache.poi.xssf.model.BinaryPart; import org.apache.poi.xssf.model.BinaryPart;
@ -49,7 +50,7 @@ import org.openxml4j.opc.TargetMode;
/** /**
* *
*/ */
public final class XSSFRelation<W extends XSSFModel> { public final class XSSFRelation<W extends XSSFModel> extends POIXMLRelation {
public static final XSSFRelation WORKBOOK = new XSSFRelation( public static final XSSFRelation WORKBOOK = new XSSFRelation(
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
@ -156,16 +157,12 @@ public final class XSSFRelation<W extends XSSFModel> {
return new XSSFRelation<R>(type, rel, defaultName, cls); return new XSSFRelation<R>(type, rel, defaultName, cls);
} }
private String _type;
private String _relation;
private String _defaultName;
private Constructor<W> _constructor; private Constructor<W> _constructor;
private final boolean _constructorTakesTwoArgs; private final boolean _constructorTakesTwoArgs;
private XSSFRelation(String type, String rel, String defaultName, Class<W> cls) { private XSSFRelation(String type, String rel, String defaultName, Class<W> cls) {
_type = type; super(type, rel, defaultName);
_relation = rel;
_defaultName = defaultName;
if (cls == null) { if (cls == null) {
_constructor = null; _constructor = null;
_constructorTakesTwoArgs = false; _constructorTakesTwoArgs = false;
@ -189,9 +186,6 @@ public final class XSSFRelation<W extends XSSFModel> {
_constructorTakesTwoArgs = twoArg; _constructorTakesTwoArgs = twoArg;
} }
} }
public String getContentType() { return _type; }
public String getRelation() { return _relation; }
public String getDefaultFileName() { return _defaultName; }
/** /**
* Does one of these exist for the given core * Does one of these exist for the given core

View File

@ -24,6 +24,7 @@ import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import javax.xml.namespace.QName;
import org.apache.poi.hssf.util.PaneInformation; import org.apache.poi.hssf.util.PaneInformation;
import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.CellStyle;
@ -41,53 +42,32 @@ import org.apache.poi.xssf.model.CommentsTable;
import org.apache.poi.xssf.model.Control; import org.apache.poi.xssf.model.Control;
import org.apache.poi.xssf.model.Drawing; import org.apache.poi.xssf.model.Drawing;
import org.apache.poi.xssf.usermodel.helpers.ColumnHelper; import org.apache.poi.xssf.usermodel.helpers.ColumnHelper;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.POIXMLException;
import org.apache.xmlbeans.XmlOptions; import org.apache.xmlbeans.XmlOptions;
import org.apache.xmlbeans.XmlException;
import org.openxml4j.opc.PackagePart; import org.openxml4j.opc.PackagePart;
import org.openxml4j.opc.PackageRelationship; import org.openxml4j.opc.PackageRelationship;
import org.openxml4j.opc.PackageRelationshipCollection; import org.openxml4j.opc.PackageRelationshipCollection;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBreak; import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDialogsheet;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHeaderFooter;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHyperlink;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCell;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCells;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOutlinePr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageBreak;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageMargins;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageSetUpPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPane;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPrintOptions;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSelection;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetFormatPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetProtection;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetView;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetViews;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane;
/** /**
* High level representation of a worksheet. * High level representation of a SpreadsheetML worksheet.
* *
* <p> * <p>
* Sheets are the central structures within a workbook, and are where a user does most of his spreadsheet work. * Sheets are the central structures within a workbook, and are where a user does most of his spreadsheet work.
* The most common type of sheet is the worksheet, which is represented as a grid of cells. Worksheet cells can * The most common type of sheet is the worksheet, which is represented as a grid of cells. Worksheet cells can
* contain text, numbers, dates, and formulas. Cells can also be formatted. A workbook usually contains more than one sheet. * contain text, numbers, dates, and formulas. Cells can also be formatted.
* </p> * </p>
*/ */
public class XSSFSheet implements Sheet { public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
protected CTSheet sheet; protected CTSheet sheet;
protected CTWorksheet worksheet; protected CTWorksheet worksheet;
protected CTDialogsheet dialogsheet; protected CTDialogsheet dialogsheet;
protected List<Row> rows; protected List<Row> rows;
protected List<XSSFHyperlink> hyperlinks; protected List<XSSFHyperlink> hyperlinks;
protected ColumnHelper columnHelper; protected ColumnHelper columnHelper;
protected XSSFWorkbook workbook;
protected CommentsSource sheetComments; protected CommentsSource sheetComments;
protected CTMergeCells ctMergeCells; protected CTMergeCells ctMergeCells;
@ -103,44 +83,35 @@ public class XSSFSheet implements Sheet {
public static final short HeaderMargin = 4; public static final short HeaderMargin = 4;
public static final short FooterMargin = 5; public static final short FooterMargin = 5;
public XSSFSheet(CTSheet sheet, CTWorksheet worksheet, XSSFWorkbook workbook, CommentsSource sheetComments, List<Drawing> drawings, List<Control> controls) {
this(sheet, worksheet, workbook, sheetComments); public XSSFSheet() {
this.drawings = drawings; super(null, null);
this.controls = controls; this.worksheet = newSheet();
initialize();
} }
public List<Drawing> getDrawings() public XSSFSheet(PackagePart part, PackageRelationship rel) throws IOException, XmlException {
{ super(part, rel);
return drawings; worksheet = WorksheetDocument.Factory.parse(part.getInputStream()).getWorksheet();
}
public List<Control> getControls()
{
return controls;
} }
public XSSFSheet(CTSheet sheet, CTWorksheet worksheet, XSSFWorkbook workbook, CommentsSource sheetComments) { public XSSFSheet(CTSheet sheet, CTWorksheet worksheet, XSSFWorkbook workbook, CommentsSource sheetComments) {
this(sheet, worksheet, workbook); super(null, null);
this.parent = workbook;
this.sheet = sheet;
this.worksheet = worksheet;
this.sheetComments = sheetComments; this.sheetComments = sheetComments;
initialize();
} }
public XSSFSheet(CTSheet sheet, CTWorksheet worksheet, XSSFWorkbook workbook) { public XSSFSheet(CTSheet sheet, CTWorksheet worksheet, XSSFWorkbook workbook) {
this.workbook = workbook; this(sheet, worksheet, workbook, null);
this.sheet = sheet;
this.worksheet = worksheet;
if (this.worksheet.getSheetData() == null) {
this.worksheet.addNewSheetData();
}
initRows(this.worksheet);
initColumns(this.worksheet);
hyperlinks = new ArrayList<XSSFHyperlink>();
} }
protected XSSFSheet(XSSFWorkbook workbook) { protected XSSFSheet(XSSFWorkbook workbook) {
this.workbook = workbook; super(null, null);
this.parent = workbook;
hyperlinks = new ArrayList<XSSFHyperlink>(); hyperlinks = new ArrayList<XSSFHyperlink>();
} }
@ -151,7 +122,20 @@ public class XSSFSheet implements Sheet {
* @return the parent XSSFWorkbook * @return the parent XSSFWorkbook
*/ */
public XSSFWorkbook getWorkbook() { public XSSFWorkbook getWorkbook() {
return this.workbook; return (XSSFWorkbook)getParent();
}
protected void initialize(){
if (this.worksheet.getSheetData() == null) {
this.worksheet.addNewSheetData();
}
initRows(this.worksheet);
initColumns(this.worksheet);
for(POIXMLDocumentPart p : getRelations()){
if(p instanceof CommentsTable) sheetComments = (CommentsTable)p;
}
hyperlinks = new ArrayList<XSSFHyperlink>();
} }
/** /**
@ -159,7 +143,7 @@ public class XSSFSheet implements Sheet {
* *
* @return a new instance * @return a new instance
*/ */
protected static CTWorksheet newInstance(){ protected static CTWorksheet newSheet(){
CTWorksheet worksheet = CTWorksheet.Factory.newInstance(); CTWorksheet worksheet = CTWorksheet.Factory.newInstance();
CTSheetFormatPr ctFormat = worksheet.addNewSheetFormatPr(); CTSheetFormatPr ctFormat = worksheet.addNewSheetFormatPr();
ctFormat.setDefaultRowHeight(15.0); ctFormat.setDefaultRowHeight(15.0);
@ -183,41 +167,14 @@ public class XSSFSheet implements Sheet {
return worksheet; return worksheet;
} }
/** public List<Drawing> getDrawings()
* Tweaks the CTWorksheet to fit with what Excel {
* will accept without a massive huff, and write into return drawings;
* the OutputStream supplied.
*/
protected void save(PackagePart sheetPart, XmlOptions xmlOptions) throws IOException {
// Excel objects to <cols/>
if(worksheet.getColsArray().length == 1) {
CTCols col = worksheet.getColsArray(0);
if(col.getColArray().length == 0) {
worksheet.setColsArray(null);
}
} }
// Now re-generate our CTHyperlinks, if needed public List<Control> getControls()
if(hyperlinks.size() > 0) { {
if(worksheet.getHyperlinks() == null) { return controls;
worksheet.addNewHyperlinks();
}
CTHyperlink[] ctHls = new CTHyperlink[hyperlinks.size()];
for(int i=0; i<ctHls.length; i++) {
// If our sheet has hyperlinks, have them add
// any relationships that they might need
XSSFHyperlink hyperlink = hyperlinks.get(i);
hyperlink.generateRelationIfNeeded(sheetPart);
// Now grab their underling object
ctHls[i] = hyperlink.getCTHyperlink();
}
worksheet.getHyperlinks().setHyperlinkArray(ctHls);
}
// Save
OutputStream out = sheetPart.getOutputStream();
worksheet.save(out, xmlOptions);
out.close();
} }
/** /**
@ -407,7 +364,8 @@ public class XSSFSheet implements Sheet {
} }
public XSSFComment getCellComment(int row, int column) { public XSSFComment getCellComment(int row, int column) {
return (XSSFComment)getComments().findCellComment(row, column); if (sheetComments == null) return null;
else return (XSSFComment)getComments().findCellComment(row, column);
} }
public XSSFHyperlink getHyperlink(int row, int column) { public XSSFHyperlink getHyperlink(int row, int column) {
@ -646,7 +604,7 @@ public class XSSFSheet implements Sheet {
case FooterMargin: case FooterMargin:
return pageMargins.getFooter(); return pageMargins.getFooter();
default : default :
throw new RuntimeException( "Unknown margin constant: " + margin ); throw new POIXMLException( "Unknown margin constant: " + margin );
} }
} }
@ -1509,7 +1467,7 @@ public class XSSFSheet implements Sheet {
} }
protected XSSFSheet cloneSheet() { protected XSSFSheet cloneSheet() {
XSSFSheet newSheet = new XSSFSheet(this.workbook); XSSFSheet newSheet = new XSSFSheet(getWorkbook());
newSheet.setSheet((CTSheet)sheet.copy()); newSheet.setSheet((CTSheet)sheet.copy());
return newSheet; return newSheet;
} }
@ -1520,7 +1478,7 @@ public class XSSFSheet implements Sheet {
private CommentsSource getComments() { private CommentsSource getComments() {
if (sheetComments == null) { if (sheetComments == null) {
sheetComments = new CommentsTable(); sheetComments = (CommentsTable)createRelationship(XSSFRelation.SHEET_COMMENTS, CommentsTable.class, (int)sheet.getSheetId());
} }
return sheetComments; return sheetComments;
} }
@ -1568,4 +1526,44 @@ public class XSSFSheet implements Sheet {
} }
return getDefaultSheetView().getPane(); return getDefaultSheetView().getPane();
} }
@Override
protected void commit() throws IOException {
if(worksheet.getColsArray().length == 1) {
CTCols col = worksheet.getColsArray(0);
if(col.getColArray().length == 0) {
worksheet.setColsArray(null);
}
}
// Now re-generate our CTHyperlinks, if needed
if(hyperlinks.size() > 0) {
if(worksheet.getHyperlinks() == null) {
worksheet.addNewHyperlinks();
}
CTHyperlink[] ctHls = new CTHyperlink[hyperlinks.size()];
for(int i=0; i<ctHls.length; i++) {
// If our sheet has hyperlinks, have them add
// any relationships that they might need
XSSFHyperlink hyperlink = hyperlinks.get(i);
hyperlink.generateRelationIfNeeded(getPackagePart());
// Now grab their underling object
ctHls[i] = hyperlink.getCTHyperlink();
}
worksheet.getHyperlinks().setHyperlinkArray(ctHls);
}
XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
xmlOptions.setSaveSyntheticDocumentElement(new QName(CTWorksheet.type.getName().getNamespaceURI(), "worksheet"));
PackagePart part = getPackagePart();
OutputStream out = part.getOutputStream();
worksheet.save(out, xmlOptions);
out.close();
}
protected void setParent(POIXMLDocumentPart p){
this.parent = p;
}
} }

View File

@ -75,10 +75,22 @@ public class XSSFCellBorder {
private CTBorderPr getBorder(BorderSide side) { private CTBorderPr getBorder(BorderSide side) {
switch (side) { switch (side) {
case TOP: return border.getTop(); case TOP: {
case RIGHT: return border.getRight(); CTBorderPr borderPr = border.isSetTop() ? border.getTop() : border.addNewTop();
case BOTTOM: return border.getBottom(); return borderPr;
case LEFT: return border.getLeft(); }
case RIGHT: {
CTBorderPr borderPr = border.isSetRight() ? border.getRight() : border.addNewRight();
return borderPr;
}
case BOTTOM:{
CTBorderPr borderPr = border.isSetBottom() ? border.getBottom() : border.addNewBottom();
return borderPr;
}
case LEFT:{
CTBorderPr borderPr = border.isSetLeft() ? border.getLeft() : border.addNewLeft();
return borderPr;
}
default: throw new IllegalArgumentException("No suitable side specified for the border"); default: throw new IllegalArgumentException("No suitable side specified for the border");
} }
} }

View File

@ -17,10 +17,7 @@
package org.apache.poi.xssf; package org.apache.poi.xssf;
import java.io.ByteArrayInputStream; import java.io.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.poi.hssf.HSSFTestDataSamples; import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
@ -47,15 +44,20 @@ public class XSSFTestDataSamples {
} }
} }
public static <R extends Workbook> R writeOutAndReadBack(R wb) { public static <R extends Workbook> R writeOutAndReadBack(R wb) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);
Workbook result; Workbook result;
try { try {
if (wb instanceof HSSFWorkbook) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);
wb.write(baos); wb.write(baos);
InputStream is = new ByteArrayInputStream(baos.toByteArray()); InputStream is = new ByteArrayInputStream(baos.toByteArray());
if (wb instanceof HSSFWorkbook) {
result = new HSSFWorkbook(is); result = new HSSFWorkbook(is);
} else if (wb instanceof XSSFWorkbook) { } else if (wb instanceof XSSFWorkbook) {
Package pkg = Package.open(is); File tmp = File.createTempFile("poi-ooxml-", ".xlsx");
tmp.deleteOnExit();
FileOutputStream out = new FileOutputStream(tmp);
wb.write(out);
out.close();
Package pkg = Package.open(tmp.getAbsolutePath());
result = new XSSFWorkbook(pkg); result = new XSSFWorkbook(pkg);
} else { } else {
throw new RuntimeException("Unexpected workbook type (" throw new RuntimeException("Unexpected workbook type ("

View File

@ -30,6 +30,7 @@ import org.apache.poi.xssf.usermodel.XSSFComment;
import org.apache.poi.xssf.usermodel.XSSFRichTextString; import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.XSSFTestDataSamples;
import org.openxml4j.opc.Package; import org.openxml4j.opc.Package;
import org.openxml4j.opc.PackagePart; import org.openxml4j.opc.PackagePart;
import org.openxml4j.opc.PackagingURIHelper; import org.openxml4j.opc.PackagingURIHelper;
@ -212,11 +213,7 @@ public class TestCommentsTable extends TestCase {
// Save, and re-load the file // Save, and re-load the file
ByteArrayOutputStream baos = new ByteArrayOutputStream(); workbook = XSSFTestDataSamples.writeOutAndReadBack(workbook);
workbook.write(baos);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
workbook = new XSSFWorkbook(Package.open(bais));
// Check we still have comments where we should do // Check we still have comments where we should do
sheet1 = workbook.getSheetAt(0); sheet1 = workbook.getSheetAt(0);
@ -259,11 +256,7 @@ public class TestCommentsTable extends TestCase {
sheet1.getRow(12).getCell(2).getCellComment().getAuthor()); sheet1.getRow(12).getCell(2).getCellComment().getAuthor());
// Save, and re-load the file // Save, and re-load the file
ByteArrayOutputStream baos = new ByteArrayOutputStream(); workbook = XSSFTestDataSamples.writeOutAndReadBack(workbook);
workbook.write(baos);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
workbook = new XSSFWorkbook(Package.open(bais));
// Check we still have comments where we should do // Check we still have comments where we should do
sheet1 = workbook.getSheetAt(0); sheet1 = workbook.getSheetAt(0);

View File

@ -17,16 +17,14 @@
package org.apache.poi.xssf.usermodel; package org.apache.poi.xssf.usermodel;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.openxml4j.opc.Package; import org.openxml4j.opc.Package;
import org.openxml4j.opc.PackagePart; import org.openxml4j.opc.PackagePart;
import org.openxml4j.opc.PackagingURIHelper; import org.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.xssf.XSSFTestDataSamples;
public class TestXSSFBugs extends TestCase { public class TestXSSFBugs extends TestCase {
private String getFilePath(String file) { private String getFilePath(String file) {
@ -39,16 +37,6 @@ public class TestXSSFBugs extends TestCase {
return xml.toString(); return xml.toString();
} }
private Package saveAndOpen(XSSFWorkbook wb) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
wb.write(baos);
ByteArrayInputStream inp = new ByteArrayInputStream(
baos.toByteArray()
);
Package pkg = Package.open(inp);
return pkg;
}
/** /**
* Named ranges had the right reference, but * Named ranges had the right reference, but
* the wrong sheet name * the wrong sheet name
@ -74,8 +62,7 @@ public class TestXSSFBugs extends TestCase {
assertEquals("SheetC", wb.getNameAt(2).getSheetName()); assertEquals("SheetC", wb.getNameAt(2).getSheetName());
// Save and re-load, still there // Save and re-load, still there
Package nPkg = saveAndOpen(wb); XSSFWorkbook nwb = XSSFTestDataSamples.writeOutAndReadBack(wb);
XSSFWorkbook nwb = new XSSFWorkbook(nPkg);
assertEquals(3, nwb.getNumberOfNames()); assertEquals(3, nwb.getNumberOfNames());
assertEquals("SheetA!$A$1", nwb.getNameAt(0).getReference()); assertEquals("SheetA!$A$1", nwb.getNameAt(0).getReference());
} }
@ -101,8 +88,8 @@ public class TestXSSFBugs extends TestCase {
// Save and re-open, both still there // Save and re-open, both still there
Package nPkg = saveAndOpen(wb); XSSFWorkbook nwb = XSSFTestDataSamples.writeOutAndReadBack(wb);
XSSFWorkbook nwb = new XSSFWorkbook(nPkg); Package nPkg = nwb.getPackage();
assertTrue(nwb.isMacroEnabled()); assertTrue(nwb.isMacroEnabled());
vba = nPkg.getPart( vba = nPkg.getPart(
@ -115,8 +102,8 @@ public class TestXSSFBugs extends TestCase {
assertNotNull(drw); assertNotNull(drw);
// And again, just to be sure // And again, just to be sure
nPkg = saveAndOpen(nwb); nwb = XSSFTestDataSamples.writeOutAndReadBack(nwb);
nwb = new XSSFWorkbook(nPkg); nPkg = nwb.getPackage();
assertTrue(nwb.isMacroEnabled()); assertTrue(nwb.isMacroEnabled());
vba = nPkg.getPart( vba = nPkg.getPart(

View File

@ -17,9 +17,6 @@
package org.apache.poi.xssf.usermodel; package org.apache.poi.xssf.usermodel;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import org.apache.poi.hssf.usermodel.HSSFRichTextString; import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Comment; import org.apache.poi.ss.usermodel.Comment;
@ -27,6 +24,7 @@ import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.model.CommentsTable; import org.apache.poi.xssf.model.CommentsTable;
import org.apache.poi.xssf.XSSFTestDataSamples;
import org.openxml4j.opc.Package; import org.openxml4j.opc.Package;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTAuthors; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTAuthors;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment;
@ -135,7 +133,7 @@ public class TestXSSFComment extends TestCase {
*/ */
public void testCreateSave() throws Exception { public void testCreateSave() throws Exception {
XSSFWorkbook wb = new XSSFWorkbook(); XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet s1 = (XSSFSheet)wb.createSheet(); XSSFSheet s1 = wb.createSheet();
Row r1 = s1.createRow(0); Row r1 = s1.createRow(0);
Cell r1c1 = r1.createCell(0); Cell r1c1 = r1.createCell(0);
r1c1.setCellValue(2.2); r1c1.setCellValue(2.2);
@ -150,12 +148,8 @@ public class TestXSSFComment extends TestCase {
assertEquals(1, s1.getNumberOfComments()); assertEquals(1, s1.getNumberOfComments());
// Save and re-load // Save and re-load
ByteArrayOutputStream baos = new ByteArrayOutputStream(); wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
wb.write(baos); s1 = wb.getSheetAt(0);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
wb = new XSSFWorkbook(Package.open(bais));
s1 = (XSSFSheet)wb.getSheetAt(0);
assertEquals(1, s1.getNumberOfComments()); assertEquals(1, s1.getNumberOfComments());
assertNotNull(s1.getRow(0).getCell(0).getCellComment()); assertNotNull(s1.getRow(0).getCell(0).getCellComment());
@ -171,12 +165,9 @@ public class TestXSSFComment extends TestCase {
assertEquals(2, s1.getNumberOfComments()); assertEquals(2, s1.getNumberOfComments());
// Save and re-load // Save and re-load
baos = new ByteArrayOutputStream();
wb.write(baos);
bais = new ByteArrayInputStream(baos.toByteArray());
wb = new XSSFWorkbook(Package.open(bais)); wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
s1 = (XSSFSheet)wb.getSheetAt(0); s1 = wb.getSheetAt(0);
assertEquals(2, s1.getNumberOfComments()); assertEquals(2, s1.getNumberOfComments());
assertNotNull(s1.getCellComment(0, 0)); assertNotNull(s1.getCellComment(0, 0));

View File

@ -17,8 +17,6 @@
package org.apache.poi.xssf.usermodel; package org.apache.poi.xssf.usermodel;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import junit.framework.TestCase; import junit.framework.TestCase;
@ -27,6 +25,7 @@ import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CreationHelper; import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Hyperlink; import org.apache.poi.ss.usermodel.Hyperlink;
import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.xssf.XSSFTestDataSamples;
import org.openxml4j.opc.Package; import org.openxml4j.opc.Package;
public class TestXSSFHyperlink extends TestCase { public class TestXSSFHyperlink extends TestCase {
@ -79,12 +78,9 @@ public class TestXSSFHyperlink extends TestCase {
// Write out, and check // Write out, and check
ByteArrayOutputStream baos = new ByteArrayOutputStream();
workbook.write(baos);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
// Load up again, check all links still there // Load up again, check all links still there
XSSFWorkbook wb2 = new XSSFWorkbook(Package.open(bais)); XSSFWorkbook wb2 = XSSFTestDataSamples.writeOutAndReadBack(workbook);
assertEquals(3, wb2.getNumberOfSheets()); assertEquals(3, wb2.getNumberOfSheets());
assertNotNull(wb2.getSheetAt(0)); assertNotNull(wb2.getSheetAt(0));
assertNotNull(wb2.getSheetAt(1)); assertNotNull(wb2.getSheetAt(1));
@ -119,18 +115,14 @@ public class TestXSSFHyperlink extends TestCase {
// Save and re-load once more // Save and re-load once more
baos = new ByteArrayOutputStream();
wb2.write(baos);
bais = new ByteArrayInputStream(baos.toByteArray());
XSSFWorkbook wb3 = XSSFTestDataSamples.writeOutAndReadBack(wb2);
XSSFWorkbook wb3 = new XSSFWorkbook(Package.open(bais));
assertEquals(3, wb3.getNumberOfSheets()); assertEquals(3, wb3.getNumberOfSheets());
assertNotNull(wb3.getSheetAt(0)); assertNotNull(wb3.getSheetAt(0));
assertNotNull(wb3.getSheetAt(1)); assertNotNull(wb3.getSheetAt(1));
assertNotNull(wb3.getSheetAt(2)); assertNotNull(wb3.getSheetAt(2));
sheet = (XSSFSheet)wb3.getSheetAt(0); sheet = wb3.getSheetAt(0);
assertEquals(5, sheet.getNumHyperlinks()); assertEquals(5, sheet.getNumHyperlinks());
doTestHyperlinkContents(sheet); doTestHyperlinkContents(sheet);

View File

@ -17,8 +17,6 @@
package org.apache.poi.xssf.usermodel; package org.apache.poi.xssf.usermodel;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.util.Iterator; import java.util.Iterator;
import junit.framework.TestCase; import junit.framework.TestCase;
@ -30,11 +28,7 @@ import org.apache.poi.ss.util.Region;
import org.apache.poi.xssf.model.CommentsTable; import org.apache.poi.xssf.model.CommentsTable;
import org.apache.poi.xssf.model.StylesTable; import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.helpers.ColumnHelper; import org.apache.poi.xssf.usermodel.helpers.ColumnHelper;
import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.xssf.XSSFTestDataSamples;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.openxml4j.opc.Package;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment;
@ -349,11 +343,7 @@ public class TestXSSFSheet extends TestCase {
// Save and reload // Save and reload
ByteArrayOutputStream baos = new ByteArrayOutputStream(); XSSFWorkbook wb = XSSFTestDataSamples.writeOutAndReadBack(workbook);
workbook.write(baos);
XSSFWorkbook wb = new XSSFWorkbook(Package.open(
new ByteArrayInputStream(baos.toByteArray())
));
hdr = (XSSFOddHeader)wb.getSheetAt(0).getHeader(); hdr = (XSSFOddHeader)wb.getSheetAt(0).getHeader();
ftr = (XSSFOddFooter)wb.getSheetAt(0).getFooter(); ftr = (XSSFOddFooter)wb.getSheetAt(0).getFooter();