Initial support for XSSF External Links tables, which hold references to other workbooks referenced by formulas and names. #56744

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1611828 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2014-07-18 22:48:59 +00:00
parent d0db408a2f
commit 611bcffb0c
4 changed files with 280 additions and 2 deletions

View File

@ -0,0 +1,165 @@
/* ====================================================================
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.model;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.ss.usermodel.Name;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalDefinedName;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalLink;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalSheetName;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.ExternalLinkDocument;
/**
* Holds details of links to parts of other workbooks (eg named ranges),
* along with the most recently seen values for what they point to.
*/
public class ExternalLinksTable extends POIXMLDocumentPart {
private CTExternalLink link;
public ExternalLinksTable() {
super();
link = CTExternalLink.Factory.newInstance();
}
public ExternalLinksTable(PackagePart part, PackageRelationship rel) throws IOException {
super(part, rel);
readFrom(part.getInputStream());
}
public void readFrom(InputStream is) throws IOException {
try {
ExternalLinkDocument doc = ExternalLinkDocument.Factory.parse(is);
link = doc.getExternalLink();
} catch (XmlException e) {
throw new IOException(e.getLocalizedMessage());
}
}
public void writeTo(OutputStream out) throws IOException {
ExternalLinkDocument doc = ExternalLinkDocument.Factory.newInstance();
doc.setExternalLink(link);
doc.save(out, DEFAULT_XML_OPTIONS);
}
@Override
protected void commit() throws IOException {
PackagePart part = getPackagePart();
OutputStream out = part.getOutputStream();
writeTo(out);
out.close();
}
/**
* Returns the underlying xmlbeans object for the external
* link table
*/
public CTExternalLink getCTExternalLink(){
return link;
}
@SuppressWarnings("deprecation")
public List<String> getSheetNames() {
CTExternalSheetName[] sheetNames =
link.getExternalBook().getSheetNames().getSheetNameArray();
List<String> names = new ArrayList<String>(sheetNames.length);
for (CTExternalSheetName name : sheetNames) {
names.add(name.getVal());
}
return names;
}
@SuppressWarnings("deprecation")
public List<Name> getDefinedNames() {
CTExternalDefinedName[] extNames =
link.getExternalBook().getDefinedNames().getDefinedNameArray();
List<Name> names = new ArrayList<Name>(extNames.length);
for (CTExternalDefinedName extName : extNames) {
names.add(new ExternalName(extName));
}
return names;
}
// TODO Last seen data
protected class ExternalName implements Name {
private CTExternalDefinedName name;
protected ExternalName(CTExternalDefinedName name) {
this.name = name;
}
public String getNameName() {
return name.getName();
}
public void setNameName(String name) {
this.name.setName(name);
}
public String getSheetName() {
int sheetId = getSheetIndex();
if (sheetId >= 0) {
return getSheetNames().get(sheetId);
} else {
return null;
}
}
public int getSheetIndex() {
if (name.isSetSheetId()) {
return (int)name.getSheetId();
}
return -1;
}
public void setSheetIndex(int sheetId) {
name.setSheetId(sheetId);
}
public String getRefersToFormula() {
// Return, without the leading =
return name.getRefersTo().substring(1);
}
public void setRefersToFormula(String formulaText) {
// Save with leading =
name.setRefersTo('=' + formulaText);
}
public boolean isFunctionName() {
return false;
}
public boolean isDeleted() {
return false;
}
public String getComment() {
return null;
}
public void setComment(String comment) {
throw new IllegalStateException("Not Supported");
}
public void setFunction(boolean value) {
throw new IllegalStateException("Not Supported");
}
}
}

View File

