Bläddra i källkod

improved work with UDFs and Analysis Toolpack functions, ATP functions are enabled by default and user can create / evaluate them just like built-in functions, both HSSF andf XSSF are supported

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1039870 13f79535-47bb-0310-9956-ffa450edef68
tags/REL_3_8_BETA1
Yegor Kozlov 13 år sedan
förälder
incheckning
db89d09ca3

+ 4
- 3
src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java Visa fil

} }


public NameXPtg getNameXPtg(String name) { public NameXPtg getNameXPtg(String name) {
// TODO YK: passing UDFFinder.DEFAULT is temporary,
// a proper design should take it from the parent HSSFWorkbook
return _iBook.getNameXPtg(name, UDFFinder.DEFAULT);
return _iBook.getNameXPtg(name, _uBook.getUDFFinder());
} }


/** /**
FormulaRecordAggregate fra = (FormulaRecordAggregate) cell.getCellValueRecord(); FormulaRecordAggregate fra = (FormulaRecordAggregate) cell.getCellValueRecord();
return fra.getFormulaTokens(); return fra.getFormulaTokens();
} }
public UDFFinder getUDFFinder(){
return _uBook.getUDFFinder();
}


private static final class Name implements EvaluationName { private static final class Name implements EvaluationName {



+ 31
- 1
src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java Visa fil

import org.apache.poi.hssf.util.CellReference; import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.ss.usermodel.CreationHelper; import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy; import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
import org.apache.poi.ss.formula.FormulaType; import org.apache.poi.ss.formula.FormulaType;


private static POILogger log = POILogFactory.getLogger(HSSFWorkbook.class); private static POILogger log = POILogFactory.getLogger(HSSFWorkbook.class);


/**
* The locator of user-defined functions.
* By default includes functions from the Excel Analysis Toolpack
*/
private UDFFinder _udfFinder = UDFFinder.DEFAULT;

public static HSSFWorkbook create(InternalWorkbook book) { public static HSSFWorkbook create(InternalWorkbook book) {
return new HSSFWorkbook(book); return new HSSFWorkbook(book);
} }
} }
} }


public CreationHelper getCreationHelper() {
public HSSFCreationHelper getCreationHelper() {
return new HSSFCreationHelper(this); return new HSSFCreationHelper(this);
} }


private static byte[] newUID() { private static byte[] newUID() {
return new byte[16]; return new byte[16];
} }

/**
*
* Returns the locator of user-defined functions.
* The default instance extends the built-in functions with the Analysis Tool Pack
*
* @return the locator of user-defined functions
*/
/*package*/ UDFFinder getUDFFinder(){
return _udfFinder;
}

/**
* Register a new toolpack in this workbook.
*
* @param toopack the toolpack to register
*/
public void addToolPack(UDFFinder toopack){
AggregatingUDFFinder udfs = (AggregatingUDFFinder)_udfFinder;
udfs.add(toopack);
}

} }

+ 3
- 0
src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java Visa fil

import org.apache.poi.ss.formula.ptg.NamePtg; import org.apache.poi.ss.formula.ptg.NamePtg;
import org.apache.poi.ss.formula.ptg.NameXPtg; import org.apache.poi.ss.formula.ptg.NameXPtg;
import org.apache.poi.ss.formula.ptg.Ptg; import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.formula.udf.UDFFinder;


