Apache的POI - 如何注册功能(Apache POI - How to register

2019-06-23 22:23发布

我读的Apache POI对网站上的教程如何注册自定义函数为FormulaEvaluator,我想用它来定义函数MINVERSE针对POI不提供支持。 因此,首先在I创建了一个类,定义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表:

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

有什么建议? 非常感谢提前!

Answer 1:

你一直在寻找的自定义功能教程仅适用于真正的自定义函数。 它不会让你重写没有POI实现尚未内置Excel函数

如果你看一下组织/阿帕奇/ POI / SS /公式/功能/ functionMetadata.txt你会看到列表中内置的文件格式定义Excel函数。 凡是在该列表中不能被覆写为自定义函数,因为他们得到存储在不同的文件格式。 (嗯,当然,对于.xls文件,.XLSX稍有不同)。 虽然看着那个文件,记下您的功能的ID。

如果您的公式函数是一个内置的一个,那么你应该看看FunctionEval 。 您可以使用getNotSupportedFunctionNames()或只是看看代码,看看该功能尚未实现。 (该阵列由功能ID,您从functionMetadata.txt得到索引)

如果您的功能没有实现,你需要抓住POI源代码,并:

  • 添加在您的函数实现的地方
  • 在FunctionEval功能用正确的ID列表
  • 测试(可以使用POI公式测试帮助)
  • 提交它作为一个补丁! 见POI贡献的指导方针的细节

你的补丁提交后不久,然后POI将包括丢失的功能,和社区将有助于保持它,你就赢了前进:)



Answer 2:

本教程是关于如何重写使用Java类Excel的侧定义的自定义功能。 为了覆盖现有的Excel函数为其POI不提供你需要把它注册到FunctionEval支持。 这是简单的:

FunctionEval.registerFunction("MINVERSE", new Minverse());

(但它变得很困难,因为缺乏适当的文件)。 类MINVERSE应实现的接口org.apache.poi.ss.formula.functions.Function或延长一些抽象类相同的包的。

Function定义了方法:

public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex)

其中一个需要重写,以提供期望的功能。 它是不是还清楚,我如何处理与承认数据的领域,并返回区域(未矢量/阵列)功能。 我将开始一个新的问题...



Answer 3:

我不知道为什么,但你必须把VBA代码函数的定义(甚至可以是空的)在工作表 - 把功能模块。

Function MINVERSE(principal As Double)
End Function


文章来源: Apache POI - How to register a function