@ -36,6 +36,7 @@ import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.xssf.model.CalculationChain;
import org.apache.poi.xssf.model.CommentsTable;
import org.apache.poi.xssf.model.ExternalLinksTable;
import org.apache.poi.xssf.model.MapInfo;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.model.SingleXmlCells;
@ -305,6 +306,13 @@ public final class XSSFRelation extends POIXMLRelation {
CalculationChain.class
);
public static final XSSFRelation EXTERNAL_LINKS = new XSSFRelation(
"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink",
"/xl/externalLinks/externalLink#.xmll",
ExternalLinksTable.class
);
public static final XSSFRelation PRINTER_SETTINGS = new XSSFRelation(
"application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings",
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/printerSettings",

View File

@ -63,6 +63,7 @@ import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.PackageHelper;
import org.apache.poi.xssf.model.CalculationChain;
import org.apache.poi.xssf.model.ExternalLinksTable;
import org.apache.poi.xssf.model.MapInfo;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.model.StylesTable;
@ -154,6 +155,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
* TODO
*/
private CalculationChain calcChain;
/**
* External Links, for referencing names or cells in other workbooks
*/
private ExternalLinksTable externalLinks;
/**
* A collection of custom XML mappings
@ -283,6 +289,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
else if(p instanceof StylesTable) stylesSource = (StylesTable)p;
else if(p instanceof ThemesTable) theme = (ThemesTable)p;
else if(p instanceof CalculationChain) calcChain = (CalculationChain)p;
else if(p instanceof ExternalLinksTable) externalLinks = (ExternalLinksTable)p;
else if(p instanceof MapInfo) mapInfo = (MapInfo)p;
else if (p instanceof XSSFSheet) {
shIdMap.put(p.getPackageRelationship().getId(), (XSSFSheet)p);
@ -1591,7 +1598,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
}
/**
* Return the CalculationChain object for this workbook
* Return the {@link CalculationChain} object for this workbook
* <p>
* The calculation chain object specifies the order in which the cells in a workbook were last calculated
* </p>
@ -1599,9 +1606,23 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
* @return the <code>CalculationChain</code> object or <code>null</code> if not defined
*/
@Internal
public CalculationChain getCalculationChain(){
public CalculationChain getCalculationChain() {
return calcChain;
}
/**
* Returns the {@link ExternalLinksTable} object for this workbook.
*
* <p>The external links table specifies details of named ranges etc
* that are referenced from other workbooks, along with the last seen
* values of what they point to.</p>
*
* @return the <code>ExternalLinksTable</code> object or <code>null</code> if not defined
*/
@Internal
public ExternalLinksTable getExternalLinksTable() {
return externalLinks;
}
/**
*

View File

@ -0,0 +1,84 @@
/* ====================================================================
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.model;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.apache.poi.ss.usermodel.Name;
import org.apache.poi.xssf.XSSFTestDataSamples;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.Test;
public final class TestExternalLinksTable {
@Test
public void none() {
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("SampleSS.xlsx");
assertEquals(null, wb.getExternalLinksTable());
}
@Test
public void basicRead() {
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("ref-56737.xlsx");
assertNotNull(wb.getExternalLinksTable());
Name name = null;
ExternalLinksTable links = wb.getExternalLinksTable();
assertEquals(3, links.getSheetNames().size());
assertEquals(2, links.getDefinedNames().size());
assertEquals("Uses", links.getSheetNames().get(0));
assertEquals("Defines", links.getSheetNames().get(1));
assertEquals("56737", links.getSheetNames().get(2));
name = links.getDefinedNames().get(0);
assertEquals("NR_Global_B2", name.getNameName());
assertEquals(-1, name.getSheetIndex());
assertEquals(null, name.getSheetName());
assertEquals("'Defines'!$B$2", name.getRefersToFormula());
name = links.getDefinedNames().get(1);
assertEquals("NR_To_A1", name.getNameName());
assertEquals(1, name.getSheetIndex());
assertEquals("Defines", name.getSheetName());
assertEquals("'Defines'!$A$1", name.getRefersToFormula());
}
@Test
public void basicReadWriteRead() {
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("ref-56737.xlsx");
Name name = wb.getExternalLinksTable().getDefinedNames().get(1);
name.setNameName("Testing");
name.setRefersToFormula("$A$1");
wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
ExternalLinksTable links = wb.getExternalLinksTable();
name = links.getDefinedNames().get(0);
assertEquals("NR_Global_B2", name.getNameName());
assertEquals(-1, name.getSheetIndex());
assertEquals(null, name.getSheetName());
assertEquals("'Defines'!$B$2", name.getRefersToFormula());
name = links.getDefinedNames().get(1);
assertEquals("Testing", name.getNameName());
assertEquals(1, name.getSheetIndex());
assertEquals("Defines", name.getSheetName());
assertEquals("$A$1", name.getRefersToFormula());
}
}