/** /**
* Abstracts a workbook for the purpose of formula evaluation.<br/> * Abstracts a workbook for the purpose of formula evaluation.<br/>
int convertFromExternSheetIndex(int externSheetIndex); int convertFromExternSheetIndex(int externSheetIndex);
ExternalName getExternalName(int externSheetIndex, int externNameIndex); ExternalName getExternalName(int externSheetIndex, int externNameIndex);
EvaluationName getName(NamePtg namePtg); EvaluationName getName(NamePtg namePtg);
EvaluationName getName(String name, int sheetIndex);
String resolveNameXText(NameXPtg ptg); String resolveNameXText(NameXPtg ptg);
Ptg[] getFormulaTokens(EvaluationCell cell); Ptg[] getFormulaTokens(EvaluationCell cell);
UDFFinder getUDFFinder();


class ExternalSheet { class ExternalSheet {
private final String _workbookName; private final String _workbookName;

+ 10
- 7
src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java Visa fil

import org.apache.poi.ss.formula.functions.Choose; import org.apache.poi.ss.formula.functions.Choose;
import org.apache.poi.ss.formula.functions.FreeRefFunction; import org.apache.poi.ss.formula.functions.FreeRefFunction;
import org.apache.poi.ss.formula.functions.IfFunc; import org.apache.poi.ss.formula.functions.IfFunc;
import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
import org.apache.poi.ss.formula.udf.UDFFinder; import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException; import org.apache.poi.ss.formula.CollaboratingWorkbooksEnvironment.WorkbookNotFoundException;
import org.apache.poi.ss.formula.eval.NotImplementedException; import org.apache.poi.ss.formula.eval.NotImplementedException;
private final Map<String, Integer> _sheetIndexesByName; private final Map<String, Integer> _sheetIndexesByName;
private CollaboratingWorkbooksEnvironment _collaboratingWorkbookEnvironment; private CollaboratingWorkbooksEnvironment _collaboratingWorkbookEnvironment;
private final IStabilityClassifier _stabilityClassifier; private final IStabilityClassifier _stabilityClassifier;
private final UDFFinder _udfFinder;
private final AggregatingUDFFinder _udfFinder;


/** /**
* @param udfFinder pass <code>null</code> for default (AnalysisToolPak only) * @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
_collaboratingWorkbookEnvironment = CollaboratingWorkbooksEnvironment.EMPTY; _collaboratingWorkbookEnvironment = CollaboratingWorkbooksEnvironment.EMPTY;
_workbookIx = 0; _workbookIx = 0;
_stabilityClassifier = stabilityClassifier; _stabilityClassifier = stabilityClassifier;
_udfFinder = udfFinder == null ? UDFFinder.DEFAULT : udfFinder;

AggregatingUDFFinder defaultToolkit = // workbook can be null in unit tests
workbook == null ? null : (AggregatingUDFFinder)workbook.getUDFFinder();
if(defaultToolkit != null && udfFinder != null) {
defaultToolkit.add(udfFinder);
}
_udfFinder = defaultToolkit;
} }


/** /**
} }
/* package */ EvaluationName getName(String name, int sheetIndex) { /* package */ EvaluationName getName(String name, int sheetIndex) {
NamePtg namePtg = null;
if(_workbook instanceof HSSFEvaluationWorkbook){
namePtg =((HSSFEvaluationWorkbook)_workbook).getName(name, sheetIndex).createPtg();
}
NamePtg namePtg = _workbook.getName(name, sheetIndex).createPtg();


if(namePtg == null) { if(namePtg == null) {
return null; return null;

+ 146
- 129
src/java/org/apache/poi/ss/formula/atp/AnalysisToolPak.java Visa fil

*/ */
public final class AnalysisToolPak implements UDFFinder { public final class AnalysisToolPak implements UDFFinder {


public static final UDFFinder instance = new AnalysisToolPak();

private static final class NotImplemented implements FreeRefFunction {
private final String _functionName;

public NotImplemented(String functionName) {
_functionName = functionName;
}

public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
throw new NotImplementedException(_functionName);
}
};

private final Map<String, FreeRefFunction> _functionsByName = createFunctionsMap();


private AnalysisToolPak() {
// enforce singleton
}

public FreeRefFunction findFunction(String name) {
return _functionsByName.get(name);
}

private Map<String, FreeRefFunction> createFunctionsMap() {
Map<String, FreeRefFunction> m = new HashMap<String, FreeRefFunction>(100);

r(m, "ACCRINT", null);
r(m, "ACCRINTM", null);
r(m, "AMORDEGRC", null);
r(m, "AMORLINC", null);
r(m, "BESSELI", null);
r(m, "BESSELJ", null);
r(m, "BESSELK", null);
r(m, "BESSELY", null);
r(m, "BIN2DEC", null);
r(m, "BIN2HEX", null);
r(m, "BIN2OCT", null);
r(m, "CO MPLEX", null);
r(m, "CONVERT", null);
r(m, "COUPDAYBS", null);
r(m, "COUPDAYS", null);
r(m, "COUPDAYSNC", null);
r(m, "COUPNCD", null);
r(m, "COUPNUM", null);
r(m, "COUPPCD", null);
r(m, "CUMIPMT", null);
r(m, "CUMPRINC", null);
r(m, "DEC2BIN", null);
r(m, "DEC2HEX", null);
r(m, "DEC2OCT", null);
r(m, "DELTA", null);
r(m, "DISC", null);
r(m, "DOLLARDE", null);
r(m, "DOLLARFR", null);
r(m, "DURATION", null);
r(m, "EDATE", null);
r(m, "EFFECT", null);
r(m, "EOMONTH", null);
r(m, "ERF", null);
r(m, "ERFC", null);
r(m, "FACTDOUBLE", null);
r(m, "FVSCHEDULE", null);
r(m, "GCD", null);
r(m, "GESTEP", null);
r(m, "HEX2BIN", null);
r(m, "HEX2DEC", null);
r(m, "HEX2OCT", null);
r(m, "IMABS", null);
r(m, "IMAGINARY", null);
r(m, "IMARGUMENT", null);
r(m, "IMCONJUGATE", null);
r(m, "IMCOS", null);
r(m, "IMDIV", null);
r(m, "IMEXP", null);
r(m, "IMLN", null);
r(m, "IMLOG10", null);
r(m, "IMLOG2", null);
r(m, "IMPOWER", null);
r(m, "IMPRODUCT", null);
r(m, "IMREAL", null);
r(m, "IMSIN", null);
r(m, "IMSQRT", null);
r(m, "IMSUB", null);
r(m, "IMSUM", null);
r(m, "INTRATE", null);
r(m, "ISEVEN", ParityFunction.IS_EVEN);
r(m, "ISODD", ParityFunction.IS_ODD);
r(m, "LCM", null);
r(m, "MDURATION", null);
r(m, "MROUND", null);
r(m, "MULTINOMIAL", null);
r(m, "NETWORKDAYS", null);
r(m, "NOMINAL", null);
r(m, "OCT2BIN", null);
r(m, "OCT2DEC", null);
r(m, "OCT2HEX", null);
r(m, "ODDFPRICE", null);
r(m, "ODDFYIELD", null);
r(m, "ODDLPRICE", null);
r(m, "ODDLYIELD", null);
r(m, "PRICE", null);
r(m, "PRICEDISC", null);
r(m, "PRICEMAT", null);
r(m, "QUOTIENT", null);
r(m, "RANDBETWEEN", RandBetween.instance);
r(m, "RECEIVED", null);
r(m, "SERIESSUM", null);
r(m, "SQRTPI", null);
r(m, "TBILLEQ", null);
r(m, "TBILLPRICE", null);
r(m, "TBILLYIELD", null);
r(m, "WEEKNUM", null);
r(m, "WORKDAY", null);
r(m, "XIRR", null);
r(m, "XNPV", null);
r(m, "YEARFRAC", YearFrac.instance);
r(m, "YIELD", null);
r(m, "YIELDDISC", null);
r(m, "YIELDMAT", null);

return m;
}

private static void r(Map<String, FreeRefFunction> m, String functionName, FreeRefFunction pFunc) {
FreeRefFunction func = pFunc == null ? new NotImplemented(functionName) : pFunc;
m.put(functionName, func);
}
public static final UDFFinder instance = new AnalysisToolPak();

private static final class NotImplemented implements FreeRefFunction {
private final String _functionName;

public NotImplemented(String functionName) {
_functionName = functionName;
}

public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
throw new NotImplementedException(_functionName);
}
}

;

private final Map<String, FreeRefFunction> _functionsByName = createFunctionsMap();


private AnalysisToolPak() {
// enforce singleton
}

public FreeRefFunction findFunction(String name) {
return _functionsByName.get(name);
}

private Map<String, FreeRefFunction> createFunctionsMap() {
Map<String, FreeRefFunction> m = new HashMap<String, FreeRefFunction>(108);

r(m, "ACCRINT", null);
r(m, "ACCRINTM", null);
r(m, "AMORDEGRC", null);
r(m, "AMORLINC", null);
r(m, "AVERAGEIF", null);
r(m, "AVERAGEIFS", null);
r(m, "BAHTTEXT", null);
r(m, "BESSELI", null);
r(m, "BESSELJ", null);
r(m, "BESSELK", null);
r(m, "BESSELY", null);
r(m, "BIN2DEC", null);
r(m, "BIN2HEX", null);
r(m, "BIN2OCT", null);
r(m, "COMPLEX", null);
r(m, "CONVERT", null);
r(m, "COUNTIFS", null);
r(m, "COUPDAYBS", null);
r(m, "COUPDAYS", null);
r(m, "COUPDAYSNC", null);
r(m, "COUPNCD", null);
r(m, "COUPNUM", null);
r(m, "COUPPCD", null);
r(m, "CUBEKPIMEMBER", null);
r(m, "CUBEMEMBER", null);
r(m, "CUBEMEMBERPROPERTY", null);
r(m, "CUBERANKEDMEMBER", null);
r(m, "CUBESET", null);
r(m, "CUBESETCOUNT", null);
r(m, "CUBEVALUE", null);
r(m, "CUMIPMT", null);
r(m, "CUMPRINC", null);
r(m, "DEC2BIN", null);
r(m, "DEC2HEX", null);
r(m, "DEC2OCT", null);
r(m, "DELTA", null);
r(m, "DISC", null);
r(m, "DOLLARDE", null);
r(m, "DOLLARFR", null);
r(m, "DURATION", null);
r(m, "EDATE", null);
r(m, "EFFECT", null);
r(m, "EOMONTH", null);
r(m, "ERF", null);
r(m, "ERFC", null);
r(m, "FACTDOUBLE", null);
r(m, "FVSCHEDULE", null);
r(m, "GCD", null);
r(m, "GESTEP", null);
r(m, "HEX2BIN", null);
r(m, "HEX2DEC", null);
r(m, "HEX2OCT", null);
r(m, "IFERROR", null);
r(m, "IMABS", null);
r(m, "IMAGINARY", null);
r(m, "IMARGUMENT", null);
r(m, "IMCONJUGATE", null);
r(m, "IMCOS", null);
r(m, "IMDIV", null);
r(m, "IMEXP", null);
r(m, "IMLN", null);
r(m, "IMLOG10", null);
r(m, "IMLOG2", null);
r(m, "IMPOWER", null);
r(m, "IMPRODUCT", null);
r(m, "IMREAL", null);
r(m, "IMSIN", null);
r(m, "IMSQRT", null);
r(m, "IMSUB", null);
r(m, "IMSUM", null);
r(m, "INTRATE", null);
r(m, "ISEVEN", ParityFunction.IS_EVEN);
r(m, "ISODD", ParityFunction.IS_ODD);
r(m, "JIS", null);
r(m, "LCM", null);
r(m, "MDURATION", null);
r(m, "MROUND", null);
r(m, "MULTINOMIAL", null);
r(m, "NETWORKDAYS", null);
r(m, "NOMINAL", null);
r(m, "OCT2BIN", null);
r(m, "OCT2DEC", null);
r(m, "OCT2HEX", null);
r(m, "ODDFPRICE", null);
r(m, "ODDFYIELD", null);
r(m, "ODDLPRICE", null);
r(m, "ODDLYIELD", null);
r(m, "PRICE", null);
r(m, "PRICEDISC", null);
r(m, "PRICEMAT", null);
r(m, "QUOTIENT", null);
r(m, "RANDBETWEEN", RandBetween.instance);
r(m, "RECEIVED", null);
r(m, "RTD", null);
r(m, "SERIESSUM", null);
r(m, "SQRTPI", null);
r(m, "SUMIFS", null);
r(m, "TBILLEQ", null);
r(m, "TBILLPRICE", null);
r(m, "TBILLYIELD", null);
r(m, "WEEKNUM", null);
r(m, "WORKDAY", null);
r(m, "XIRR", null);
r(m, "XNPV", null);
r(m, "YEARFRAC", YearFrac.instance);
r(m, "YIELD", null);
r(m, "YIELDDISC", null);
r(m, "YIELDMAT", null);

return m;
}

private static void r(Map<String, FreeRefFunction> m, String functionName, FreeRefFunction pFunc) {
FreeRefFunction func = pFunc == null ? new NotImplemented(functionName) : pFunc;
m.put(functionName, func);
}
} }

+ 9
- 0
src/java/org/apache/poi/ss/formula/eval/forked/ForkedEvaluationWorkbook.java Visa fil

import org.apache.poi.ss.formula.EvaluationName; import org.apache.poi.ss.formula.EvaluationName;
import org.apache.poi.ss.formula.EvaluationSheet; import org.apache.poi.ss.formula.EvaluationSheet;
import org.apache.poi.ss.formula.EvaluationWorkbook; import org.apache.poi.ss.formula.EvaluationWorkbook;
import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.Workbook;


/** /**
return _masterBook.getName(namePtg); return _masterBook.getName(namePtg);
} }


public EvaluationName getName(String name, int sheetIndex){
return _masterBook.getName(name, sheetIndex);
}

public EvaluationSheet getSheet(int sheetIndex) { public EvaluationSheet getSheet(int sheetIndex) {
return getSharedSheet(getSheetName(sheetIndex)); return getSharedSheet(getSheetName(sheetIndex));
} }
return _masterBook.resolveNameXText(ptg); return _masterBook.resolveNameXText(ptg);
} }


public UDFFinder getUDFFinder(){
return _masterBook.getUDFFinder();
}

private static final class OrderedSheet implements Comparable<OrderedSheet> { private static final class OrderedSheet implements Comparable<OrderedSheet> {
private final String _sheetName; private final String _sheetName;
private final int _index; private final int _index;

+ 1
- 1
src/java/org/apache/poi/ss/formula/function/FunctionMetadataRegistry.java Visa fil

private final FunctionMetadata[] _functionDataByIndex; private final FunctionMetadata[] _functionDataByIndex;
private final Map<String, FunctionMetadata> _functionDataByName; private final Map<String, FunctionMetadata> _functionDataByName;


private static FunctionMetadataRegistry getInstance() {
public static FunctionMetadataRegistry getInstance() {
if (_instance == null) { if (_instance == null) {
_instance = FunctionMetadataReader.createRegistry(); _instance = FunctionMetadataReader.createRegistry();
} }

+ 17
- 3
src/java/org/apache/poi/ss/formula/udf/AggregatingUDFFinder.java Visa fil



import org.apache.poi.ss.formula.functions.FreeRefFunction; import org.apache.poi.ss.formula.functions.FreeRefFunction;


import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

/** /**
* Collects add-in libraries and VB macro functions together into one UDF finder * Collects add-in libraries and VB macro functions together into one UDF finder
* *
* @author PUdalau * @author PUdalau
*/ */
public final class AggregatingUDFFinder implements UDFFinder {
public class AggregatingUDFFinder implements UDFFinder {


private final UDFFinder[] _usedToolPacks;
private final Collection<UDFFinder> _usedToolPacks;


public AggregatingUDFFinder(UDFFinder ... usedToolPacks) { public AggregatingUDFFinder(UDFFinder ... usedToolPacks) {
_usedToolPacks = usedToolPacks.clone();
_usedToolPacks = new ArrayList<UDFFinder>(usedToolPacks.length);
_usedToolPacks.addAll(Arrays.asList(usedToolPacks));
} }


/** /**
} }
return null; return null;
} }

/**
* Add a new toolpack
*
* @param toolPack the UDF toolpack to add
*/
public void add(UDFFinder toolPack){
_usedToolPacks.add(toolPack);
}
} }

+ 2
- 2
src/java/org/apache/poi/ss/formula/udf/DefaultUDFFinder.java Visa fil

} }
HashMap<String, FreeRefFunction> m = new HashMap<String, FreeRefFunction>(nFuncs * 3 / 2); HashMap<String, FreeRefFunction> m = new HashMap<String, FreeRefFunction>(nFuncs * 3 / 2);
for (int i = 0; i < functionImpls.length; i++) { for (int i = 0; i < functionImpls.length; i++) {
m.put(functionNames[i], functionImpls[i]);
m.put(functionNames[i].toUpperCase(), functionImpls[i]);
} }
_functionsByName = m; _functionsByName = m;
} }


