diff --git a/src/ooxml/java/org/apache/poi/xssf/model/ExternalLinksTable.java b/src/ooxml/java/org/apache/poi/xssf/model/ExternalLinksTable.java new file mode 100644 index 000000000..22a0de9c4 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xssf/model/ExternalLinksTable.java @@ -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 getSheetNames() { + CTExternalSheetName[] sheetNames = + link.getExternalBook().getSheetNames().getSheetNameArray(); + List names = new ArrayList(sheetNames.length); + for (CTExternalSheetName name : sheetNames) { + names.add(name.getVal()); + } + return names; + } + + @SuppressWarnings("deprecation") + public List getDefinedNames() { + CTExternalDefinedName[] extNames = + link.getExternalBook().getDefinedNames().getDefinedNameArray(); + List names = new ArrayList(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"); + } + } +} \ No newline at end of file diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java index 037c41356..70e755574 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java @@ -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", diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java index 727989c2e..f1025bce7 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java @@ -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 * The calculation chain object specifies the order in which the cells in a workbook were last calculated *

@@ -1599,9 +1606,23 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, IterableCalculationChain object or null if not defined */ @Internal - public CalculationChain getCalculationChain(){ + public CalculationChain getCalculationChain() { return calcChain; } + + /** + * Returns the {@link ExternalLinksTable} object for this workbook. + * + *

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.

+ * + * @return the ExternalLinksTable object or null if not defined + */ + @Internal + public ExternalLinksTable getExternalLinksTable() { + return externalLinks; + } /** * diff --git a/src/ooxml/testcases/org/apache/poi/xssf/model/TestExternalLinksTable.java b/src/ooxml/testcases/org/apache/poi/xssf/model/TestExternalLinksTable.java new file mode 100644 index 000000000..b2c9aff14 --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/xssf/model/TestExternalLinksTable.java @@ -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()); + } +}