mirror of https://github.com/apache/poi.git
init support for XLOOKUP
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1892116 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
65a2e42a3d
commit
65d7486cc6
|
@ -18,15 +18,17 @@
|
||||||
package org.apache.poi.ss.formula.atp;
|
package org.apache.poi.ss.formula.atp;
|
||||||
|
|
||||||
import org.apache.poi.ss.formula.OperationEvaluationContext;
|
import org.apache.poi.ss.formula.OperationEvaluationContext;
|
||||||
|
import org.apache.poi.ss.formula.TwoDEval;
|
||||||
import org.apache.poi.ss.formula.eval.*;
|
import org.apache.poi.ss.formula.eval.*;
|
||||||
import org.apache.poi.ss.formula.functions.FreeRefFunction;
|
import org.apache.poi.ss.formula.functions.FreeRefFunction;
|
||||||
|
import org.apache.poi.ss.formula.functions.LookupUtils;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of Excel function XLOOKUP()
|
* Implementation of Excel function XLOOKUP()
|
||||||
*
|
*
|
||||||
* POI does not currently support have return values with multiple columns and just takes the first cell
|
* POI does not currently support having return values with multiple columns and just takes the first cell
|
||||||
* right now.
|
* right now.
|
||||||
*
|
*
|
||||||
* <b>Syntax</b><br>
|
* <b>Syntax</b><br>
|
||||||
|
@ -66,48 +68,59 @@ final class XLookupFunction implements FreeRefFunction {
|
||||||
return e.getErrorEval();
|
return e.getErrorEval();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2], notFound);
|
int matchMode = 0;
|
||||||
|
if (args.length > 4) {
|
||||||
|
try {
|
||||||
|
ValueEval matchModeValue = OperandResolver.getSingleValue(args[4], srcRowIndex, srcColumnIndex);
|
||||||
|
matchMode = OperandResolver.coerceValueToInt(matchModeValue);
|
||||||
|
} catch (EvaluationException e) {
|
||||||
|
return e.getErrorEval();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int searchMode = 1;
|
||||||
|
if (args.length > 5) {
|
||||||
|
try {
|
||||||
|
ValueEval searchModeValue = OperandResolver.getSingleValue(args[5], srcRowIndex, srcColumnIndex);
|
||||||
|
searchMode = OperandResolver.coerceValueToInt(searchModeValue);
|
||||||
|
} catch (EvaluationException e) {
|
||||||
|
return e.getErrorEval();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2], notFound, matchMode, searchMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval lookupEval, ValueEval indexEval,
|
private ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval lookupEval, ValueEval indexEval,
|
||||||
ValueEval returnEval, Optional<String> notFound) {
|
ValueEval returnEval, Optional<String> notFound, int matchMode, int searchMode) {
|
||||||
try {
|
try {
|
||||||
ValueEval lookupValue = OperandResolver.getSingleValue(lookupEval, srcRowIndex, srcColumnIndex);
|
ValueEval lookupValue = OperandResolver.getSingleValue(lookupEval, srcRowIndex, srcColumnIndex);
|
||||||
String lookup = laxValueToString(lookupValue);
|
TwoDEval tableArray = LookupUtils.resolveTableArrayArg(indexEval);
|
||||||
int matchedRow = matchedIndex(indexEval, lookup);
|
boolean isRangeLookup = false;
|
||||||
if (matchedRow != -1) {
|
int matchedRow;
|
||||||
|
try {
|
||||||
|
matchedRow = LookupUtils.lookupIndexOfValue(lookupValue, LookupUtils.createColumnVector(tableArray, 0), isRangeLookup);
|
||||||
|
} catch (EvaluationException e) {
|
||||||
|
if (ErrorEval.NA.equals(e.getErrorEval())) {
|
||||||
|
if (notFound.isPresent()) {
|
||||||
|
return new StringEval(notFound.get());
|
||||||
|
}
|
||||||
|
return ErrorEval.NA;
|
||||||
|
} else {
|
||||||
|
return e.getErrorEval();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (returnEval instanceof AreaEval) {
|
if (returnEval instanceof AreaEval) {
|
||||||
AreaEval area = (AreaEval)returnEval;
|
AreaEval area = (AreaEval)returnEval;
|
||||||
//TODO to fully support XLOOKUP, we should return the full row
|
//TODO to fully support XLOOKUP, we should return the full row
|
||||||
//but POI does not currently support functions returning multiple cell values
|
//but POI does not currently support functions returning multiple cell values
|
||||||
return area.getRelativeValue(matchedRow, 0);
|
return area.getRelativeValue(matchedRow, 0);
|
||||||
|
} else {
|
||||||
|
return ErrorEval.VALUE_INVALID;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (notFound.isPresent()) {
|
|
||||||
return new StringEval(notFound.get());
|
|
||||||
}
|
|
||||||
return ErrorEval.NA;
|
|
||||||
} catch (EvaluationException e) {
|
} catch (EvaluationException e) {
|
||||||
return e.getErrorEval();
|
return e.getErrorEval();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int matchedIndex(ValueEval areaEval, String lookup) {
|
|
||||||
if (areaEval instanceof AreaEval) {
|
|
||||||
AreaEval area = (AreaEval)areaEval;
|
|
||||||
for (int r = 0; r <= area.getHeight(); r++) {
|
|
||||||
for (int c = 0; c <= area.getWidth(); c++) {
|
|
||||||
ValueEval cellEval = area.getRelativeValue(r, c);
|
|
||||||
String cellValue = OperandResolver.coerceValueToString(cellEval);
|
|
||||||
if (lookup.equals(cellValue)) {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String laxValueToString(ValueEval eval) {
|
private String laxValueToString(ValueEval eval) {
|
||||||
return (eval instanceof MissingArgEval) ? "" : OperandResolver.coerceValueToString(eval);
|
return (eval instanceof MissingArgEval) ? "" : OperandResolver.coerceValueToString(eval);
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ import org.apache.poi.ss.formula.eval.ValueEval;
|
||||||
/**
|
/**
|
||||||
* Common functionality used by VLOOKUP, HLOOKUP, LOOKUP and MATCH
|
* Common functionality used by VLOOKUP, HLOOKUP, LOOKUP and MATCH
|
||||||
*/
|
*/
|
||||||
final class LookupUtils {
|
public final class LookupUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a single row or column within an {@code AreaEval}.
|
* Represents a single row or column within an {@code AreaEval}.
|
||||||
|
|
Loading…
Reference in New Issue