From 41eb660d9a51f7d01cc4493408bd2d98ffbb30de Mon Sep 17 00:00:00 2001 From: ongdisheng Date: Mon, 17 Nov 2025 08:35:05 +0000 Subject: [PATCH 1/6] feat: Add support for reading shared formulas in XLSX files --- .../v07/handlers/CellFormulaTagHandler.java | 181 +++++++++---- .../sheet/constant/ExcelXmlConstants.java | 248 +++++++++--------- .../holder/xlsx/XlsxReadSheetHolder.java | 179 ++++++++----- .../fesod/sheet/formula/FormulaData.java | 58 ++++ .../sheet/formula/FormulaDataListener.java | 71 +++++ .../fesod/sheet/formula/FormulaDataTest.java | 46 ++++ .../resources/formula/shared_formula.xlsx | Bin 0 -> 12432 bytes 7 files changed, 543 insertions(+), 240 deletions(-) create mode 100644 fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaData.java create mode 100644 fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaDataListener.java create mode 100644 fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaDataTest.java create mode 100644 fesod/src/test/resources/formula/shared_formula.xlsx diff --git a/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java b/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java index 6e098fa1d..b7d36e95b 100644 --- a/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java +++ b/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java @@ -1,51 +1,130 @@ -/* - * 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.fesod.sheet.analysis.v07.handlers; - -import org.apache.fesod.sheet.context.xlsx.XlsxReadContext; -import org.apache.fesod.sheet.metadata.data.FormulaData; -import org.apache.fesod.sheet.read.metadata.holder.xlsx.XlsxReadSheetHolder; -import org.xml.sax.Attributes; - -/** - * Cell Handler - * - */ -public class CellFormulaTagHandler extends AbstractXlsxTagHandler { - - @Override - public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { - XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); - xlsxReadSheetHolder.setTempFormula(new StringBuilder()); - } - - @Override - public void endElement(XlsxReadContext xlsxReadContext, String name) { - XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); - FormulaData formulaData = new FormulaData(); - formulaData.setFormulaValue(xlsxReadSheetHolder.getTempFormula().toString()); - xlsxReadSheetHolder.getTempCellData().setFormulaData(formulaData); - } - - @Override - public void characters(XlsxReadContext xlsxReadContext, char[] ch, int start, int length) { - xlsxReadContext.xlsxReadSheetHolder().getTempFormula().append(ch, start, length); - } -} +/* + * 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.fesod.sheet.analysis.v07.handlers; + +import org.apache.fesod.sheet.constant.ExcelXmlConstants; +import org.apache.fesod.sheet.context.xlsx.XlsxReadContext; +import org.apache.fesod.sheet.metadata.data.FormulaData; +import org.apache.fesod.sheet.read.metadata.holder.xlsx.XlsxReadSheetHolder; +import org.apache.fesod.sheet.util.StringUtils; +import org.apache.poi.ss.SpreadsheetVersion; +import org.apache.poi.ss.formula.FormulaParser; +import org.apache.poi.ss.formula.FormulaRenderer; +import org.apache.poi.ss.formula.FormulaType; +import org.apache.poi.ss.formula.SharedFormula; +import org.apache.poi.ss.formula.ptg.Ptg; +import org.xml.sax.Attributes; + +/** + * Cell Handler + * + */ +public class CellFormulaTagHandler extends AbstractXlsxTagHandler { + + @Override + public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { + XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); + xlsxReadSheetHolder.setTempFormula(new StringBuilder()); + + String formulaType = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_T); + String sharedIndex = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_SI); + + xlsxReadSheetHolder.setTempFormulaType(formulaType); + xlsxReadSheetHolder.setTempFormulaSharedIndex(sharedIndex != null ? Integer.parseInt(sharedIndex) : null); + } + + @Override + public void endElement(XlsxReadContext xlsxReadContext, String name) { + XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); + String formulaText = xlsxReadSheetHolder.getTempFormula().toString(); + String formulaType = xlsxReadSheetHolder.getTempFormulaType(); + Integer sharedIndex = xlsxReadSheetHolder.getTempFormulaSharedIndex(); + + if (ExcelXmlConstants.ATTRIBUTE_SHARED.equals(formulaType) && sharedIndex != null) { + formulaText = handleSharedFormula(xlsxReadSheetHolder, formulaText, sharedIndex); + } + + FormulaData formulaData = new FormulaData(); + formulaData.setFormulaValue(formulaText); + xlsxReadSheetHolder.getTempCellData().setFormulaData(formulaData); + } + + @Override + public void characters(XlsxReadContext xlsxReadContext, char[] ch, int start, int length) { + xlsxReadContext.xlsxReadSheetHolder().getTempFormula().append(ch, start, length); + } + + /** + * Handles shared formula when reading from Excel + */ + private String handleSharedFormula(XlsxReadSheetHolder xlsxReadSheetHolder, String formulaText, int sharedIndex) { + Integer currentRow = xlsxReadSheetHolder.getRowIndex(); + Integer currentCol = xlsxReadSheetHolder.getColumnIndex(); + + if (currentRow == null || currentCol == null) { + return formulaText; + } + + // If formula text exists then this is the master cell + if (!StringUtils.isEmpty(formulaText)) { + xlsxReadSheetHolder + .getSharedFormulaMap() + .put(sharedIndex, new XlsxReadSheetHolder.SharedFormulaInfo(formulaText, currentRow, currentCol)); + return formulaText; + } else { + // No formula text means this is a shared reference cell + XlsxReadSheetHolder.SharedFormulaInfo masterInfo = + xlsxReadSheetHolder.getSharedFormulaMap().get(sharedIndex); + + if (masterInfo == null) { + return ""; + } + + return convertSharedFormula(masterInfo, currentRow, currentCol); + } + } + + /** + * Converts shared formula based on row and column offset + */ + private String convertSharedFormula( + XlsxReadSheetHolder.SharedFormulaInfo masterInfo, int currentRow, int currentCol) { + try { + // Parse the master formula text into tokens + Ptg[] masterPtgs = FormulaParser.parse(masterInfo.getFormulaText(), null, FormulaType.CELL, 0); + + // Calculate offset from the master cell position + int rowOffset = currentRow - masterInfo.getFirstRow(); + int colOffset = currentCol - masterInfo.getFirstCol(); + + // Use POI SharedFormula to convert with offset + SharedFormula sharedFormula = new SharedFormula(SpreadsheetVersion.EXCEL2007); + Ptg[] convertedPtgs = sharedFormula.convertSharedFormulas(masterPtgs, rowOffset, colOffset); + + // Convert tokens back to formula string + return FormulaRenderer.toFormulaString(null, convertedPtgs); + } catch (Exception e) { + // If conversion fails, return the master formula as-is + // This handles cases like volatile functions with no cell references + // where the formula should be identical across all cells anyway + return masterInfo.getFormulaText(); + } + } +} diff --git a/fesod/src/main/java/org/apache/fesod/sheet/constant/ExcelXmlConstants.java b/fesod/src/main/java/org/apache/fesod/sheet/constant/ExcelXmlConstants.java index 2b6ea96b9..3c4ae2b66 100644 --- a/fesod/src/main/java/org/apache/fesod/sheet/constant/ExcelXmlConstants.java +++ b/fesod/src/main/java/org/apache/fesod/sheet/constant/ExcelXmlConstants.java @@ -1,120 +1,128 @@ -/* - * 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.fesod.sheet.constant; - -/** - * - */ -public class ExcelXmlConstants { - public static final String DIMENSION_TAG = "dimension"; - public static final String ROW_TAG = "row"; - public static final String CELL_FORMULA_TAG = "f"; - public static final String CELL_VALUE_TAG = "v"; - /** - * When the data is "inlineStr" his tag is "t" - */ - public static final String CELL_INLINE_STRING_VALUE_TAG = "t"; - - public static final String CELL_TAG = "c"; - public static final String MERGE_CELL_TAG = "mergeCell"; - public static final String HYPERLINK_TAG = "hyperlink"; - - public static final String X_DIMENSION_TAG = "x:dimension"; - public static final String NS2_DIMENSION_TAG = "ns2:dimension"; - - public static final String X_ROW_TAG = "x:row"; - public static final String NS2_ROW_TAG = "ns2:row"; - - public static final String X_CELL_FORMULA_TAG = "x:f"; - public static final String NS2_CELL_FORMULA_TAG = "ns2:f"; - public static final String X_CELL_VALUE_TAG = "x:v"; - public static final String NS2_CELL_VALUE_TAG = "ns2:v"; - - /** - * When the data is "inlineStr" his tag is "t" - */ - public static final String X_CELL_INLINE_STRING_VALUE_TAG = "x:t"; - - public static final String NS2_CELL_INLINE_STRING_VALUE_TAG = "ns2:t"; - - public static final String X_CELL_TAG = "x:c"; - public static final String NS2_CELL_TAG = "ns2:c"; - public static final String X_MERGE_CELL_TAG = "x:mergeCell"; - public static final String NS2_MERGE_CELL_TAG = "ns2:mergeCell"; - public static final String X_HYPERLINK_TAG = "x:hyperlink"; - public static final String NS2_HYPERLINK_TAG = "ns2:hyperlink"; - - /** - * s attribute - */ - public static final String ATTRIBUTE_S = "s"; - /** - * ref attribute - */ - public static final String ATTRIBUTE_REF = "ref"; - /** - * r attribute - */ - public static final String ATTRIBUTE_R = "r"; - /** - * t attribute - */ - public static final String ATTRIBUTE_T = "t"; - /** - * location attribute - */ - public static final String ATTRIBUTE_LOCATION = "location"; - - /** - * rId attribute - */ - public static final String ATTRIBUTE_RID = "r:id"; - - /** - * Cell range split - */ - public static final String CELL_RANGE_SPLIT = ":"; - - // The following is a constant read the `SharedStrings.xml` - - /** - * text - */ - public static final String SHAREDSTRINGS_T_TAG = "t"; - - public static final String SHAREDSTRINGS_X_T_TAG = "x:t"; - public static final String SHAREDSTRINGS_NS2_T_TAG = "ns2:t"; - - /** - * SharedStringItem - */ - public static final String SHAREDSTRINGS_SI_TAG = "si"; - - public static final String SHAREDSTRINGS_X_SI_TAG = "x:si"; - public static final String SHAREDSTRINGS_NS2_SI_TAG = "ns2:si"; - - /** - * Mac 2016 2017 will have this extra field to ignore - */ - public static final String SHAREDSTRINGS_RPH_TAG = "rPh"; - - public static final String SHAREDSTRINGS_X_RPH_TAG = "x:rPh"; - public static final String SHAREDSTRINGS_NS2_RPH_TAG = "ns2:rPh"; -} +/* + * 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.fesod.sheet.constant; + +/** + * + */ +public class ExcelXmlConstants { + public static final String DIMENSION_TAG = "dimension"; + public static final String ROW_TAG = "row"; + public static final String CELL_FORMULA_TAG = "f"; + public static final String CELL_VALUE_TAG = "v"; + /** + * When the data is "inlineStr" his tag is "t" + */ + public static final String CELL_INLINE_STRING_VALUE_TAG = "t"; + + public static final String CELL_TAG = "c"; + public static final String MERGE_CELL_TAG = "mergeCell"; + public static final String HYPERLINK_TAG = "hyperlink"; + + public static final String X_DIMENSION_TAG = "x:dimension"; + public static final String NS2_DIMENSION_TAG = "ns2:dimension"; + + public static final String X_ROW_TAG = "x:row"; + public static final String NS2_ROW_TAG = "ns2:row"; + + public static final String X_CELL_FORMULA_TAG = "x:f"; + public static final String NS2_CELL_FORMULA_TAG = "ns2:f"; + public static final String X_CELL_VALUE_TAG = "x:v"; + public static final String NS2_CELL_VALUE_TAG = "ns2:v"; + + /** + * When the data is "inlineStr" his tag is "t" + */ + public static final String X_CELL_INLINE_STRING_VALUE_TAG = "x:t"; + + public static final String NS2_CELL_INLINE_STRING_VALUE_TAG = "ns2:t"; + + public static final String X_CELL_TAG = "x:c"; + public static final String NS2_CELL_TAG = "ns2:c"; + public static final String X_MERGE_CELL_TAG = "x:mergeCell"; + public static final String NS2_MERGE_CELL_TAG = "ns2:mergeCell"; + public static final String X_HYPERLINK_TAG = "x:hyperlink"; + public static final String NS2_HYPERLINK_TAG = "ns2:hyperlink"; + + /** + * s attribute + */ + public static final String ATTRIBUTE_S = "s"; + /** + * ref attribute + */ + public static final String ATTRIBUTE_REF = "ref"; + /** + * r attribute + */ + public static final String ATTRIBUTE_R = "r"; + /** + * t attribute + */ + public static final String ATTRIBUTE_T = "t"; + /** + * si attribute + */ + public static final String ATTRIBUTE_SI = "si"; + /** + * shared attribute + */ + public static final String ATTRIBUTE_SHARED = "shared"; + /** + * location attribute + */ + public static final String ATTRIBUTE_LOCATION = "location"; + + /** + * rId attribute + */ + public static final String ATTRIBUTE_RID = "r:id"; + + /** + * Cell range split + */ + public static final String CELL_RANGE_SPLIT = ":"; + + // The following is a constant read the `SharedStrings.xml` + + /** + * text + */ + public static final String SHAREDSTRINGS_T_TAG = "t"; + + public static final String SHAREDSTRINGS_X_T_TAG = "x:t"; + public static final String SHAREDSTRINGS_NS2_T_TAG = "ns2:t"; + + /** + * SharedStringItem + */ + public static final String SHAREDSTRINGS_SI_TAG = "si"; + + public static final String SHAREDSTRINGS_X_SI_TAG = "x:si"; + public static final String SHAREDSTRINGS_NS2_SI_TAG = "ns2:si"; + + /** + * Mac 2016 2017 will have this extra field to ignore + */ + public static final String SHAREDSTRINGS_RPH_TAG = "rPh"; + + public static final String SHAREDSTRINGS_X_RPH_TAG = "x:rPh"; + public static final String SHAREDSTRINGS_NS2_RPH_TAG = "ns2:rPh"; +} diff --git a/fesod/src/main/java/org/apache/fesod/sheet/read/metadata/holder/xlsx/XlsxReadSheetHolder.java b/fesod/src/main/java/org/apache/fesod/sheet/read/metadata/holder/xlsx/XlsxReadSheetHolder.java index c4ab92f4c..69f8c168a 100644 --- a/fesod/src/main/java/org/apache/fesod/sheet/read/metadata/holder/xlsx/XlsxReadSheetHolder.java +++ b/fesod/src/main/java/org/apache/fesod/sheet/read/metadata/holder/xlsx/XlsxReadSheetHolder.java @@ -1,69 +1,110 @@ -/* - * 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.fesod.sheet.read.metadata.holder.xlsx; - -import java.util.Deque; -import java.util.LinkedList; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; -import org.apache.fesod.sheet.read.metadata.ReadSheet; -import org.apache.fesod.sheet.read.metadata.holder.ReadSheetHolder; -import org.apache.fesod.sheet.read.metadata.holder.ReadWorkbookHolder; -import org.apache.poi.openxml4j.opc.PackageRelationshipCollection; - -/** - * sheet holder - * - * - */ -@Getter -@Setter -@EqualsAndHashCode -public class XlsxReadSheetHolder extends ReadSheetHolder { - /** - * Record the label of the current operation to prevent NPE. - */ - private Deque tagDeque; - /** - * Current Column - */ - private Integer columnIndex; - /** - * Data for current label. - */ - private StringBuilder tempData; - /** - * Formula for current label. - */ - private StringBuilder tempFormula; - /** - * excel Relationship - */ - private PackageRelationshipCollection packageRelationshipCollection; - - public XlsxReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) { - super(readSheet, readWorkbookHolder); - this.tagDeque = new LinkedList(); - packageRelationshipCollection = ((XlsxReadWorkbookHolder) readWorkbookHolder) - .getPackageRelationshipCollectionMap() - .get(readSheet.getSheetNo()); - } -} +/* + * 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.fesod.sheet.read.metadata.holder.xlsx; + +import java.util.Deque; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import org.apache.fesod.sheet.read.metadata.ReadSheet; +import org.apache.fesod.sheet.read.metadata.holder.ReadSheetHolder; +import org.apache.fesod.sheet.read.metadata.holder.ReadWorkbookHolder; +import org.apache.poi.openxml4j.opc.PackageRelationshipCollection; + +/** + * sheet holder + * + * + */ +@Getter +@Setter +@EqualsAndHashCode +public class XlsxReadSheetHolder extends ReadSheetHolder { + /** + * Record the label of the current operation to prevent NPE. + */ + private Deque tagDeque; + /** + * Current Column + */ + private Integer columnIndex; + /** + * Data for current label. + */ + private StringBuilder tempData; + /** + * Formula for current label. + */ + private StringBuilder tempFormula; + /** + * Formula type for current label. + */ + private String tempFormulaType; + /** + * Shared formula index for current label. + */ + private Integer tempFormulaSharedIndex; + /** + * Map to store master shared formulas by their shared index. + */ + private Map sharedFormulaMap; + /** + * excel Relationship + */ + private PackageRelationshipCollection packageRelationshipCollection; + + public XlsxReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) { + super(readSheet, readWorkbookHolder); + this.tagDeque = new LinkedList(); + this.sharedFormulaMap = new HashMap<>(); + packageRelationshipCollection = ((XlsxReadWorkbookHolder) readWorkbookHolder) + .getPackageRelationshipCollectionMap() + .get(readSheet.getSheetNo()); + } + + /** + * Information about a shared formula master cell. + */ + @Getter + @Setter + public static class SharedFormulaInfo { + /** + * The master formula text. + */ + private String formulaText; + /** + * Row index of the master formula cell. + */ + private int firstRow; + /** + * Column index of the master formula cell. + */ + private int firstCol; + + public SharedFormulaInfo(String formulaText, int firstRow, int firstCol) { + this.formulaText = formulaText; + this.firstRow = firstRow; + this.firstCol = firstCol; + } + } +} diff --git a/fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaData.java b/fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaData.java new file mode 100644 index 000000000..de15e3e2a --- /dev/null +++ b/fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaData.java @@ -0,0 +1,58 @@ +/* + * 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.fesod.sheet.formula; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import org.apache.fesod.sheet.annotation.ExcelProperty; +import org.apache.fesod.sheet.metadata.data.ReadCellData; + +/** + * Test data for shared formula reading + */ +@Getter +@Setter +@EqualsAndHashCode +public class FormulaData { + @ExcelProperty("date") + private String date; + + @ExcelProperty("value1") + private Integer value1; + + @ExcelProperty("value2") + private Integer value2; + + @ExcelProperty("volatileFormula") + private ReadCellData volatileFormula; + + @ExcelProperty("relativeFormula") + private ReadCellData relativeFormula; + + @ExcelProperty("columnAbsoluteFormula") + private ReadCellData columnAbsoluteFormula; + + @ExcelProperty("mixedAbsoluteFormula") + private ReadCellData mixedAbsoluteFormula; + + @ExcelProperty("additionFormula") + private ReadCellData additionFormula; +} diff --git a/fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaDataListener.java b/fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaDataListener.java new file mode 100644 index 000000000..2e55e9508 --- /dev/null +++ b/fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaDataListener.java @@ -0,0 +1,71 @@ +/* + * 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.fesod.sheet.formula; + +import lombok.extern.slf4j.Slf4j; +import org.apache.fesod.sheet.context.AnalysisContext; +import org.apache.fesod.sheet.event.AnalysisEventListener; +import org.junit.jupiter.api.Assertions; + +/** + * Listener for formula data testing + */ +@Slf4j +public class FormulaDataListener extends AnalysisEventListener { + + @Override + public void invoke(FormulaData data, AnalysisContext context) { + // Verify that shared formulas are read correctly + if (data.getVolatileFormula() != null && data.getVolatileFormula().getFormulaData() != null) { + String formula = data.getVolatileFormula().getFormulaData().getFormulaValue(); + Assertions.assertNotNull(formula); + log.info("volatileFormula: {}", formula); + } + + if (data.getRelativeFormula() != null && data.getRelativeFormula().getFormulaData() != null) { + String formula = data.getRelativeFormula().getFormulaData().getFormulaValue(); + Assertions.assertNotNull(formula); + log.info("relativeFormula: {}", formula); + } + + if (data.getColumnAbsoluteFormula() != null && data.getColumnAbsoluteFormula().getFormulaData() != null) { + String formula = data.getColumnAbsoluteFormula().getFormulaData().getFormulaValue(); + Assertions.assertNotNull(formula); + log.info("columnAbsoluteFormula: {}", formula); + } + + if (data.getMixedAbsoluteFormula() != null && data.getMixedAbsoluteFormula().getFormulaData() != null) { + String formula = data.getMixedAbsoluteFormula().getFormulaData().getFormulaValue(); + Assertions.assertNotNull(formula); + log.info("mixedAbsoluteFormula: {}", formula); + } + + if (data.getAdditionFormula() != null && data.getAdditionFormula().getFormulaData() != null) { + String formula = data.getAdditionFormula().getFormulaData().getFormulaValue(); + Assertions.assertNotNull(formula); + log.info("additionFormula: {}", formula); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + log.info("All formula data analysed"); + } +} diff --git a/fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaDataTest.java b/fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaDataTest.java new file mode 100644 index 000000000..1643025d1 --- /dev/null +++ b/fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaDataTest.java @@ -0,0 +1,46 @@ +/* + * 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.fesod.sheet.formula; + +import java.io.File; +import org.apache.fesod.sheet.FastExcel; +import org.apache.fesod.sheet.util.TestFileUtil; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +/** + * Test for shared formula reading + */ +public class FormulaDataTest { + + private static File file07; + + @BeforeAll + public static void init() { + file07 = TestFileUtil.readFile("formula" + File.separator + "shared_formula.xlsx"); + } + + @Test + public void t01ReadSharedFormula07() throws Exception { + FastExcel.read(file07, FormulaData.class, new FormulaDataListener()) + .sheet() + .doRead(); + } +} diff --git a/fesod/src/test/resources/formula/shared_formula.xlsx b/fesod/src/test/resources/formula/shared_formula.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c1f5fa44e4bb479f3eb455aeb2bbb80ad137ae45 GIT binary patch literal 12432 zcmeHtbx<7Zv-V=ao!}N+g9mqacXzkNCBY>~@SuUArTiwIR-e1gH8800&+FpY8wf3UtSh*>y4^^d84uA*q(3BRVAIz3=q1 z?L)LY0ITZGMYTlh@#|O|L-b*lC4f=1Ocb+SJHDTfyh2#Q`}y-=zGDe+Y?FCsw~AAmq?2U}YLb|>an@9Ljo-oefpV1U){XL_LgAaRZ4?y09AM&?A} z7@-aE_3~IgYdeh=RiLF$fM9{MUH*^-UkRJDbf?HwCoubn+Gj6A(}B=37P0~VJ0nfX zPCDf)7{x9}jT*M4iI}|c8607jZHxlxmQA?q;_|wcftsXq*6F?#5Z|7kApi=0b6Rx0 zR#R}0)2@Jg5+3BV`an|~Cx+KQKL6va|A#&Fw?{9Dm6e8ILJ2PWk$h=ZmF=F5;^m6=Q54oc&1|YktyB83 zp#d5-4k#9RAkpbZVpFtVe900?vzhtzk}s@eEi3Rf`Li#!i?~{kKkpYEOAd_$Ahy

Avo^KJ7RcG+^vAy4~(TvFQTJdx38&70_Xp}ljq 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 G{Q7@nj% Date: Mon, 17 Nov 2025 08:57:35 +0000 Subject: [PATCH 2/6] refactor: Revert unnecessary formatting to keep diff clean --- .../v07/handlers/CellFormulaTagHandler.java | 260 +++++++++--------- .../sheet/constant/ExcelXmlConstants.java | 256 ++++++++--------- .../holder/xlsx/XlsxReadSheetHolder.java | 220 +++++++-------- 3 files changed, 368 insertions(+), 368 deletions(-) diff --git a/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java b/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java index b7d36e95b..e2305c507 100644 --- a/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java +++ b/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java @@ -1,130 +1,130 @@ -/* - * 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.fesod.sheet.analysis.v07.handlers; - -import org.apache.fesod.sheet.constant.ExcelXmlConstants; -import org.apache.fesod.sheet.context.xlsx.XlsxReadContext; -import org.apache.fesod.sheet.metadata.data.FormulaData; -import org.apache.fesod.sheet.read.metadata.holder.xlsx.XlsxReadSheetHolder; -import org.apache.fesod.sheet.util.StringUtils; -import org.apache.poi.ss.SpreadsheetVersion; -import org.apache.poi.ss.formula.FormulaParser; -import org.apache.poi.ss.formula.FormulaRenderer; -import org.apache.poi.ss.formula.FormulaType; -import org.apache.poi.ss.formula.SharedFormula; -import org.apache.poi.ss.formula.ptg.Ptg; -import org.xml.sax.Attributes; - -/** - * Cell Handler - * - */ -public class CellFormulaTagHandler extends AbstractXlsxTagHandler { - - @Override - public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { - XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); - xlsxReadSheetHolder.setTempFormula(new StringBuilder()); - - String formulaType = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_T); - String sharedIndex = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_SI); - - xlsxReadSheetHolder.setTempFormulaType(formulaType); - xlsxReadSheetHolder.setTempFormulaSharedIndex(sharedIndex != null ? Integer.parseInt(sharedIndex) : null); - } - - @Override - public void endElement(XlsxReadContext xlsxReadContext, String name) { - XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); - String formulaText = xlsxReadSheetHolder.getTempFormula().toString(); - String formulaType = xlsxReadSheetHolder.getTempFormulaType(); - Integer sharedIndex = xlsxReadSheetHolder.getTempFormulaSharedIndex(); - - if (ExcelXmlConstants.ATTRIBUTE_SHARED.equals(formulaType) && sharedIndex != null) { - formulaText = handleSharedFormula(xlsxReadSheetHolder, formulaText, sharedIndex); - } - - FormulaData formulaData = new FormulaData(); - formulaData.setFormulaValue(formulaText); - xlsxReadSheetHolder.getTempCellData().setFormulaData(formulaData); - } - - @Override - public void characters(XlsxReadContext xlsxReadContext, char[] ch, int start, int length) { - xlsxReadContext.xlsxReadSheetHolder().getTempFormula().append(ch, start, length); - } - - /** - * Handles shared formula when reading from Excel - */ - private String handleSharedFormula(XlsxReadSheetHolder xlsxReadSheetHolder, String formulaText, int sharedIndex) { - Integer currentRow = xlsxReadSheetHolder.getRowIndex(); - Integer currentCol = xlsxReadSheetHolder.getColumnIndex(); - - if (currentRow == null || currentCol == null) { - return formulaText; - } - - // If formula text exists then this is the master cell - if (!StringUtils.isEmpty(formulaText)) { - xlsxReadSheetHolder - .getSharedFormulaMap() - .put(sharedIndex, new XlsxReadSheetHolder.SharedFormulaInfo(formulaText, currentRow, currentCol)); - return formulaText; - } else { - // No formula text means this is a shared reference cell - XlsxReadSheetHolder.SharedFormulaInfo masterInfo = - xlsxReadSheetHolder.getSharedFormulaMap().get(sharedIndex); - - if (masterInfo == null) { - return ""; - } - - return convertSharedFormula(masterInfo, currentRow, currentCol); - } - } - - /** - * Converts shared formula based on row and column offset - */ - private String convertSharedFormula( - XlsxReadSheetHolder.SharedFormulaInfo masterInfo, int currentRow, int currentCol) { - try { - // Parse the master formula text into tokens - Ptg[] masterPtgs = FormulaParser.parse(masterInfo.getFormulaText(), null, FormulaType.CELL, 0); - - // Calculate offset from the master cell position - int rowOffset = currentRow - masterInfo.getFirstRow(); - int colOffset = currentCol - masterInfo.getFirstCol(); - - // Use POI SharedFormula to convert with offset - SharedFormula sharedFormula = new SharedFormula(SpreadsheetVersion.EXCEL2007); - Ptg[] convertedPtgs = sharedFormula.convertSharedFormulas(masterPtgs, rowOffset, colOffset); - - // Convert tokens back to formula string - return FormulaRenderer.toFormulaString(null, convertedPtgs); - } catch (Exception e) { - // If conversion fails, return the master formula as-is - // This handles cases like volatile functions with no cell references - // where the formula should be identical across all cells anyway - return masterInfo.getFormulaText(); - } - } -} +/* + * 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.fesod.sheet.analysis.v07.handlers; + +import org.apache.fesod.sheet.constant.ExcelXmlConstants; +import org.apache.fesod.sheet.context.xlsx.XlsxReadContext; +import org.apache.fesod.sheet.metadata.data.FormulaData; +import org.apache.fesod.sheet.read.metadata.holder.xlsx.XlsxReadSheetHolder; +import org.apache.fesod.sheet.util.StringUtils; +import org.apache.poi.ss.formula.FormulaParser; +import org.apache.poi.ss.formula.FormulaRenderer; +import org.apache.poi.ss.formula.FormulaType; +import org.apache.poi.ss.formula.SharedFormula; +import org.apache.poi.ss.formula.ptg.Ptg; +import org.apache.poi.ss.SpreadsheetVersion; +import org.xml.sax.Attributes; + +/** + * Cell Handler + * + */ +public class CellFormulaTagHandler extends AbstractXlsxTagHandler { + + @Override + public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { + XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); + xlsxReadSheetHolder.setTempFormula(new StringBuilder()); + + String formulaType = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_T); + String sharedIndex = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_SI); + + xlsxReadSheetHolder.setTempFormulaType(formulaType); + xlsxReadSheetHolder.setTempFormulaSharedIndex(sharedIndex != null ? Integer.parseInt(sharedIndex) : null); + } + + @Override + public void endElement(XlsxReadContext xlsxReadContext, String name) { + XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); + String formulaText = xlsxReadSheetHolder.getTempFormula().toString(); + String formulaType = xlsxReadSheetHolder.getTempFormulaType(); + Integer sharedIndex = xlsxReadSheetHolder.getTempFormulaSharedIndex(); + + if (ExcelXmlConstants.ATTRIBUTE_SHARED.equals(formulaType) && sharedIndex != null) { + formulaText = handleSharedFormula(xlsxReadSheetHolder, formulaText, sharedIndex); + } + + FormulaData formulaData = new FormulaData(); + formulaData.setFormulaValue(formulaText); + xlsxReadSheetHolder.getTempCellData().setFormulaData(formulaData); + } + + @Override + public void characters(XlsxReadContext xlsxReadContext, char[] ch, int start, int length) { + xlsxReadContext.xlsxReadSheetHolder().getTempFormula().append(ch, start, length); + } + + /** + * Handles shared formula when reading from Excel + */ + private String handleSharedFormula(XlsxReadSheetHolder xlsxReadSheetHolder, String formulaText, int sharedIndex) { + Integer currentRow = xlsxReadSheetHolder.getRowIndex(); + Integer currentCol = xlsxReadSheetHolder.getColumnIndex(); + + if (currentRow == null || currentCol == null) { + return formulaText; + } + + // If formula text exists then this is the master cell + if (!StringUtils.isEmpty(formulaText)) { + xlsxReadSheetHolder + .getSharedFormulaMap() + .put(sharedIndex, new XlsxReadSheetHolder.SharedFormulaInfo(formulaText, currentRow, currentCol)); + return formulaText; + } else { + // No formula text means this is a shared reference cell + XlsxReadSheetHolder.SharedFormulaInfo masterInfo = + xlsxReadSheetHolder.getSharedFormulaMap().get(sharedIndex); + + if (masterInfo == null) { + return ""; + } + + return convertSharedFormula(masterInfo, currentRow, currentCol); + } + } + + /** + * Converts shared formula based on row and column offset + */ + private String convertSharedFormula( + XlsxReadSheetHolder.SharedFormulaInfo masterInfo, int currentRow, int currentCol) { + try { + // Parse the master formula text into tokens + Ptg[] masterPtgs = FormulaParser.parse(masterInfo.getFormulaText(), null, FormulaType.CELL, 0); + + // Calculate offset from the master cell position + int rowOffset = currentRow - masterInfo.getFirstRow(); + int colOffset = currentCol - masterInfo.getFirstCol(); + + // Use POI SharedFormula to convert with offset + SharedFormula sharedFormula = new SharedFormula(SpreadsheetVersion.EXCEL2007); + Ptg[] convertedPtgs = sharedFormula.convertSharedFormulas(masterPtgs, rowOffset, colOffset); + + // Convert tokens back to formula string + return FormulaRenderer.toFormulaString(null, convertedPtgs); + } catch (Exception e) { + // If conversion fails, return the master formula as-is + // This handles cases like volatile functions with no cell references + // where the formula should be identical across all cells anyway + return masterInfo.getFormulaText(); + } + } +} diff --git a/fesod/src/main/java/org/apache/fesod/sheet/constant/ExcelXmlConstants.java b/fesod/src/main/java/org/apache/fesod/sheet/constant/ExcelXmlConstants.java index 3c4ae2b66..0d7163ef0 100644 --- a/fesod/src/main/java/org/apache/fesod/sheet/constant/ExcelXmlConstants.java +++ b/fesod/src/main/java/org/apache/fesod/sheet/constant/ExcelXmlConstants.java @@ -1,128 +1,128 @@ -/* - * 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.fesod.sheet.constant; - -/** - * - */ -public class ExcelXmlConstants { - public static final String DIMENSION_TAG = "dimension"; - public static final String ROW_TAG = "row"; - public static final String CELL_FORMULA_TAG = "f"; - public static final String CELL_VALUE_TAG = "v"; - /** - * When the data is "inlineStr" his tag is "t" - */ - public static final String CELL_INLINE_STRING_VALUE_TAG = "t"; - - public static final String CELL_TAG = "c"; - public static final String MERGE_CELL_TAG = "mergeCell"; - public static final String HYPERLINK_TAG = "hyperlink"; - - public static final String X_DIMENSION_TAG = "x:dimension"; - public static final String NS2_DIMENSION_TAG = "ns2:dimension"; - - public static final String X_ROW_TAG = "x:row"; - public static final String NS2_ROW_TAG = "ns2:row"; - - public static final String X_CELL_FORMULA_TAG = "x:f"; - public static final String NS2_CELL_FORMULA_TAG = "ns2:f"; - public static final String X_CELL_VALUE_TAG = "x:v"; - public static final String NS2_CELL_VALUE_TAG = "ns2:v"; - - /** - * When the data is "inlineStr" his tag is "t" - */ - public static final String X_CELL_INLINE_STRING_VALUE_TAG = "x:t"; - - public static final String NS2_CELL_INLINE_STRING_VALUE_TAG = "ns2:t"; - - public static final String X_CELL_TAG = "x:c"; - public static final String NS2_CELL_TAG = "ns2:c"; - public static final String X_MERGE_CELL_TAG = "x:mergeCell"; - public static final String NS2_MERGE_CELL_TAG = "ns2:mergeCell"; - public static final String X_HYPERLINK_TAG = "x:hyperlink"; - public static final String NS2_HYPERLINK_TAG = "ns2:hyperlink"; - - /** - * s attribute - */ - public static final String ATTRIBUTE_S = "s"; - /** - * ref attribute - */ - public static final String ATTRIBUTE_REF = "ref"; - /** - * r attribute - */ - public static final String ATTRIBUTE_R = "r"; - /** - * t attribute - */ - public static final String ATTRIBUTE_T = "t"; - /** - * si attribute - */ - public static final String ATTRIBUTE_SI = "si"; - /** - * shared attribute - */ - public static final String ATTRIBUTE_SHARED = "shared"; - /** - * location attribute - */ - public static final String ATTRIBUTE_LOCATION = "location"; - - /** - * rId attribute - */ - public static final String ATTRIBUTE_RID = "r:id"; - - /** - * Cell range split - */ - public static final String CELL_RANGE_SPLIT = ":"; - - // The following is a constant read the `SharedStrings.xml` - - /** - * text - */ - public static final String SHAREDSTRINGS_T_TAG = "t"; - - public static final String SHAREDSTRINGS_X_T_TAG = "x:t"; - public static final String SHAREDSTRINGS_NS2_T_TAG = "ns2:t"; - - /** - * SharedStringItem - */ - public static final String SHAREDSTRINGS_SI_TAG = "si"; - - public static final String SHAREDSTRINGS_X_SI_TAG = "x:si"; - public static final String SHAREDSTRINGS_NS2_SI_TAG = "ns2:si"; - - /** - * Mac 2016 2017 will have this extra field to ignore - */ - public static final String SHAREDSTRINGS_RPH_TAG = "rPh"; - - public static final String SHAREDSTRINGS_X_RPH_TAG = "x:rPh"; - public static final String SHAREDSTRINGS_NS2_RPH_TAG = "ns2:rPh"; -} +/* + * 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.fesod.sheet.constant; + +/** + * + */ +public class ExcelXmlConstants { + public static final String DIMENSION_TAG = "dimension"; + public static final String ROW_TAG = "row"; + public static final String CELL_FORMULA_TAG = "f"; + public static final String CELL_VALUE_TAG = "v"; + /** + * When the data is "inlineStr" his tag is "t" + */ + public static final String CELL_INLINE_STRING_VALUE_TAG = "t"; + + public static final String CELL_TAG = "c"; + public static final String MERGE_CELL_TAG = "mergeCell"; + public static final String HYPERLINK_TAG = "hyperlink"; + + public static final String X_DIMENSION_TAG = "x:dimension"; + public static final String NS2_DIMENSION_TAG = "ns2:dimension"; + + public static final String X_ROW_TAG = "x:row"; + public static final String NS2_ROW_TAG = "ns2:row"; + + public static final String X_CELL_FORMULA_TAG = "x:f"; + public static final String NS2_CELL_FORMULA_TAG = "ns2:f"; + public static final String X_CELL_VALUE_TAG = "x:v"; + public static final String NS2_CELL_VALUE_TAG = "ns2:v"; + + /** + * When the data is "inlineStr" his tag is "t" + */ + public static final String X_CELL_INLINE_STRING_VALUE_TAG = "x:t"; + + public static final String NS2_CELL_INLINE_STRING_VALUE_TAG = "ns2:t"; + + public static final String X_CELL_TAG = "x:c"; + public static final String NS2_CELL_TAG = "ns2:c"; + public static final String X_MERGE_CELL_TAG = "x:mergeCell"; + public static final String NS2_MERGE_CELL_TAG = "ns2:mergeCell"; + public static final String X_HYPERLINK_TAG = "x:hyperlink"; + public static final String NS2_HYPERLINK_TAG = "ns2:hyperlink"; + + /** + * s attribute + */ + public static final String ATTRIBUTE_S = "s"; + /** + * ref attribute + */ + public static final String ATTRIBUTE_REF = "ref"; + /** + * r attribute + */ + public static final String ATTRIBUTE_R = "r"; + /** + * t attribute + */ + public static final String ATTRIBUTE_T = "t"; + /** + * si attribute + */ + public static final String ATTRIBUTE_SI = "si"; + /** + * shared attribute + */ + public static final String ATTRIBUTE_SHARED = "shared"; + /** + * location attribute + */ + public static final String ATTRIBUTE_LOCATION = "location"; + + /** + * rId attribute + */ + public static final String ATTRIBUTE_RID = "r:id"; + + /** + * Cell range split + */ + public static final String CELL_RANGE_SPLIT = ":"; + + // The following is a constant read the `SharedStrings.xml` + + /** + * text + */ + public static final String SHAREDSTRINGS_T_TAG = "t"; + + public static final String SHAREDSTRINGS_X_T_TAG = "x:t"; + public static final String SHAREDSTRINGS_NS2_T_TAG = "ns2:t"; + + /** + * SharedStringItem + */ + public static final String SHAREDSTRINGS_SI_TAG = "si"; + + public static final String SHAREDSTRINGS_X_SI_TAG = "x:si"; + public static final String SHAREDSTRINGS_NS2_SI_TAG = "ns2:si"; + + /** + * Mac 2016 2017 will have this extra field to ignore + */ + public static final String SHAREDSTRINGS_RPH_TAG = "rPh"; + + public static final String SHAREDSTRINGS_X_RPH_TAG = "x:rPh"; + public static final String SHAREDSTRINGS_NS2_RPH_TAG = "ns2:rPh"; +} diff --git a/fesod/src/main/java/org/apache/fesod/sheet/read/metadata/holder/xlsx/XlsxReadSheetHolder.java b/fesod/src/main/java/org/apache/fesod/sheet/read/metadata/holder/xlsx/XlsxReadSheetHolder.java index 69f8c168a..c5f9cb685 100644 --- a/fesod/src/main/java/org/apache/fesod/sheet/read/metadata/holder/xlsx/XlsxReadSheetHolder.java +++ b/fesod/src/main/java/org/apache/fesod/sheet/read/metadata/holder/xlsx/XlsxReadSheetHolder.java @@ -1,110 +1,110 @@ -/* - * 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.fesod.sheet.read.metadata.holder.xlsx; - -import java.util.Deque; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; -import org.apache.fesod.sheet.read.metadata.ReadSheet; -import org.apache.fesod.sheet.read.metadata.holder.ReadSheetHolder; -import org.apache.fesod.sheet.read.metadata.holder.ReadWorkbookHolder; -import org.apache.poi.openxml4j.opc.PackageRelationshipCollection; - -/** - * sheet holder - * - * - */ -@Getter -@Setter -@EqualsAndHashCode -public class XlsxReadSheetHolder extends ReadSheetHolder { - /** - * Record the label of the current operation to prevent NPE. - */ - private Deque tagDeque; - /** - * Current Column - */ - private Integer columnIndex; - /** - * Data for current label. - */ - private StringBuilder tempData; - /** - * Formula for current label. - */ - private StringBuilder tempFormula; - /** - * Formula type for current label. - */ - private String tempFormulaType; - /** - * Shared formula index for current label. - */ - private Integer tempFormulaSharedIndex; - /** - * Map to store master shared formulas by their shared index. - */ - private Map sharedFormulaMap; - /** - * excel Relationship - */ - private PackageRelationshipCollection packageRelationshipCollection; - - public XlsxReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) { - super(readSheet, readWorkbookHolder); - this.tagDeque = new LinkedList(); - this.sharedFormulaMap = new HashMap<>(); - packageRelationshipCollection = ((XlsxReadWorkbookHolder) readWorkbookHolder) - .getPackageRelationshipCollectionMap() - .get(readSheet.getSheetNo()); - } - - /** - * Information about a shared formula master cell. - */ - @Getter - @Setter - public static class SharedFormulaInfo { - /** - * The master formula text. - */ - private String formulaText; - /** - * Row index of the master formula cell. - */ - private int firstRow; - /** - * Column index of the master formula cell. - */ - private int firstCol; - - public SharedFormulaInfo(String formulaText, int firstRow, int firstCol) { - this.formulaText = formulaText; - this.firstRow = firstRow; - this.firstCol = firstCol; - } - } -} +/* + * 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.fesod.sheet.read.metadata.holder.xlsx; + +import java.util.Deque; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import org.apache.fesod.sheet.read.metadata.ReadSheet; +import org.apache.fesod.sheet.read.metadata.holder.ReadSheetHolder; +import org.apache.fesod.sheet.read.metadata.holder.ReadWorkbookHolder; +import org.apache.poi.openxml4j.opc.PackageRelationshipCollection; + +/** + * sheet holder + * + * + */ +@Getter +@Setter +@EqualsAndHashCode +public class XlsxReadSheetHolder extends ReadSheetHolder { + /** + * Record the label of the current operation to prevent NPE. + */ + private Deque tagDeque; + /** + * Current Column + */ + private Integer columnIndex; + /** + * Data for current label. + */ + private StringBuilder tempData; + /** + * Formula for current label. + */ + private StringBuilder tempFormula; + /** + * Formula type for current label. + */ + private String tempFormulaType; + /** + * Formula shared index for current label. + */ + private Integer tempFormulaSharedIndex; + /** + * Map to store master shared formulas by their shared index. + */ + private Map sharedFormulaMap; + /** + * excel Relationship + */ + private PackageRelationshipCollection packageRelationshipCollection; + + public XlsxReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) { + super(readSheet, readWorkbookHolder); + this.tagDeque = new LinkedList(); + this.sharedFormulaMap = new HashMap<>(); + packageRelationshipCollection = ((XlsxReadWorkbookHolder) readWorkbookHolder) + .getPackageRelationshipCollectionMap() + .get(readSheet.getSheetNo()); + } + + /** + * Information about a shared formula master cell. + */ + @Getter + @Setter + public static class SharedFormulaInfo { + /** + * The master formula text. + */ + private String formulaText; + /** + * Row index of the master formula cell. + */ + private int firstRow; + /** + * Column index of the master formula cell. + */ + private int firstCol; + + public SharedFormulaInfo(String formulaText, int firstRow, int firstCol) { + this.formulaText = formulaText; + this.firstRow = firstRow; + this.firstCol = firstCol; + } + } +} From 6c87bba69228029f4ebbbd88053464404c7a0692 Mon Sep 17 00:00:00 2001 From: ongdisheng Date: Mon, 17 Nov 2025 09:53:08 +0000 Subject: [PATCH 3/6] style: Fix spotless violations --- .../sheet/analysis/v07/handlers/CellFormulaTagHandler.java | 2 +- .../org/apache/fesod/sheet/formula/FormulaDataListener.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java b/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java index e2305c507..4a29aefea 100644 --- a/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java +++ b/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java @@ -24,12 +24,12 @@ import org.apache.fesod.sheet.metadata.data.FormulaData; import org.apache.fesod.sheet.read.metadata.holder.xlsx.XlsxReadSheetHolder; import org.apache.fesod.sheet.util.StringUtils; +import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.formula.FormulaParser; import org.apache.poi.ss.formula.FormulaRenderer; import org.apache.poi.ss.formula.FormulaType; import org.apache.poi.ss.formula.SharedFormula; import org.apache.poi.ss.formula.ptg.Ptg; -import org.apache.poi.ss.SpreadsheetVersion; import org.xml.sax.Attributes; /** diff --git a/fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaDataListener.java b/fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaDataListener.java index 2e55e9508..1dbf69e50 100644 --- a/fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaDataListener.java +++ b/fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaDataListener.java @@ -45,13 +45,15 @@ public void invoke(FormulaData data, AnalysisContext context) { log.info("relativeFormula: {}", formula); } - if (data.getColumnAbsoluteFormula() != null && data.getColumnAbsoluteFormula().getFormulaData() != null) { + if (data.getColumnAbsoluteFormula() != null + && data.getColumnAbsoluteFormula().getFormulaData() != null) { String formula = data.getColumnAbsoluteFormula().getFormulaData().getFormulaValue(); Assertions.assertNotNull(formula); log.info("columnAbsoluteFormula: {}", formula); } - if (data.getMixedAbsoluteFormula() != null && data.getMixedAbsoluteFormula().getFormulaData() != null) { + if (data.getMixedAbsoluteFormula() != null + && data.getMixedAbsoluteFormula().getFormulaData() != null) { String formula = data.getMixedAbsoluteFormula().getFormulaData().getFormulaValue(); Assertions.assertNotNull(formula); log.info("mixedAbsoluteFormula: {}", formula); From 333b212e8298db38998e3903bd2ce19b0a22ef94 Mon Sep 17 00:00:00 2001 From: ongdisheng Date: Mon, 17 Nov 2025 17:24:02 +0000 Subject: [PATCH 4/6] fix: Add logging based on Copilot suggestions --- .../analysis/v07/handlers/CellFormulaTagHandler.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java b/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java index 4a29aefea..3d74c6995 100644 --- a/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java +++ b/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java @@ -19,6 +19,7 @@ package org.apache.fesod.sheet.analysis.v07.handlers; +import lombok.extern.slf4j.Slf4j; import org.apache.fesod.sheet.constant.ExcelXmlConstants; import org.apache.fesod.sheet.context.xlsx.XlsxReadContext; import org.apache.fesod.sheet.metadata.data.FormulaData; @@ -36,6 +37,7 @@ * Cell Handler * */ +@Slf4j public class CellFormulaTagHandler extends AbstractXlsxTagHandler { @Override @@ -94,6 +96,11 @@ private String handleSharedFormula(XlsxReadSheetHolder xlsxReadSheetHolder, Stri xlsxReadSheetHolder.getSharedFormulaMap().get(sharedIndex); if (masterInfo == null) { + log.debug( + "Master formula not found for shared index {} at row {}, col {}", + sharedIndex, + currentRow, + currentCol); return ""; } @@ -124,6 +131,10 @@ private String convertSharedFormula( // If conversion fails, return the master formula as-is // This handles cases like volatile functions with no cell references // where the formula should be identical across all cells anyway + log.warn( + "Failed to convert shared formula at row {}, col {}. Using master formula instead.", + currentRow, + currentCol); return masterInfo.getFormulaText(); } } From 369cb700966cd2b7fcd55545957c43dce9334a72 Mon Sep 17 00:00:00 2001 From: ongdisheng Date: Tue, 18 Nov 2025 10:45:45 +0000 Subject: [PATCH 5/6] fix: Replace logging debug level to warn --- .../sheet/analysis/v07/handlers/CellFormulaTagHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java b/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java index 3d74c6995..43d87e1e7 100644 --- a/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java +++ b/fesod/src/main/java/org/apache/fesod/sheet/analysis/v07/handlers/CellFormulaTagHandler.java @@ -96,7 +96,7 @@ private String handleSharedFormula(XlsxReadSheetHolder xlsxReadSheetHolder, Stri xlsxReadSheetHolder.getSharedFormulaMap().get(sharedIndex); if (masterInfo == null) { - log.debug( + log.warn( "Master formula not found for shared index {} at row {}, col {}", sharedIndex, currentRow, From 5f0b5526621cbfa2cdcd9765233a26f077699c3a Mon Sep 17 00:00:00 2001 From: ongdisheng Date: Thu, 20 Nov 2025 18:08:44 +0000 Subject: [PATCH 6/6] refactor: Update FormulaDataTest to use FesodSheet --- .../java/org/apache/fesod/sheet/formula/FormulaDataTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaDataTest.java b/fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaDataTest.java index 1643025d1..fe388f5fc 100644 --- a/fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaDataTest.java +++ b/fesod/src/test/java/org/apache/fesod/sheet/formula/FormulaDataTest.java @@ -20,7 +20,7 @@ package org.apache.fesod.sheet.formula; import java.io.File; -import org.apache.fesod.sheet.FastExcel; +import org.apache.fesod.sheet.FesodSheet; import org.apache.fesod.sheet.util.TestFileUtil; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -39,7 +39,7 @@ public static void init() { @Test public void t01ReadSharedFormula07() throws Exception { - FastExcel.read(file07, FormulaData.class, new FormulaDataListener()) + FesodSheet.read(file07, FormulaData.class, new FormulaDataListener()) .sheet() .doRead(); }