public FreeRefFunction findFunction(String name) { public FreeRefFunction findFunction(String name) {
return _functionsByName.get(name);
return _functionsByName.get(name.toUpperCase());
} }
} }

+ 9
- 0
src/java/org/apache/poi/ss/usermodel/Workbook.java Visa fil

import java.io.OutputStream; import java.io.OutputStream;
import java.util.List; import java.util.List;


import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.ss.usermodel.Row.MissingCellPolicy; import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;


/** /**
* @throws IllegalArgumentException if the supplied sheet index or state is invalid * @throws IllegalArgumentException if the supplied sheet index or state is invalid
*/ */
void setSheetHidden(int sheetIx, int hidden); void setSheetHidden(int sheetIx, int hidden);

/**
* Register a new toolpack in this workbook.
*
* @param toopack the toolpack to register
*/
void addToolPack(UDFFinder toopack);

} }

+ 56
- 0
src/ooxml/java/org/apache/poi/xssf/model/IndexedUDFFinder.java Visa fil

/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.xssf.model;

import org.apache.poi.ss.formula.functions.FreeRefFunction;
import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.util.Internal;

import java.util.HashMap;

/**
* A UDFFinder that can retrieve functions both by name and by fake index.
*
* @author Yegor Kozlov
*/
@Internal
public final class IndexedUDFFinder extends AggregatingUDFFinder {
private final HashMap<Integer, String> _funcMap;

public IndexedUDFFinder(UDFFinder... usedToolPacks) {
super(usedToolPacks);
_funcMap = new HashMap<Integer, String>();
}

public FreeRefFunction findFunction(String name) {
FreeRefFunction func = super.findFunction(name);
if (func != null) {
int idx = getFunctionIndex(name);
_funcMap.put(idx, name);
}
return func;
}

public String getFunctionName(int idx) {
return _funcMap.get(idx);
}

public int getFunctionIndex(String name) {
return name.hashCode();
}
}

