Преглед на файлове

[github-296] cache data of external workbook. Thanks to aspojo. This closes #296

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1897311 13f79535-47bb-0310-9956-ffa450edef68
tags/REL_5_2_1
PJ Fanning преди 2 години
родител
ревизия
68ce022531

+ 82
- 2
poi-ooxml/src/main/java/org/apache/poi/xssf/model/ExternalLinksTable.java Целия файл

@@ -33,9 +33,15 @@ import org.apache.poi.ss.usermodel.Name;
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;

/**
@@ -123,7 +129,7 @@ public class ExternalLinksTable extends POIXMLDocumentPart {

// Have a new one added
PackageRelationship newRel = getPackagePart().addExternalRelationship(
target, PackageRelationshipTypes.EXTERNAL_LINK_PATH);
target, PackageRelationshipTypes.EXTERNAL_LINK_PATH);
link.getExternalBook().setId(newRel.getId());
}

@@ -148,6 +154,80 @@ public class ExternalLinksTable extends POIXMLDocumentPart {
}


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


@@ -226,4 +306,4 @@ public class ExternalLinksTable extends POIXMLDocumentPart {
throw new IllegalStateException("Not Supported");
}
}
}
}

+ 54
- 1
poi-ooxml/src/main/java/org/apache/poi/xssf/usermodel/BaseXSSFFormulaEvaluator.java Целия файл

@@ -26,10 +26,14 @@ import org.apache.poi.ss.formula.eval.ErrorEval;
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
@@ -55,6 +59,7 @@ public abstract class BaseXSSFFormulaEvaluator extends BaseFormulaEvaluator {
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());
@@ -73,9 +78,57 @@ public abstract class BaseXSSFFormulaEvaluator extends BaseFormulaEvaluator {
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;


+ 73
- 31
poi-ooxml/src/test/java/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java Целия файл

@@ -61,6 +61,8 @@ import org.apache.poi.xssf.XSSFITestDataProvider;
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;
@@ -109,13 +111,13 @@ public final class TestXSSFWorkbook extends BaseTestXWorkbook {
// 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());
@@ -294,11 +296,11 @@ public final class TestXSSFWorkbook extends BaseTestXWorkbook {

// 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());


@@ -370,7 +372,7 @@ public final class TestXSSFWorkbook extends BaseTestXWorkbook {
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);

@@ -1069,31 +1071,31 @@ public final class TestXSSFWorkbook extends BaseTestXWorkbook {
*/
@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")
@@ -1299,6 +1301,46 @@ public final class TestXSSFWorkbook extends BaseTestXWorkbook {
}
}

@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.");

Двоични данни
poi/src/main/java9/module-info.class Целия файл


Loading…
Отказ
Запис