Skip to content

Commit

Permalink
Disable calcChain processing #174
Browse files Browse the repository at this point in the history
  • Loading branch information
Gavrilov-Ivan committed Jan 25, 2023
1 parent df60236 commit 6aed66b
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import org.docx4j.openpackaging.io3.Save;
import org.docx4j.openpackaging.packages.SpreadsheetMLPackage;
import org.docx4j.openpackaging.parts.PartName;
import org.docx4j.openpackaging.parts.Parts;
import org.docx4j.openpackaging.parts.SpreadsheetML.CalcChain;
import org.docx4j.openpackaging.parts.SpreadsheetML.PivotCacheDefinition;
import org.docx4j.openpackaging.parts.SpreadsheetML.WorksheetPart;
Expand Down Expand Up @@ -140,6 +141,20 @@ protected void validateTemplateContainsNamedRange() {
protected void saveAndClose() {
try {
checkThreadInterrupted();

//Remove calcChain until it is well-formed and to get rid of MS Excel errors on file opening in some cases
SpreadsheetMLPackage smlPackage = result.getPackage();
Parts parts = smlPackage.getParts();
CalcChain calcChain = null;
try {
calcChain = (CalcChain) parts.get(new PartName("/xl/calcChain.xml"));
} catch (InvalidFormatException e) {
log.warn("Invalid format of part name", e);
}
if (calcChain != null) {
calcChain.remove();
}

if (ReportOutputType.csv.equals(outputType)) {
saveXlsxAsCsv(result, outputStream);
outputStream.flush();
Expand Down Expand Up @@ -342,9 +357,8 @@ protected void shiftChart(Document.ChartWrapper chart, Range templateRange, Rang

//todo support formulas without range but with list of cells
protected void updateFormulas() {
CTCalcChain calculationChain = getCalculationChain();
int formulaCount = processInnerFormulas(calculationChain);
processOuterFormulas(formulaCount, calculationChain);
processInnerFormulas();
processOuterFormulas();
}

protected void updateConditionalFormatting() {
Expand Down Expand Up @@ -378,7 +392,7 @@ protected void updateConditionalFormatting() {
}
}

protected void processOuterFormulas(int formulaCount, CTCalcChain calculationChain) {
protected void processOuterFormulas() {
for (CellWithBand cellWithWithBand : outerFormulas) {
Cell cellWithFormula = cellWithWithBand.cell;
String oldFormula = cellWithFormula.getF().getValue();
Expand Down Expand Up @@ -441,7 +455,7 @@ protected void processOuterFormulas(int formulaCount, CTCalcChain calculationCha
for (Range formulaRange : formulaRanges) {
if (newRanges.size() > 0) {
Range shiftedRange = calculateFormulaRangeChange(formulaRange, templateRange, newRanges);
updateFormula(cellWithFormula, formulaRange, shiftedRange, calculationChain, formulaCount++);
updateFormula(cellWithFormula, formulaRange, shiftedRange);
} else {
cellWithFormula.setF(null);
cellWithFormula.setV("ERROR: Formula references to empty range");
Expand All @@ -467,9 +481,7 @@ protected Range calculateFormulaRangeChange(Range formulaRange, Range templateRa
return shiftedRange;
}

protected int processInnerFormulas(CTCalcChain calculationChain) {
int formulaCount = 1;

protected void processInnerFormulas() {
for (CellWithBand cellWithWithBand : innerFormulas) {
Cell cellWithFormula = cellWithWithBand.cell;
String oldFormula = cellWithFormula.getF().getValue();
Expand All @@ -491,60 +503,24 @@ protected int processInnerFormulas(CTCalcChain calculationChain) {

for (Range formulaRange : formulaRanges) {
Range shiftedFormulaRange = formulaRange.copy().shift(offset.downOffset, offset.rightOffset);
updateFormula(cellWithFormula, formulaRange, shiftedFormulaRange, calculationChain, formulaCount++);
updateFormula(cellWithFormula, formulaRange, shiftedFormulaRange);
}
break;
}
}
}
}
}
return formulaCount;
}

protected CTCalcChain getCalculationChain() {
CTCalcChain calculationChain = null;
try {
CalcChain part = (CalcChain) result.getPackage().getParts().get(new PartName("/xl/calcChain.xml"));
if (part != null) {
try {
calculationChain = part.getContents();
} catch (Docx4JException e) {
throw new RuntimeException("Unable to get contents of part", e);
}
calculationChain.getC().clear();
}
} catch (InvalidFormatException e) {
//do nothing
}
return calculationChain;
}

protected void updateFormula(Cell cellWithFormula, Range originalFormulaRange, Range formulaRange,
CTCalcChain calculationChain, int formulaCount) {
protected void updateFormula(Cell cellWithFormula, Range originalFormulaRange, Range formulaRange) {
CTCellFormula formula = cellWithFormula.getF();
formula.setValue(formula.getValue().replace(originalFormulaRange.toRange(), formulaRange.toRange()));
if (originalFormulaRange.isOneCellRange() && formulaRange.isOneCellRange()) {
//here we check that there are no alpha-numeric symbols around the single reference
String pattern = "(?<!\\w+)" + originalFormulaRange.toFirstCellReference() + "(?!\\w+)";
formula.setValue(formula.getValue().replaceAll(pattern, formulaRange.toFirstCellReference()));
}

if (calculationChain != null) {
CTCalcCell calcCell = new CTCalcCell();
calcCell.setR(cellWithFormula.getR());
String sheetName = originalFormulaRange.getSheet();
Sheets sheets = template.getWorkbook().getSheets();
if (sheets != null && sheets.getSheet() != null) {
for (Sheet sheet : sheets.getSheet()) {
if (Objects.equals(sheet.getName(), sheetName)) {
calcCell.setI((int) sheet.getSheetId());
break;
}
}
}
calculationChain.getC().add(calcCell);
}
}

protected Offset calculateOffset(Range from, Range to) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,20 @@ public void testFormulaShifts() throws Exception {
new FormatterFactoryInput("xls", new BandData(""), reportTemplate, null));

Cell cellWithFormula = cellWithFormula("SUM(A9:A9)/B9");
xlsxFormatter.updateFormula(cellWithFormula, Range.fromRange("Sheet", "A9:A9"), Range.fromRange("Sheet", "A90:A90"), null, 0);
xlsxFormatter.updateFormula(cellWithFormula, Range.fromRange("Sheet", "B9:B9"), Range.fromRange("Sheet", "B90:B90"), null, 0);
xlsxFormatter.updateFormula(cellWithFormula, Range.fromRange("Sheet", "A9:A9"), Range.fromRange("Sheet", "A90:A90"));
xlsxFormatter.updateFormula(cellWithFormula, Range.fromRange("Sheet", "B9:B9"), Range.fromRange("Sheet", "B90:B90"));
Assert.assertEquals("SUM(A90:A90)/B90", cellWithFormula.getF().getValue());

cellWithFormula = cellWithFormula("SUM(A9:B9)");
xlsxFormatter.updateFormula(cellWithFormula, Range.fromRange("Sheet", "A9:B9"), Range.fromRange("Sheet", "A90:B90"), null, 0);
xlsxFormatter.updateFormula(cellWithFormula, Range.fromRange("Sheet", "A9:B9"), Range.fromRange("Sheet", "A90:B90"));
Assert.assertEquals("SUM(A90:B90)", cellWithFormula.getF().getValue());

cellWithFormula = cellWithFormula("A9*SUM(A9:A9)");
xlsxFormatter.updateFormula(cellWithFormula, Range.fromRange("Sheet", "A9:A9"), Range.fromRange("Sheet", "A90:A90"), null, 0);
xlsxFormatter.updateFormula(cellWithFormula, Range.fromRange("Sheet", "A9:A9"), Range.fromRange("Sheet", "A90:A90"));
Assert.assertEquals("A90*SUM(A90:A90)", cellWithFormula.getF().getValue());

cellWithFormula = cellWithFormula("CA9*SUM(A9:A9)");
xlsxFormatter.updateFormula(cellWithFormula, Range.fromRange("Sheet", "A9:A9"), Range.fromRange("Sheet", "A90:A90"), null, 0);
xlsxFormatter.updateFormula(cellWithFormula, Range.fromRange("Sheet", "A9:A9"), Range.fromRange("Sheet", "A90:A90"));
Assert.assertEquals("CA9*SUM(A90:A90)", cellWithFormula.getF().getValue());
}

Expand Down

0 comments on commit 6aed66b

Please sign in to comment.