+ 19
- 10
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFEvaluationWorkbook.java Visa fil



package org.apache.poi.xssf.usermodel; package org.apache.poi.xssf.usermodel;


import org.apache.poi.ss.formula.functions.FreeRefFunction;
import org.apache.poi.ss.formula.ptg.NamePtg; import org.apache.poi.ss.formula.ptg.NamePtg;
import org.apache.poi.ss.formula.ptg.NameXPtg; import org.apache.poi.ss.formula.ptg.NameXPtg;
import org.apache.poi.ss.formula.ptg.Ptg; import org.apache.poi.ss.formula.ptg.Ptg;
import org.apache.poi.ss.formula.FormulaParsingWorkbook; import org.apache.poi.ss.formula.FormulaParsingWorkbook;
import org.apache.poi.ss.formula.FormulaRenderingWorkbook; import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
import org.apache.poi.ss.formula.FormulaType; import org.apache.poi.ss.formula.FormulaType;
import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.xssf.model.IndexedUDFFinder;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDefinedName;


import java.util.HashMap;

/** /**
* Internal POI use only * Internal POI use only
* *
} }


public NameXPtg getNameXPtg(String name) { public NameXPtg getNameXPtg(String name) {
// may require to return null to make tests pass
throw new RuntimeException("Not implemented yet");
IndexedUDFFinder udfFinder = (IndexedUDFFinder)getUDFFinder();
FreeRefFunction func = udfFinder.findFunction(name);
if(func == null) return null;
else return new NameXPtg(0, udfFinder.getFunctionIndex(name));
} }


public String resolveNameXText(NameXPtg n) {
int idx = n.getNameIndex();
IndexedUDFFinder udfFinder = (IndexedUDFFinder)getUDFFinder();
return udfFinder.getFunctionName(idx);
}

public EvaluationSheet getSheet(int sheetIndex) { public EvaluationSheet getSheet(int sheetIndex) {
return new XSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex)); return new XSSFEvaluationSheet(_uBook.getSheetAt(sheetIndex));
} }
return _uBook.getSheetIndex(sheetName); return _uBook.getSheetIndex(sheetName);
} }


/**
* TODO - figure out what the hell this methods does in
* HSSF...
*/
public String resolveNameXText(NameXPtg n) {
throw new RuntimeException("method not implemented yet");
}

public String getSheetNameByExternSheet(int externSheetIndex) { public String getSheetNameByExternSheet(int externSheetIndex) {
int sheetIndex = convertFromExternalSheetIndex(externSheetIndex); int sheetIndex = convertFromExternalSheetIndex(externSheetIndex);
return _uBook.getSheetName(sheetIndex); return _uBook.getSheetName(sheetIndex);
return FormulaParser.parse(cell.getCellFormula(), frBook, FormulaType.CELL, _uBook.getSheetIndex(cell.getSheet())); return FormulaParser.parse(cell.getCellFormula(), frBook, FormulaType.CELL, _uBook.getSheetIndex(cell.getSheet()));
} }


public UDFFinder getUDFFinder(){
return _uBook.getUDFFinder();
}

private static final class Name implements EvaluationName { private static final class Name implements EvaluationName {


private final XSSFName _nameRecord; private final XSSFName _nameRecord;

+ 36
- 5
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java Visa fil

import org.apache.poi.openxml4j.opc.PackageRelationshipTypes; import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
import org.apache.poi.openxml4j.opc.PackagingURIHelper; import org.apache.poi.openxml4j.opc.PackagingURIHelper;
import org.apache.poi.openxml4j.opc.TargetMode; import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.ss.formula.udf.AggregatingUDFFinder;
import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellReference; import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.util.WorkbookUtil; import org.apache.poi.ss.util.WorkbookUtil;
import org.apache.poi.util.*; import org.apache.poi.util.*;
import org.apache.poi.xssf.model.CalculationChain;
import org.apache.poi.xssf.model.MapInfo;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.model.ThemesTable;
import org.apache.poi.xssf.model.*;
import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions; import org.apache.xmlbeans.XmlOptions;


private ThemesTable theme; private ThemesTable theme;


/**
* The locator of user-defined functions.
* By default includes functions from the Excel Analysis Toolpack
*/
private IndexedUDFFinder _udfFinder = new IndexedUDFFinder(UDFFinder.DEFAULT);

/** /**
* TODO * TODO
*/ */
workbook.setWorkbookProtection(CTWorkbookProtection.Factory.newInstance()); workbook.setWorkbookProtection(CTWorkbookProtection.Factory.newInstance());
} }
} }

