import org.apache.poi.util.Internal;
import org.apache.poi.util.Removal;
import org.apache.xmlbeans.XmlException;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalBook;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalCell;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalDefinedName;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalLink;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalRow;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalSheetData;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalSheetDataSet;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalSheetName;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalSheetNames;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.ExternalLinkDocument;
/**
// Have a new one added
PackageRelationship newRel = getPackagePart().addExternalRelationship(
- target, PackageRelationshipTypes.EXTERNAL_LINK_PATH);
+ target, PackageRelationshipTypes.EXTERNAL_LINK_PATH);
link.getExternalBook().setId(newRel.getId());
}
}
+ public void cacheData(String sheetName, long rowR, String cellR, String v) {
+ CTExternalBook externalBook = link.getExternalBook();
+ synchronized (externalBook.monitor()) {
+ CTExternalSheetData sheetData = getSheetData(getSheetNameIndex(sheetName));
+ CTExternalRow row = getRow(sheetData, rowR);
+ CTExternalCell cell = getCell(row, cellR);
+ cell.setV(v);
+ }
+ }
+
+ private int getSheetNameIndex(String sheetName) {
+ CTExternalBook externalBook = link.getExternalBook();
+ CTExternalSheetNames sheetNames = externalBook.getSheetNames();
+ if (sheetNames == null) {
+ sheetNames = externalBook.addNewSheetNames();
+ }
+ int index = -1;
+ for (int i = 0; i < sheetNames.sizeOfSheetNameArray(); i++) {
+ CTExternalSheetName ctExternalSheetName = sheetNames.getSheetNameArray(i);
+ if (ctExternalSheetName.getVal().equals(sheetName)) {
+ index = i;
+ break;
+ }
+ }
+ if (index == -1) {
+ CTExternalSheetName ctExternalSheetName = sheetNames.addNewSheetName();
+ ctExternalSheetName.setVal(sheetName);
+ index = sheetNames.sizeOfSheetNameArray() - 1;
+ }
+ return index;
+
+ }
+
+ private CTExternalSheetData getSheetData(int sheetId) {
+
+ CTExternalSheetDataSet sheetDataSet = link.getExternalBook().getSheetDataSet();
+ if (sheetDataSet == null) {
+ sheetDataSet = link.getExternalBook().addNewSheetDataSet();
+ }
+ CTExternalSheetData ctExternalSheetData = null;
+ for (CTExternalSheetData item : sheetDataSet.getSheetDataArray()) {
+ if (item.getSheetId() == sheetId) {
+ ctExternalSheetData = item;
+ break;
+ }
+ }
+ if (ctExternalSheetData == null) {
+ ctExternalSheetData = sheetDataSet.addNewSheetData();
+ ctExternalSheetData.setSheetId(sheetId);
+ }
+ return ctExternalSheetData;
+ }
+
+ private CTExternalRow getRow(CTExternalSheetData sheetData, long rowR) {
+ for (CTExternalRow ctExternalRow : sheetData.getRowArray()) {
+ if (ctExternalRow.getR() == rowR) {
+ return ctExternalRow;
+ }
+ }
+ CTExternalRow ctExternalRow = sheetData.addNewRow();
+ ctExternalRow.setR(rowR);
+ return ctExternalRow;
+ }
+
+ private CTExternalCell getCell(CTExternalRow row, String cellR) {
+ for (CTExternalCell ctExternalCell : row.getCellArray()) {
+ if (ctExternalCell.getR().equals(cellR)) {
+ return ctExternalCell;
+ }
+ }
+ CTExternalCell ctExternalCell = row.addNewCell();
+ ctExternalCell.setR(cellR);
+ return ctExternalCell;
+ }
// TODO Last seen data
throw new IllegalStateException("Not Supported");
}
}
-}
\ No newline at end of file
+}
import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.StringEval;
import org.apache.poi.ss.formula.eval.ValueEval;
+import org.apache.poi.ss.formula.ptg.Area3DPxg;
+import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.CellValue;
import org.apache.poi.ss.usermodel.RichTextString;
+import org.apache.poi.ss.util.CellReference;
+import org.apache.poi.xssf.model.ExternalLinksTable;
/**
* Internal POI use only - parent of XSSF and SXSSF formula evaluators
protected CellValue evaluateFormulaCellValue(Cell cell) {
EvaluationCell evalCell = toEvaluationCell(cell);
ValueEval eval = _bookEvaluator.evaluate(evalCell);
+ cacheExternalWorkbookCells(evalCell);
if (eval instanceof NumberEval) {
NumberEval ne = (NumberEval) eval;
return new CellValue(ne.getNumberValue());
throw new RuntimeException("Unexpected eval class (" + eval.getClass().getName() + ")");
}
+ /**
+ * cache cell value of external workbook
+ *
+ * @param evalCell sourceCell
+ */
+ private void cacheExternalWorkbookCells(EvaluationCell evalCell) {
+ //
+ Ptg[] formulaTokens = getEvaluationWorkbook().getFormulaTokens(evalCell);
+ for (Ptg ptg : formulaTokens) {
+ if (ptg instanceof Area3DPxg) {
+ Area3DPxg area3DPxg = (Area3DPxg) ptg;
+ if (area3DPxg.getExternalWorkbookNumber() > 0) {
+ EvaluationWorkbook.ExternalSheet externalSheet = getEvaluationWorkbook().getExternalSheet(area3DPxg.getSheetName(), area3DPxg.getLastSheetName(), area3DPxg.getExternalWorkbookNumber());
+
+ XSSFCell xssfCell = ((XSSFEvaluationCell) evalCell).getXSSFCell();
+ XSSFWorkbook externalWorkbook = (XSSFWorkbook) xssfCell.getSheet().getWorkbook().getCreationHelper().getReferencedWorkbooks().get(externalSheet.getWorkbookName());
+ ExternalLinksTable externalLinksTable = xssfCell.getSheet().getWorkbook().getExternalLinksTable().get(area3DPxg.getExternalWorkbookNumber() - 1);
+
+ int firstSheet = externalWorkbook.getSheetIndex(area3DPxg.getSheetName());
+ int lastSheet = firstSheet;
+ if (area3DPxg.getLastSheetName() != null) {
+ lastSheet = externalWorkbook.getSheetIndex(area3DPxg.getLastSheetName());
+ }
+
+ for (int sheetIndex = firstSheet; sheetIndex <= lastSheet; sheetIndex++) {
+ XSSFSheet sheet = externalWorkbook.getSheetAt(sheetIndex);
+ int firstRow = area3DPxg.getFirstRow();
+ int lastRow = area3DPxg.getLastRow();
+ for (int rowIndex = firstRow; rowIndex <= lastRow; rowIndex++) {
+ XSSFRow row = sheet.getRow(rowIndex);
+ int firstColumn = area3DPxg.getFirstColumn();
+ int lastColumn = area3DPxg.getLastColumn();
+ for (int cellIndex = firstColumn; cellIndex <= lastColumn; cellIndex++) {
+ XSSFCell cell = row.getCell(cellIndex);
+ String cellValue = cell.getRawValue();
+ String cellR = new CellReference(cell).formatAsString(false);
+ externalLinksTable.cacheData(sheet.getSheetName(), rowIndex + 1, cellR, cellValue);
+
+ }
+ }
+
+ }
+ }
+
+ }
+ }
+ }
+
@Override
protected void setCellType(Cell cell, CellType cellType) {
- if (cell instanceof XSSFCell) {
+ if (cell instanceof XSSFCell) {
EvaluationWorkbook evaluationWorkbook = getEvaluationWorkbook();
BaseXSSFEvaluationWorkbook xewb = BaseXSSFEvaluationWorkbook.class.isAssignableFrom(evaluationWorkbook.getClass()) ? (BaseXSSFEvaluationWorkbook) evaluationWorkbook : null;
import org.apache.poi.xssf.model.StylesTable;
import org.junit.jupiter.api.Test;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCalcPr;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalLink;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTExternalSheetData;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPivotCache;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr;
// Check the package contains what we'd expect it to
try (OPCPackage pkg = OPCPackage.open(file.toString())) {
PackagePart wbRelPart =
- pkg.getPart(PackagingURIHelper.createPartName("/xl/_rels/workbook.xml.rels"));
+ pkg.getPart(PackagingURIHelper.createPartName("/xl/_rels/workbook.xml.rels"));
assertNotNull(wbRelPart);
assertTrue(wbRelPart.isRelationshipPart());
assertEquals(ContentTypes.RELATIONSHIPS_PART, wbRelPart.getContentType());
PackagePart wbPart =
- pkg.getPart(PackagingURIHelper.createPartName("/xl/workbook.xml"));
+ pkg.getPart(PackagingURIHelper.createPartName("/xl/workbook.xml"));
// Links to the three sheets, shared strings and styles
assertTrue(wbPart.hasRelationships());
assertEquals(5, wbPart.getRelationships().size());
// Add two more styles
assertEquals(StylesTable.FIRST_CUSTOM_STYLE_ID + 8,
- st.putNumberFormat("testFORMAT"));
+ st.putNumberFormat("testFORMAT"));
assertEquals(StylesTable.FIRST_CUSTOM_STYLE_ID + 8,
- st.putNumberFormat("testFORMAT"));
+ st.putNumberFormat("testFORMAT"));
assertEquals(StylesTable.FIRST_CUSTOM_STYLE_ID + 9,
- st.putNumberFormat("testFORMAT2"));
+ st.putNumberFormat("testFORMAT2"));
assertEquals(10, st.getNumDataFormats());
assertEquals(1, allPictures.size());
PackagePartName imagePartName = PackagingURIHelper
- .createPartName("/xl/media/image1.jpeg");
+ .createPartName("/xl/media/image1.jpeg");
PackagePart imagePart = workbook.getPackage().getPart(imagePartName);
assertNotNull(imagePart);
*/
@Test
void getTable() throws IOException {
- XSSFWorkbook wb = openSampleWorkbook("WithTable.xlsx");
- XSSFTable table1 = wb.getTable("Tabella1");
- assertNotNull(table1, "Tabella1 was not found in workbook");
- assertEquals("Tabella1", table1.getName(), "Table name");
- assertEquals("Foglio1", table1.getSheetName(), "Sheet name");
-
- // Table lookup should be case-insensitive
- assertSame(table1, wb.getTable("TABELLA1"), "Case insensitive table name lookup");
-
- // If workbook does not contain any data tables matching the provided name, getTable should return null
- assertNull(wb.getTable(null), "Null table name should not throw NPE");
- assertNull(wb.getTable("Foglio1"), "Should not be able to find non-existent table");
-
- // If a table is added after getTable is called it should still be reachable by XSSFWorkbook.getTable
- // This test makes sure that if any caching is done that getTable never uses a stale cache
- XSSFTable table2 = wb.getSheet("Foglio2").createTable(null);
- table2.setName("Table2");
- assertSame(table2, wb.getTable("Table2"), "Did not find Table2");
-
- // If table name is modified after getTable is called, the table can only be found by its new name
- // This test makes sure that if any caching is done that getTable never uses a stale cache
- table1.setName("Table1");
- assertSame(table1, wb.getTable("TABLE1"), "Did not find Tabella1 renamed to Table1");
-
- wb.close();
+ XSSFWorkbook wb = openSampleWorkbook("WithTable.xlsx");
+ XSSFTable table1 = wb.getTable("Tabella1");
+ assertNotNull(table1, "Tabella1 was not found in workbook");
+ assertEquals("Tabella1", table1.getName(), "Table name");
+ assertEquals("Foglio1", table1.getSheetName(), "Sheet name");
+
+ // Table lookup should be case-insensitive
+ assertSame(table1, wb.getTable("TABELLA1"), "Case insensitive table name lookup");
+
+ // If workbook does not contain any data tables matching the provided name, getTable should return null
+ assertNull(wb.getTable(null), "Null table name should not throw NPE");
+ assertNull(wb.getTable("Foglio1"), "Should not be able to find non-existent table");
+
+ // If a table is added after getTable is called it should still be reachable by XSSFWorkbook.getTable
+ // This test makes sure that if any caching is done that getTable never uses a stale cache
+ XSSFTable table2 = wb.getSheet("Foglio2").createTable(null);
+ table2.setName("Table2");
+ assertSame(table2, wb.getTable("Table2"), "Did not find Table2");
+
+ // If table name is modified after getTable is called, the table can only be found by its new name
+ // This test makes sure that if any caching is done that getTable never uses a stale cache
+ table1.setName("Table1");
+ assertSame(table1, wb.getTable("TABLE1"), "Did not find Tabella1 renamed to Table1");
+
+ wb.close();
}
@SuppressWarnings("deprecation")
}
}
+ @Test
+ void testCacheExternalWorkbook() throws Exception {
+ String nameA = "cache-external-workbook-a.xlsx";
+
+ try (
+ UnsynchronizedByteArrayOutputStream bosA = new UnsynchronizedByteArrayOutputStream();
+ UnsynchronizedByteArrayOutputStream bosB = new UnsynchronizedByteArrayOutputStream();
+ XSSFWorkbook workbookA = new XSSFWorkbook();
+ XSSFWorkbook workbookB = new XSSFWorkbook()
+ ) {
+ XSSFRow row1 = workbookA.createSheet().createRow(0);
+ double v1 = 10, v2 = 10, sum = v1 + v2;
+ row1.createCell(0).setCellValue(v1);
+ row1.createCell(1).setCellValue(v2);
+
+ XSSFRow row = workbookB.createSheet().createRow(0);
+ XSSFCell cell = row.createCell(0);
+
+ workbookB.linkExternalWorkbook(nameA, workbookA);
+ String formula = String.format(LocaleUtil.getUserLocale(), "SUM('[%s]Sheet0'!A1:B1)", nameA);
+ cell.setCellFormula(formula);
+ XSSFFormulaEvaluator evaluator = workbookB.getCreationHelper().createFormulaEvaluator();
+ evaluator.evaluateFormulaCell(cell);
+
+ assertEquals(sum, cell.getNumericCellValue());
+
+ workbookA.write(bosA);
+ workbookB.write(bosB);
+
+ try(
+ XSSFWorkbook workbook2 = new XSSFWorkbook(bosB.toInputStream())
+ ) {
+ CTExternalLink link = workbook2.getExternalLinksTable().get(0).getCTExternalLink();
+ CTExternalSheetData sheetData = link.getExternalBook().getSheetDataSet().getSheetDataArray(0);
+ assertEquals(Double.valueOf(sheetData.getRowArray(0).getCellArray(0).getV()), v1);
+ assertEquals(Double.valueOf(sheetData.getRowArray(0).getCellArray(1).getV()), v2);
+ }
+ }
+ }
+
private static void expectFormattedContent(Cell cell, String value) {
assertEquals(value, new DataFormatter().formatCellValue(cell),
"Cell " + ref(cell) + " has wrong formatted content.");