java - Apache POI - 如何注册一个函数

标签 java excel apache-poi

我在how to register custom functions上阅读了Apache POI网站上的教程。到 FormulaEvaluator 中,我想用它来定义 POI 不提供支持的函数 MINVERSE。因此,首先我创建了一个定义 MINVERSE 的类(仅出于测试目的,我将 MINVERSE 定义为始终返回值 10)。所以这是 MINVERSE.java:

package simpleboxapi;

import org.apache.poi.ss.formula.OperationEvaluationContext;
import org.apache.poi.ss.formula.eval.NumberEval;
import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.functions.FreeRefFunction;

public class MINVERSE implements FreeRefFunction{

    @Override
    public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
        return new NumberEval(10);
    }
}

之后我尝试了一些非常简单的方法:我创建了以下 excel 表:

Screenshot from Excel

A1 是一个给定的常量,A2 是 A2=MINVERSE(A1)

这是我的主类代码:

package simpleboxapi;

import java.io.*;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.formula.functions.FreeRefFunction;
import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
import org.apache.poi.ss.formula.udf.DefaultUDFFinder;
import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.ss.usermodel.*;


public class SimpleBoxAPI {

    static String fileName = "workbook.xls";
    static Workbook wb;

    private static double updateInputVal(String cell, double val) throws IOException, InvalidFormatException{
        InputStream inp = new FileInputStream(fileName);
        wb = WorkbookFactory.create(inp);
        CellReference crInput = new CellReference(cell);
        Sheet sheet = wb.getSheetAt(0);
        Row rowInput = sheet.getRow(crInput.getRow());
        Cell cellInput = rowInput.getCell(crInput.getCol());
        cellInput.setCellValue(val);
        FileOutputStream fileOut = new FileOutputStream(fileName);
        wb.write(fileOut);
        fileOut.close();
        double cellContents = cellInput.getNumericCellValue();
        inp.close();
        return cellContents;
    }


    private static void registerMINVERSE(){
       String[] functionNames = {"MINVERSE"};
        FreeRefFunction[] functionImpls = {new MINVERSE()};
        UDFFinder udfs = new DefaultUDFFinder(functionNames, functionImpls);
        UDFFinder udfToolpack = new AggregatingUDFFinder(udfs);
        wb.addToolPack(udfToolpack); 
    }


    public static void main(String[] args) throws Exception {

        double updatedValue = updateInputVal("A1",55);
        System.out.println(updatedValue);
        registerMINVERSE();

        FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
        CellReference cr = new CellReference("A2");
        Sheet sheet = wb.getSheetAt(0);
        Row row = sheet.getRow(cr.getRow());
        Cell cell = row.getCell(cr.getCol());
        System.out.println(evaluator.evaluate(cell).getNumberValue());
    }
}

但是,每当我尝试执行它时,我都会收到以下错误:

org.apache.poi.ss.formula.eval.NotImplementedException: Error evaluating cell 'new sheet'!A2
    at org.apache.poi.ss.formula.WorkbookEvaluator.addExceptionInfo(WorkbookEvaluator.java:356)
    at org.apache.poi.ss.formula.WorkbookEvaluator.evaluateAny(WorkbookEvaluator.java:297)
    at org.apache.poi.ss.formula.WorkbookEvaluator.evaluate(WorkbookEvaluator.java:229)
    at org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.evaluateFormulaCellValue(HSSFFormulaEvaluator.java:354)
    at org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.evaluate(HSSFFormulaEvaluator.java:185)
    at simpleboxapi.SimpleBoxAPI.main(SimpleBoxAPI.java:56)
Caused by: org.apache.poi.ss.formula.eval.NotImplementedException: MINVERSE
    at org.apache.poi.ss.formula.functions.NotImplementedFunction.evaluate(NotImplementedFunction.java:42)
    at org.apache.poi.ss.formula.OperationEvaluatorFactory.evaluate(OperationEvaluatorFactory.java:132)
    at org.apache.poi.ss.formula.WorkbookEvaluator.evaluateFormula(WorkbookEvaluator.java:491)
    at org.apache.poi.ss.formula.WorkbookEvaluator.evaluateAny(WorkbookEvaluator.java:287)
    ... 4 more

有什么建议吗?非常感谢!

最佳答案

您一直在查看的自定义函数教程仅适用于真正的自定义函数。它不会让您覆盖尚未实现 POI 的内置 Excel 函数

如果你看org/apache/poi/ss/formula/function/functionMetadata.txt您将看到以文件格式定义的内置 Excel 函数列表。该列表中的任何内容都不能作为自定义函数被覆盖,因为它们以不同的文件格式存储。 (当然,对于 .xls 文件,.xlsx 有点不同)。在查看该文件时,记下您的函数的 ID。

如果您的公式函数是内置的,那么您应该看看 FunctionEval .您可以使用 getNotSupportedFunctionNames()或者只是查看代码以查看该功能是否已实现。 (该数组由您从 functionMetadata.txt 中获得的函数 ID 索引)

如果您的功能未实现,您需要获取 POI 源代码,并且:

  • 在某处添加您的函数实现
  • 用正确的 ID 列出 FunctionEval 中的函数
  • 测试(您可以使用 POI 公式测试来帮助)
  • 将其作为补丁提交!查看POI contribution guidelines详情

提交补丁后不久,POI 将包含您缺少的功能,社区将帮助维护它,以便您继续前进:)

关于java - Apache POI - 如何注册一个函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10298512/

相关文章:

java - 在初始化中加载变量的最佳实践是什么

JAVA和JODA Date解析即使格式错误也不会抛出异常

excel - 用户定义函数的自动填充

vba - UDF 返回格式化数字

excel - 抓取网页时没有可见的标签输入用户名或密码

java - 在 Java 中将 CPLEX 的 IloNumVar 变量转换为 double

java - 如何通过单击 Java Swing 应用程序中的按钮打开 HTML 页面?

java - 有没有可用的软件或库可以用 C、C++、Java 或 Ruby 绘制 3 维螺钉?

java - 减少小程序中读取excel文件

java - 将 jfreechart 导出为 pptx 作为 EMF 图像 - 线条渲染不正确