/**
*
* Returns the locator of user-defined functions.
* <p>
* The default instance extends the built-in functions with the Excel Analysis Tool Pack.
* To set / evaluate custom functions you need to register them as follows:
*
*
*
* </p>
* @return wrapped instance of UDFFinder that allows seeking functions both by index and name
*/
/*package*/ UDFFinder getUDFFinder() {
return _udfFinder;
}

/**
* Register a new toolpack in this workbook.
*
* @param toopack the toolpack to register
*/
public void addToolPack(UDFFinder toopack){
_udfFinder.add(toopack);
}


} }

+ 35
- 0
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFExternalFunctions.java Visa fil

/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */

package org.apache.poi.xssf.usermodel;

import org.apache.poi.ss.formula.BaseTestExternalFunctions;
import org.apache.poi.xssf.XSSFITestDataProvider;

/**
* Tests setting and evaluating user-defined functions in HSSF
*/
public final class TestXSSFExternalFunctions extends BaseTestExternalFunctions {

public TestXSSFExternalFunctions() {
super(XSSFITestDataProvider.instance);
}

public void testATP(){
baseTestInvokeATP("atp.xlsx");
}
}

+ 36
- 0
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFExternalFunctions.java Visa fil

/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */

package org.apache.poi.hssf.usermodel;

