【问题标题】:Dynamically add External (Cross-Workbook) references动态添加外部(跨工作簿)引用
【发布时间】:2015-09-03 08:09:44
【问题描述】:

在我们的项目中,我们有不同版本的 excelsheets 相互引用:

C:\V1\Sample.xls //没有引用

C:\V2\Sample.xls //引用 V1

C:\V3\Sample.xls //引用 V2

单元格值示例:

=MID('C:\V1\[Sample.xls]Sheet1'!$AB2;21;1)

现在我想使用apache POI评估V3的公式,我找到了以下示例here

// Create a FormulaEvaluator to use
FormulaEvaluator mainWorkbookEvaluator = workbook.getCreationHelper().createFormulaEvaluator();

// Track the workbook references
Map<String,FormulaEvaluator> workbooks = new HashMap<String, FormulaEvaluator>();
// Add this workbook
workbooks.put("report.xlsx", mainWorkbookEvaluator);
// Add two others
workbooks.put("input.xls", WorkbookFactory.create("c:\temp\input22.xls").getCreationHelper().createFormulaEvaluator());
workbooks.put("lookups.xlsx", WorkbookFactory.create("/home/poi/data/tmp-lookups.xlsx").getCreationHelper().createFormulaEvaluator());

// Attach them
mainWorkbookEvaluator.setupReferencedWorkbooks(workbooks);

// Evaluate
mainWorkbookEvaluator.evaluateAll();

现在我的问题:我不知道文件的位置,因此我需要从 mainworkbook 获取所有引用,然后自动(并且可能递归地)添加它们,而不是像在上面的例子。是否有获取参考的功能,或者有人知道实现此目的的方法吗?

另外,我想知道是否必须将所有 FormulaEvaluator 添加到 V3,还是必须将 V2 添加到 V3 和 V1 到 V2 才能工作?

我目前已经实现了 setIgnoreMissingWorkbooks(true),但是由于值会改变,我们不想手动打开每个 excel 文件来更新我想要实现这个解决方案的引用。任何帮助表示赞赏

【问题讨论】:

    标签: java excel apache-poi cross-reference


    【解决方案1】:

    要获取所有外部引用,请使用以下方法:

    private static Set<String> getReferencedWorkbooks(Workbook workbook) {
        Set<String> workbookNames = new HashSet<>();
        final EvaluationWorkbook evalWorkbook;
        if (workbook instanceof HSSFWorkbook) {
            evalWorkbook = HSSFEvaluationWorkbook.create((HSSFWorkbook) workbook);
        } else if (workbook instanceof XSSFWorkbook) {
            evalWorkbook = XSSFEvaluationWorkbook.create((XSSFWorkbook) workbook);
        } else {
            throw new IllegalStateException();
        }
        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
            Sheet sheet = workbook.getSheetAt(i);
            final EvaluationSheet evalSheet = evalWorkbook.getSheet(i);
            for (Row r : sheet) {
                for (Cell c : r) {
                    if (c.getCellType() == HSSFCell.CELL_TYPE_FORMULA) {
                        final EvaluationCell cell = evalSheet.getCell(c.getRowIndex(), c.getColumnIndex());
                        final Ptg[] formulaTokens = evalWorkbook.getFormulaTokens(cell);
                        for (Ptg formulaToken : formulaTokens) {
                            final int externalSheetIndex;
                            if (formulaToken instanceof Ref3DPtg) {
                                Ref3DPtg refToken = (Ref3DPtg) formulaToken;
                                externalSheetIndex = refToken.getExternSheetIndex();
                            } else if (formulaToken instanceof Ref3DPxg) {
                                Ref3DPxg refToken = (Ref3DPxg) formulaToken;
                                externalSheetIndex = refToken.getExternalWorkbookNumber();
                            } else {
                                externalSheetIndex = -1;
                            }
    
                            if (externalSheetIndex >= 0) {
                                final ExternalSheet externalSheet = evalWorkbook.getExternalSheet(externalSheetIndex);
                                workbookNames.add(externalSheet.getWorkbookName());
                            }
                        }
                    }
                }
            }
        }
        return workbookNames;
    }
    

    如果您所有的工作簿都是 XLSX/XLSM,您可以使用以下代码:

    private static Set<String> getReferencedWorkbooksXssf(XSSFWorkbook workbook) {
        Set<String> workbookNames = new HashSet<>();
        final List<ExternalLinksTable> externalLinksTable = workbook.getExternalLinksTable();
        for (ExternalLinksTable linksTable : externalLinksTable) {
            final String linkedFileName = linksTable.getLinkedFileName();
            workbookNames.add(linkedFileName);
        }
    
        return workbookNames;
    }
    

    【讨论】:

    • 我认为您可能误解了我的问题。我没有设置引用的工作簿,因为程序是动态的,因此我不知道工作簿的引用。我的问题是是否有办法获取引用的工作簿以便我可以附上它们
    • 也许您指的是我的第一个答案? getReferencedWorkbooks 方法将返回一组被引用的工作簿。例如。对于 C:\V2\Sample.xls 它将返回 [V1]
    • 是的,这是你的第一个答案,我会检查你的脚本 :)
    • 我在 externalSheet.getWorkbookName() 中得到了很多空值,所以我将它们排除在外。如果驱动器号与 Mainworkbook 相同(Giving: \V​​2\Sample.xls ),它也会削减驱动器号,但 java.io.File 没有问题。实际上非常复杂,但可能是唯一可行的方法
    • 感谢您附加 XSSF only 方法,但实际上恰恰相反,所以我的工作簿是 XLS
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-01
    • 1970-01-01
    相关资源
    最近更新 更多