Apache POI – 如何注册一个函数

我阅读了Apache POI网站上关于如何将自定义函数注册到FormulaEvaluator中的教程,并且我想用它来定义POI不提供支持的函数MINVERSE。 所以,首先我创build了一个定义MINVERSE的类(仅用于testing目的,我定义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); } } 

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

从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 

有什么build议么? 提前感谢!

您一直在看的自定义函数教程只用于真正的自定义函数。 它不会让你覆盖没有POI实现的内置Excel函数

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

如果你的公式函数是内置的,那么你应该看看FunctionEval 。 您可以使用getNotSupportedFunctionNames()或只查看代码,以查看函数是否已经实现。 (该数组通过函数ID进行索引,您可以从functionMetadata.txt获取该数组)

如果你的function没有实现,你需要获取POI源代码,并且:

  • 在你的函数实现的地方添加
  • 在FunctionEval中使用正确的ID列出函数
  • testing(您可以使用POI公式testing来帮助)
  • 将其作为补丁提交! 有关详细信息,请参阅兴趣点贡献准则

你的补丁提交后不久,POI将包括你的缺失function,社区将帮助你保持它,让你赢得前进:)

本教程将介绍如何使用Java类来重写在Excel端定义的自定义函数。 为了覆盖POI不提供支持的现有Excel函数,您需要将其注册到FunctionEval。 这很简单:

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

(但由于缺乏适当的文件而变得困难)。 Minverse类应该实现org.apache.poi.ss.formula.functions.Function接口,或者扩展同一个包的一些抽象类。

Function定义方法:

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

哪一个需要重写以提供所需的function。 我不清楚如何处理接受数据领域的函数,还返回区域(而不是向量/数组)。 我会就这个开始一个新的问题

我不是为什么,但你必须把VBA代码的function定义(甚至可以是空的)在工作表中 – 把function放在模块中。

 Function MINVERSE(principal As Double) End Function