import org.apache.poi.hssf.HSSFITestDataProvider;
import org.apache.poi.ss.formula.BaseTestExternalFunctions;

/**
* Tests setting and evaluating user-defined functions in HSSF
*/
public final class TestHSSFExternalFunctions extends BaseTestExternalFunctions {

public TestHSSFExternalFunctions() {
super(HSSFITestDataProvider.instance);
}

public void testATP(){
baseTestInvokeATP("atp.xls");
}

}

+ 144
- 0
src/testcases/org/apache/poi/ss/formula/BaseTestExternalFunctions.java Visa fil

/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.ss.formula;

import junit.framework.TestCase;
import org.apache.poi.ss.ITestDataProvider;
import org.apache.poi.ss.formula.eval.ErrorEval;
import org.apache.poi.ss.formula.eval.StringEval;
import org.apache.poi.ss.formula.eval.ValueEval;
import org.apache.poi.ss.formula.functions.FreeRefFunction;
import org.apache.poi.ss.formula.udf.DefaultUDFFinder;
import org.apache.poi.ss.formula.udf.UDFFinder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

/**
* Test setting / evaluating of Analysis Toolpack and user-defined functions
*
* @author Yegor Kozlov
*/
public class BaseTestExternalFunctions extends TestCase {
// define two custom user-defined functions
private static class MyFunc implements FreeRefFunction {
public MyFunc() {
//
}

public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
if (args.length != 1 || !(args[0] instanceof StringEval)) {
return ErrorEval.VALUE_INVALID;
}
StringEval input = (StringEval) args[0];
return new StringEval(input.getStringValue() + "abc");
}
}

private static class MyFunc2 implements FreeRefFunction {
public MyFunc2() {
//
}

public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
if (args.length != 1 || !(args[0] instanceof StringEval)) {
return ErrorEval.VALUE_INVALID;
}
StringEval input = (StringEval) args[0];
return new StringEval(input.getStringValue() + "abc2");
}
}

/**
* register the two test UDFs in a UDF finder, to be passed to the workbook
*/
private static UDFFinder customToolpack = new DefaultUDFFinder(
new String[] { "myFunc", "myFunc2"},
new FreeRefFunction[] { new MyFunc(), new MyFunc2()}
);


protected final ITestDataProvider _testDataProvider;

/**
* @param testDataProvider an object that provides test data in HSSF / XSSF specific way
*/
protected BaseTestExternalFunctions(ITestDataProvider testDataProvider) {
_testDataProvider = testDataProvider;
}

public void testExternalFunctions() {
Workbook wb = _testDataProvider.createWorkbook();

Sheet sh = wb.createSheet();

Cell cell1 = sh.createRow(0).createCell(0);
cell1.setCellFormula("ISODD(1)+ISEVEN(2)"); // functions from the Excel Analysis Toolpack
assertEquals("ISODD(1)+ISEVEN(2)", cell1.getCellFormula());

Cell cell2 = sh.createRow(1).createCell(0);
try {
cell2.setCellFormula("MYFUNC(\"B1\")");
fail("Should fail because MYFUNC is an unknown function");
} catch (FormulaParseException e){
; //expected
}

wb.addToolPack(customToolpack);

cell2.setCellFormula("MYFUNC(\"B1\")");
assertEquals("MYFUNC(\"B1\")", cell2.getCellFormula());

Cell cell3 = sh.createRow(2).createCell(0);
cell3.setCellFormula("MYFUNC2(\"C1\")&\"-\"&A2"); //where A2 is defined above
assertEquals("MYFUNC2(\"C1\")&\"-\"&A2", cell3.getCellFormula());

FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
assertEquals(2.0, evaluator.evaluate(cell1).getNumberValue());
assertEquals("B1abc", evaluator.evaluate(cell2).getStringValue());
assertEquals("C1abc2-B1abc", evaluator.evaluate(cell3).getStringValue());

}

/**
* test invoking saved ATP functions
*
* @param testFile either atp.xls or atp.xlsx
*/
public void baseTestInvokeATP(String testFile){
Workbook wb = _testDataProvider.openSampleWorkbook(testFile);
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();

Sheet sh = wb.getSheetAt(0);
// these two are not imlemented in r
assertEquals("DELTA(1.3,1.5)", sh.getRow(0).getCell(1).getCellFormula());
assertEquals("COMPLEX(2,4)", sh.getRow(1).getCell(1).getCellFormula());

Cell cell2 = sh.getRow(2).getCell(1);
assertEquals("ISODD(2)", cell2.getCellFormula());
assertEquals(false, evaluator.evaluate(cell2).getBooleanValue());
assertEquals(Cell.CELL_TYPE_BOOLEAN, evaluator.evaluateFormulaCell(cell2));

Cell cell3 = sh.getRow(3).getCell(1);
assertEquals("ISEVEN(2)", cell3.getCellFormula());
assertEquals(true, evaluator.evaluate(cell3).getBooleanValue());
assertEquals(Cell.CELL_TYPE_BOOLEAN, evaluator.evaluateFormulaCell(cell3));

}

}

Binär
test-data/spreadsheet/atp.xls Visa fil


Binär
test-data/spreadsheet/atp.xlsx Visa fil


Laddar…
Avbryt
Spara