2

カスタム関数を FormulaEvaluatorに登録する方法に関するApache POIの Web サイトのチュートリアルを読み、それを使用して、POI がサポートしていない関数 MINVERSE を定義したいと考えました。そこで、最初に MINVERSE を定義するクラスを作成しました (テストのみを目的として、常に値 10 を返すように MINVERSE を定義しました)。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 シートを作成しました。

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

助言がありますか?よろしくお願いします!

4

3 に答える 3

3

これまで見てきたカスタム関数のチュートリアルは、実際のカスタム関数のみを対象としています。まだ POI が実装されていない組み込みの Excel 関数をオーバーライドすることはできません。

org/apache/poi/ss/formula/function/functionMetadata.txtを見ると、ファイル形式で定義されている組み込みの Excel 関数のリストが表示されます。そのリストにあるものは、ファイル形式で異なる方法で保存されるため、カスタム関数としてオーバーライドすることはできません。(確かに、.xls ファイルの場合、.xlsx は少し異なります)。そのファイルを見ながら、関数の ID を書き留めます。

数式関数が組み込み関数である場合は、FunctionEvalを確認する必要があります。getNotSupportedFunctionNames()を使用するか、コードを調べて、関数がまだ実装されているかどうかを確認できます。(配列は、functionMetadata.txt から取得した関数 ID によってインデックス付けされます)

関数が実装されていない場合は、POI ソース コードを取得する必要があります。

  • 関数の実装をどこかに追加します
  • 正しい ID を使用して FunctionEval の関数を一覧表示する
  • テスト (POI フォーミュラ テストを使用すると役立ちます)
  • パッチとして提出してください!詳細については、POI 投稿ガイドラインを参照してください。

パッチが提出された直後に、POI に不足している機能が含まれ、コミュニティがそれを維持するのを手伝ってくれるので、あなたは前進することができます :)

于 2012-04-24T21:35:48.327 に答える
2

このチュートリアルは、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)

必要な機能を提供するためにオーバーライドする必要があるもの。データの領域を受け入れ、領域も返す関数を処理する方法はまだ明確ではありません (ベクトル/配列ではありません)。私はそれについて新しい質問を始めます...

于 2012-04-25T08:10:27.507 に答える
0

理由はわかりませんが、ワークシートに関数定義を含むVBAコード(空でもかまいません)を配置する必要があります-関数をモジュールに配置します。

Function MINVERSE(principal As Double)
End Function
于 2012-04-24T14:16:22.567 に答える