mirror of https://github.com/apache/poi.git
There can be more than one linked ExternalLinks table for a workbook #56744
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1611890 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
8d0b9df2ac
commit
03a1b6e3f6
|
@ -99,4 +99,9 @@ public interface PackageRelationshipTypes {
|
||||||
* Style type.
|
* Style type.
|
||||||
*/
|
*/
|
||||||
String STYLE_PART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
|
String STYLE_PART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* External Link to another Document
|
||||||
|
*/
|
||||||
|
String EXTERNAL_LINK_PATH = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath";
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,8 @@ import java.util.List;
|
||||||
import org.apache.poi.POIXMLDocumentPart;
|
import org.apache.poi.POIXMLDocumentPart;
|
||||||
import org.apache.poi.openxml4j.opc.PackagePart;
|
import org.apache.poi.openxml4j.opc.PackagePart;
|
||||||
import org.apache.poi.openxml4j.opc.PackageRelationship;
|
import org.apache.poi.openxml4j.opc.PackageRelationship;
|
||||||
|
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
|
||||||
|
import org.apache.poi.openxml4j.opc.TargetMode;
|
||||||
import org.apache.poi.ss.usermodel.Name;
|
import org.apache.poi.ss.usermodel.Name;
|
||||||
import org.apache.xmlbeans.XmlException;
|
import org.apache.xmlbeans.XmlException;
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalDefinedName;
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalDefinedName;
|
||||||
|
@ -79,6 +81,38 @@ public class ExternalLinksTable extends POIXMLDocumentPart {
|
||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the last recorded name of the file that this
|
||||||
|
* is linked to
|
||||||
|
*/
|
||||||
|
public String getLinkedFileName() {
|
||||||
|
String rId = link.getExternalBook().getId();
|
||||||
|
PackageRelationship rel = getPackagePart().getRelationship(rId);
|
||||||
|
if (rel != null && rel.getTargetMode() == TargetMode.EXTERNAL) {
|
||||||
|
return rel.getTargetURI().toString();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Updates the last recorded name for the file that this links to
|
||||||
|
*/
|
||||||
|
public void setLinkedFileName(String target) {
|
||||||
|
String rId = link.getExternalBook().getId();
|
||||||
|
|
||||||
|
if (rId == null || rId.isEmpty()) {
|
||||||
|
// We're a new External Link Table, so nothing to remove
|
||||||
|
} else {
|
||||||
|
// Relationships can't be changed, so remove the old one
|
||||||
|
getPackagePart().removeRelationship(rId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Have a new one added
|
||||||
|
PackageRelationship newRel = getPackagePart().addExternalRelationship(
|
||||||
|
target, PackageRelationshipTypes.EXTERNAL_LINK_PATH);
|
||||||
|
link.getExternalBook().setId(newRel.getId());
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public List<String> getSheetNames() {
|
public List<String> getSheetNames() {
|
||||||
CTExternalSheetName[] sheetNames =
|
CTExternalSheetName[] sheetNames =
|
||||||
|
|
|
@ -79,6 +79,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCalcPr;
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedNames;
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedNames;
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDialogsheet;
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDialogsheet;
|
||||||
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalReference;
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheets;
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheets;
|
||||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;
|
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;
|
||||||
|
@ -157,9 +158,9 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
|
||||||
private CalculationChain calcChain;
|
private CalculationChain calcChain;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* External Links, for referencing names or cells in other workbooks
|
* External Links, for referencing names or cells in other workbooks.
|
||||||
*/
|
*/
|
||||||
private ExternalLinksTable externalLinks;
|
private List<ExternalLinksTable> externalLinks;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A collection of custom XML mappings
|
* A collection of custom XML mappings
|
||||||
|
@ -284,16 +285,19 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
|
||||||
this.workbook = doc.getWorkbook();
|
this.workbook = doc.getWorkbook();
|
||||||
|
|
||||||
Map<String, XSSFSheet> shIdMap = new HashMap<String, XSSFSheet>();
|
Map<String, XSSFSheet> shIdMap = new HashMap<String, XSSFSheet>();
|
||||||
|
Map<String, ExternalLinksTable> elIdMap = new HashMap<String, ExternalLinksTable>();
|
||||||
for(POIXMLDocumentPart p : getRelations()){
|
for(POIXMLDocumentPart p : getRelations()){
|
||||||
if(p instanceof SharedStringsTable) sharedStringSource = (SharedStringsTable)p;
|
if(p instanceof SharedStringsTable) sharedStringSource = (SharedStringsTable)p;
|
||||||
else if(p instanceof StylesTable) stylesSource = (StylesTable)p;
|
else if(p instanceof StylesTable) stylesSource = (StylesTable)p;
|
||||||
else if(p instanceof ThemesTable) theme = (ThemesTable)p;
|
else if(p instanceof ThemesTable) theme = (ThemesTable)p;
|
||||||
else if(p instanceof CalculationChain) calcChain = (CalculationChain)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 MapInfo) mapInfo = (MapInfo)p;
|
||||||
else if (p instanceof XSSFSheet) {
|
else if (p instanceof XSSFSheet) {
|
||||||
shIdMap.put(p.getPackageRelationship().getId(), (XSSFSheet)p);
|
shIdMap.put(p.getPackageRelationship().getId(), (XSSFSheet)p);
|
||||||
}
|
}
|
||||||
|
else if (p instanceof ExternalLinksTable) {
|
||||||
|
elIdMap.put(p.getPackageRelationship().getId(), (ExternalLinksTable)p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stylesSource == null) {
|
if (stylesSource == null) {
|
||||||
|
@ -307,7 +311,8 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
|
||||||
sharedStringSource = (SharedStringsTable)createRelationship(XSSFRelation.SHARED_STRINGS, XSSFFactory.getInstance());
|
sharedStringSource = (SharedStringsTable)createRelationship(XSSFRelation.SHARED_STRINGS, XSSFFactory.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load individual sheets. The order of sheets is defined by the order of CTSheet elements in the workbook
|
// Load individual sheets. The order of sheets is defined by the order
|
||||||
|
// of CTSheet elements in the workbook
|
||||||
sheets = new ArrayList<XSSFSheet>(shIdMap.size());
|
sheets = new ArrayList<XSSFSheet>(shIdMap.size());
|
||||||
for (CTSheet ctSheet : this.workbook.getSheets().getSheetArray()) {
|
for (CTSheet ctSheet : this.workbook.getSheets().getSheetArray()) {
|
||||||
XSSFSheet sh = shIdMap.get(ctSheet.getId());
|
XSSFSheet sh = shIdMap.get(ctSheet.getId());
|
||||||
|
@ -320,6 +325,20 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
|
||||||
sheets.add(sh);
|
sheets.add(sh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load the external links tables. Their order is defined by the order
|
||||||
|
// of CTExternalReference elements in the workbook
|
||||||
|
externalLinks = new ArrayList<ExternalLinksTable>(elIdMap.size());
|
||||||
|
if (this.workbook.isSetExternalReferences()) {
|
||||||
|
for (CTExternalReference er : this.workbook.getExternalReferences().getExternalReferenceArray()) {
|
||||||
|
ExternalLinksTable el = elIdMap.get(er.getId());
|
||||||
|
if(el == null) {
|
||||||
|
logger.log(POILogger.WARN, "ExternalLinksTable with r:id " + er.getId()+ " was defined, but didn't exist in package, skipping");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
externalLinks.add(el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Process the named ranges
|
// Process the named ranges
|
||||||
reprocessNamedRanges();
|
reprocessNamedRanges();
|
||||||
} catch (XmlException e) {
|
} catch (XmlException e) {
|
||||||
|
@ -1611,16 +1630,20 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link ExternalLinksTable} object for this workbook.
|
* Returns the list of {@link ExternalLinksTable} object for this workbook
|
||||||
*
|
*
|
||||||
* <p>The external links table specifies details of named ranges etc
|
* <p>The external links table specifies details of named ranges etc
|
||||||
* that are referenced from other workbooks, along with the last seen
|
* that are referenced from other workbooks, along with the last seen
|
||||||
* values of what they point to.</p>
|
* values of what they point to.</p>
|
||||||
*
|
*
|
||||||
* @return the <code>ExternalLinksTable</code> object or <code>null</code> if not defined
|
* <p>Note that Excel uses index 0 for the current workbook, so the first
|
||||||
|
* External Links in a formula would be '[1]Foo' which corresponds to
|
||||||
|
* entry 0 in this list.</p>
|
||||||
|
|
||||||
|
* @return the <code>ExternalLinksTable</code> list, which may be empty
|
||||||
*/
|
*/
|
||||||
@Internal
|
@Internal
|
||||||
public ExternalLinksTable getExternalLinksTable() {
|
public List<ExternalLinksTable> getExternalLinksTable() {
|
||||||
return externalLinks;
|
return externalLinks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,8 @@ public final class TestExternalLinksTable {
|
||||||
@Test
|
@Test
|
||||||
public void none() {
|
public void none() {
|
||||||
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("SampleSS.xlsx");
|
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("SampleSS.xlsx");
|
||||||
assertEquals(null, wb.getExternalLinksTable());
|
assertNotNull(wb.getExternalLinksTable());
|
||||||
|
assertEquals(0, wb.getExternalLinksTable().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -38,7 +39,9 @@ public final class TestExternalLinksTable {
|
||||||
assertNotNull(wb.getExternalLinksTable());
|
assertNotNull(wb.getExternalLinksTable());
|
||||||
Name name = null;
|
Name name = null;
|
||||||
|
|
||||||
ExternalLinksTable links = wb.getExternalLinksTable();
|
assertEquals(1, wb.getExternalLinksTable().size());
|
||||||
|
|
||||||
|
ExternalLinksTable links = wb.getExternalLinksTable().get(0);
|
||||||
assertEquals(3, links.getSheetNames().size());
|
assertEquals(3, links.getSheetNames().size());
|
||||||
assertEquals(2, links.getDefinedNames().size());
|
assertEquals(2, links.getDefinedNames().size());
|
||||||
|
|
||||||
|
@ -57,17 +60,20 @@ public final class TestExternalLinksTable {
|
||||||
assertEquals(1, name.getSheetIndex());
|
assertEquals(1, name.getSheetIndex());
|
||||||
assertEquals("Defines", name.getSheetName());
|
assertEquals("Defines", name.getSheetName());
|
||||||
assertEquals("'Defines'!$A$1", name.getRefersToFormula());
|
assertEquals("'Defines'!$A$1", name.getRefersToFormula());
|
||||||
|
|
||||||
|
assertEquals("56737.xlsx", links.getLinkedFileName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void basicReadWriteRead() {
|
public void basicReadWriteRead() {
|
||||||
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("ref-56737.xlsx");
|
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("ref-56737.xlsx");
|
||||||
Name name = wb.getExternalLinksTable().getDefinedNames().get(1);
|
Name name = wb.getExternalLinksTable().get(0).getDefinedNames().get(1);
|
||||||
name.setNameName("Testing");
|
name.setNameName("Testing");
|
||||||
name.setRefersToFormula("$A$1");
|
name.setRefersToFormula("$A$1");
|
||||||
|
|
||||||
wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
|
wb = XSSFTestDataSamples.writeOutAndReadBack(wb);
|
||||||
ExternalLinksTable links = wb.getExternalLinksTable();
|
assertEquals(1, wb.getExternalLinksTable().size());
|
||||||
|
ExternalLinksTable links = wb.getExternalLinksTable().get(0);
|
||||||
|
|
||||||
name = links.getDefinedNames().get(0);
|
name = links.getDefinedNames().get(0);
|
||||||
assertEquals("NR_Global_B2", name.getNameName());
|
assertEquals("NR_Global_B2", name.getNameName());
|
||||||
|
@ -86,6 +92,53 @@ public final class TestExternalLinksTable {
|
||||||
public void readWithReferencesToTwoExternalBooks() {
|
public void readWithReferencesToTwoExternalBooks() {
|
||||||
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("ref2-56737.xlsx");
|
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("ref2-56737.xlsx");
|
||||||
|
|
||||||
// TODO Fix so we can see both of them...
|
assertNotNull(wb.getExternalLinksTable());
|
||||||
|
Name name = null;
|
||||||
|
|
||||||
|
assertEquals(2, wb.getExternalLinksTable().size());
|
||||||
|
|
||||||
|
// Check the first one, links to 56737.xlsx
|
||||||
|
ExternalLinksTable links = wb.getExternalLinksTable().get(0);
|
||||||
|
assertEquals("56737.xlsx", links.getLinkedFileName());
|
||||||
|
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());
|
||||||
|
|
||||||
|
|
||||||
|
// Check the second one, links to 56737.xls, slightly differently
|
||||||
|
links = wb.getExternalLinksTable().get(1);
|
||||||
|
assertEquals("56737.xls", links.getLinkedFileName());
|
||||||
|
assertEquals(2, links.getSheetNames().size());
|
||||||
|
assertEquals(2, links.getDefinedNames().size());
|
||||||
|
|
||||||
|
assertEquals("Uses", links.getSheetNames().get(0));
|
||||||
|
assertEquals("Defines", links.getSheetNames().get(1));
|
||||||
|
|
||||||
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue