Search in sources :

Example 6 with XPathTypeMismatchException

use of org.javarosa.xpath.XPathTypeMismatchException in project javarosa by opendatakit.

the class XPathReference method getPathExpr.

public static XPathPathExpr getPathExpr(String nodeset) {
    XPathExpression path;
    boolean validNonPathExpr = false;
    try {
        path = XPathParseTool.parseXPath(nodeset);
        if (!(path instanceof XPathPathExpr)) {
            validNonPathExpr = true;
            throw new XPathSyntaxException();
        }
    } catch (XPathSyntaxException xse) {
        // make these checked exceptions?
        if (validNonPathExpr) {
            throw new XPathTypeMismatchException("Expected XPath path, got XPath expression: [" + nodeset + "]," + xse.getMessage());
        } else {
            Std.printStack(xse);
            throw new XPathException("Parse error in XPath path: [" + nodeset + "]." + (xse.getMessage() == null ? "" : "\n" + xse.getMessage()));
        }
    }
    return (XPathPathExpr) path;
}
Also used : XPathExpression(org.javarosa.xpath.expr.XPathExpression) XPathSyntaxException(org.javarosa.xpath.parser.XPathSyntaxException) XPathException(org.javarosa.xpath.XPathException) XPathPathExpr(org.javarosa.xpath.expr.XPathPathExpr) XPathTypeMismatchException(org.javarosa.xpath.XPathTypeMismatchException)

Example 7 with XPathTypeMismatchException

use of org.javarosa.xpath.XPathTypeMismatchException in project javarosa by opendatakit.

the class XPathFuncExpr method indexedRepeat.

/**
 * This provides a method of indexing fields stored in prior repeat groups.
 *
 * args[0] = generic XPath expression to index
 * args[1] = generic XPath expression for group to index
 * args[2] = index number for group
 * args[3] = generic XPath expression for add'l group to index (if 5 or 7 parameters passed)
 * args[4] = index number for group (if 5 or 7 parameters passed)
 * args[5] = generic XPath expression for add'l group to index (if 7 parameters passed)
 * args[6] = index number for group (if 7 parameters passed)
 *
 * @param model
 * @param ec
 * @param args
 * @param argVals
 * @return
 */
public static Object indexedRepeat(DataInstance model, EvaluationContext ec, XPathExpression[] args, Object[] argVals) throws XPathTypeMismatchException {
    // initialize target and context references
    if (!(args[0] instanceof XPathPathExpr)) {
        throw new XPathTypeMismatchException("indexed-repeat(): first parameter must be XPath field reference");
    }
    XPathPathExpr targetPath = (XPathPathExpr) args[0];
    TreeReference targetRef = targetPath.getReference();
    TreeReference contextRef = targetRef.clone();
    // process passed index(es)
    for (int pathargi = 1, idxargi = 2; idxargi < args.length; pathargi += 2, idxargi += 2) {
        // confirm that we were passed an XPath
        if (!(args[pathargi] instanceof XPathPathExpr)) {
            throw new XPathTypeMismatchException("indexed-repeat(): parameter " + (pathargi + 1) + " must be XPath repeat-group reference");
        }
        // confirm that the passed XPath is a parent of our overall target path
        TreeReference groupRef = ((XPathPathExpr) args[pathargi]).getReference();
        if (!groupRef.isParentOf(targetRef, true)) {
            throw new XPathTypeMismatchException("indexed-repeat(): parameter " + (pathargi + 1) + " must be a parent of the field in parameter 1");
        }
        // process index (if valid)
        int groupIdx = toInt(args[idxargi].eval(model, ec)).intValue();
        if (groupIdx <= 0) {
            /*
                   Don't allow invalid index otherwise an exception will be thrown later by XPathNodeset#unpack().
                   This may happen if referenced node hadn't gotten a value yet but the calculation was fired. For example when adding a new repeat.
                 */
            groupIdx = 1;
        }
        contextRef.setMultiplicity(groupRef.size() - 1, groupIdx - 1);
    }
    // evaluate and return the XPath expression, in context
    EvaluationContext revisedec = new EvaluationContext(ec, contextRef);
    return (targetPath.eval(model, revisedec));
}
Also used : TreeReference(org.javarosa.core.model.instance.TreeReference) XPathTypeMismatchException(org.javarosa.xpath.XPathTypeMismatchException) EvaluationContext(org.javarosa.core.model.condition.EvaluationContext)

Example 8 with XPathTypeMismatchException

use of org.javarosa.xpath.XPathTypeMismatchException in project javarosa by opendatakit.

the class XPathFuncExpr method toDecimalDateTime.

public static Object toDecimalDateTime(Object o, boolean keepDate) {
    o = unpack(o);
    if (o instanceof Double) {
        Double n = (Double) o;
        if (n.isNaN()) {
            return n;
        }
        if (n.isInfinite() || n > Integer.MAX_VALUE || n < Integer.MIN_VALUE) {
            throw new XPathTypeMismatchException("converting out-of-range value to date");
        }
        if (keepDate) {
            return n;
        } else {
            return n - Math.floor(n);
        }
    } else if (o instanceof String) {
        String s = (String) o;
        if (s.length() == 0) {
            return s;
        }
        Date d = DateUtils.parseDateTime(s);
        if (d == null) {
            throw new XPathTypeMismatchException("converting to date");
        } else {
            if (keepDate) {
                long milli = d.getTime();
                Double v = ((double) milli) / DateUtils.DAY_IN_MS;
                return v;
            } else {
                return DateUtils.decimalTimeOfLocalDay(d);
            }
        }
    } else if (o instanceof Date) {
        Date d = (Date) o;
        if (keepDate) {
            long milli = d.getTime();
            Double v = ((double) milli) / DateUtils.DAY_IN_MS;
            return v;
        } else {
            return DateUtils.decimalTimeOfLocalDay(d);
        }
    } else {
        throw new XPathTypeMismatchException("converting to date");
    }
}
Also used : XPathTypeMismatchException(org.javarosa.xpath.XPathTypeMismatchException) Date(java.util.Date)

Example 9 with XPathTypeMismatchException

use of org.javarosa.xpath.XPathTypeMismatchException in project javarosa by opendatakit.

the class XPathFuncExpr method eval.

/**
 * Evaluate the function call.
 *
 * First check if the function is a member of the built-in function suite. If not, then check
 * for any custom handlers registered to handler the function. If not, throw and exception.
 *
 * Both function name and appropriate arguments are taken into account when finding a suitable
 * handler. For built-in functions, the number of arguments must match; for custom functions,
 * the supplied arguments must match one of the function prototypes defined by the handler.
 */
public Object eval(DataInstance model, EvaluationContext evalContext) {
    String name = id.toString();
    Object[] argVals = new Object[args.length];
    HashMap<String, IFunctionHandler> funcHandlers = evalContext.getFunctionHandlers();
    // TODO: Func handlers should be able to declare the desire for short circuiting as well
    if (name.equals("if")) {
        assertArgsCount(name, args, 3);
        return ifThenElse(model, evalContext, args, argVals);
    } else if (name.equals("coalesce")) {
        assertArgsCount(name, args, 2);
        argVals[0] = args[0].eval(model, evalContext);
        if (!isNull(argVals[0])) {
            return argVals[0];
        } else {
            // that was null, so try the other one...
            argVals[1] = args[1].eval(model, evalContext);
            return argVals[1];
        }
    } else if (name.equals("indexed-repeat")) {
        if ((args.length == 3 || args.length == 5 || args.length == 7 || args.length == 9 || args.length == 11)) {
            return indexedRepeat(model, evalContext, args, argVals);
        } else {
            throw new XPathUnhandledException("function \'" + name + "\' requires " + "3, 5, 7, 9 or 11 arguments. Only " + args.length + " provided.");
        }
    }
    for (int i = 0; i < args.length; i++) {
        argVals[i] = args[i].eval(model, evalContext);
    }
    // check built-in functions
    if (name.equals("true")) {
        assertArgsCount(name, args, 0);
        return Boolean.TRUE;
    } else if (name.equals("false")) {
        assertArgsCount(name, args, 0);
        return Boolean.FALSE;
    } else if (name.equals("boolean")) {
        assertArgsCount(name, args, 1);
        return toBoolean(argVals[0]);
    } else if (name.equals("number")) {
        assertArgsCount(name, args, 1);
        return toNumeric(argVals[0]);
    } else if (name.equals("int")) {
        // non-standard
        assertArgsCount(name, args, 1);
        return toInt(argVals[0]);
    } else if (name.equals("round")) {
        // Proximate XPath 3.0 and Excel-style round(value,decimal place)
        final int places;
        if (args.length == 1) {
            places = 0;
        } else {
            assertArgsCount(name, args, 2);
            places = toNumeric(argVals[1]).intValue();
        }
        return round(toNumeric(argVals[0]), places);
    } else if (name.equals("string")) {
        assertArgsCount(name, args, 1);
        return toString(argVals[0]);
    } else if (name.equals("date")) {
        // non-standard
        assertArgsCount(name, args, 1);
        return toDate(argVals[0], false);
    } else if (name.equals("date-time")) {
        // non-standard -- convert double/int/string to Date object
        assertArgsCount(name, args, 1);
        return toDate(argVals[0], true);
    } else if (name.equals("decimal-date-time")) {
        // non-standard -- convert string/date to decimal days off 1970-01-01T00:00:00.000-000
        assertArgsCount(name, args, 1);
        return toDecimalDateTime(argVals[0], true);
    } else if (name.equals("decimal-time")) {
        // non-standard -- convert string/date to decimal days off 1970-01-01T00:00:00.000-000
        assertArgsCount(name, args, 1);
        return toDecimalDateTime(argVals[0], false);
    } else if (name.equals("not")) {
        assertArgsCount(name, args, 1);
        return boolNot(argVals[0]);
    } else if (name.equals("boolean-from-string")) {
        assertArgsCount(name, args, 1);
        return boolStr(argVals[0]);
    } else if (name.equals("format-date")) {
        assertArgsCount(name, args, 2);
        return formatDateTime(argVals[0], argVals[1]);
    } else if (name.equals("abs")) {
        // XPath 3.0
        checkArity(name, 1, args.length);
        return Math.abs(toDouble(argVals[0]));
    } else if (name.equals("acos")) {
        // XPath 3.0
        checkArity(name, 1, args.length);
        return Math.acos(toDouble(argVals[0]));
    } else if (name.equals("asin")) {
        // XPath 3.0
        checkArity(name, 1, args.length);
        return Math.asin(toDouble(argVals[0]));
    } else if (name.equals("atan")) {
        // XPath 3.0
        checkArity(name, 1, args.length);
        return Math.atan(toDouble(argVals[0]));
    } else if (name.equals("atan2")) {
        // XPath 3.0
        checkArity(name, 2, args.length);
        return Math.atan2(toDouble(argVals[0]), toDouble(argVals[1]));
    } else if (name.equals("cos")) {
        // XPath 3.0
        checkArity(name, 1, args.length);
        return Math.cos(toDouble(argVals[0]));
    } else if (name.equals("exp")) {
        // XPath 3.0
        checkArity(name, 1, args.length);
        return Math.exp(toDouble(argVals[0]));
    } else if (name.equals("exp10")) {
        // XPath 3.0
        checkArity(name, 1, args.length);
        return Math.pow(10.0, toDouble(argVals[0]));
    } else if (name.equals("log")) {
        // XPath 3.0
        checkArity(name, 1, args.length);
        return Math.log(toDouble(argVals[0]));
    } else if (name.equals("log10")) {
        // XPath 3.0
        checkArity(name, 1, args.length);
        return Math.log10(toDouble(argVals[0]));
    } else if (name.equals("pi")) {
        // XPath 3.0
        checkArity(name, 0, args.length);
        return Math.PI;
    } else if (name.equals("sin")) {
        // XPath 3.0
        checkArity(name, 1, args.length);
        return Math.sin(toDouble(argVals[0]));
    } else if (name.equals("sqrt")) {
        // XPath 3.0
        checkArity(name, 1, args.length);
        return Math.sqrt(toDouble(argVals[0]));
    } else if (name.equals("tan")) {
        // XPath 3.0
        checkArity(name, 1, args.length);
        return Math.tan(toDouble(argVals[0]));
    } else if (name.equals("format-date-time")) {
        // non-standard
        assertArgsCount(name, args, 2);
        return formatDateTime(argVals[0], argVals[1]);
    } else if ((name.equals("selected") || name.equals("is-selected"))) {
        // non-standard
        assertArgsCount(name, args, 2);
        return multiSelected(argVals[0], argVals[1], name);
    } else if (name.equals("count-selected")) {
        // non-standard
        assertArgsCount(name, args, 1);
        return countSelected(argVals[0]);
    } else if (name.equals("selected-at")) {
        // non-standard
        assertArgsCount(name, args, 2);
        return selectedAt(argVals[0], argVals[1]);
    } else if (name.equals("position")) {
        // TODO: Technically, only the 0 length argument is valid here.
        if (args.length == 1) {
            XPathNodeset nodes = (XPathNodeset) argVals[0];
            if (nodes.size() == 0) {
                // Will likely cause an error downstream when used in an XPath.
                return (double) (1 + TreeReference.INDEX_UNBOUND);
            } else {
                // if or how this might manifest into a bug... .
                return position(nodes.getRefAt(0));
            }
        } else if (args.length == 0) {
            if (evalContext.getContextPosition() != -1) {
                return (double) (1 + evalContext.getContextPosition());
            }
            return position(evalContext.getContextRef());
        } else {
            throw new XPathUnhandledException("function \'" + name + "\' requires either exactly one argument or no arguments. Only " + args.length + " provided.");
        }
    } else if (name.equals("count")) {
        assertArgsCount(name, args, 1);
        return count(argVals[0]);
    } else if (name.equals("count-non-empty")) {
        assertArgsCount(name, args, 1);
        return countNonEmpty(argVals[0]);
    } else if (name.equals("sum")) {
        assertArgsCount(name, args, 1);
        if (argVals[0] instanceof XPathNodeset) {
            return sum(((XPathNodeset) argVals[0]).toArgList());
        } else {
            throw new XPathTypeMismatchException("not a nodeset");
        }
    } else if (name.equals("max")) {
        if (args.length == 1 && argVals[0] instanceof XPathNodeset) {
            return max(((XPathNodeset) argVals[0]).toArgList());
        } else {
            return max(argVals);
        }
    } else if (name.equals("min")) {
        if (args.length == 1 && argVals[0] instanceof XPathNodeset) {
            return min(((XPathNodeset) argVals[0]).toArgList());
        } else {
            return min(argVals);
        }
    } else if (name.equals("today")) {
        assertArgsCount(name, args, 0);
        return DateUtils.roundDate(new Date());
    } else if (name.equals("now")) {
        assertArgsCount(name, args, 0);
        return new Date();
    } else if (name.equals("concat")) {
        if (args.length == 1 && argVals[0] instanceof XPathNodeset) {
            return join("", ((XPathNodeset) argVals[0]).toArgList());
        } else {
            return join("", argVals);
        }
    } else if (name.equals("join") && args.length >= 1) {
        if (args.length == 2 && argVals[1] instanceof XPathNodeset) {
            return join(argVals[0], ((XPathNodeset) argVals[1]).toArgList());
        } else {
            return join(argVals[0], subsetArgList(argVals, 1));
        }
    } else if (name.equals("substr") && (args.length == 2 || args.length == 3)) {
        return substring(argVals[0], argVals[1], args.length == 3 ? argVals[2] : null);
    } else if (name.equals("contains") && args.length == 2) {
        return toString(argVals[0]).contains(toString(argVals[1]));
    } else if (name.equals("starts-with") && args.length == 2) {
        return toString(argVals[0]).startsWith(toString(argVals[1]));
    } else if (name.equals("ends-with") && args.length == 2) {
        return toString(argVals[0]).endsWith(toString(argVals[1]));
    } else if (name.equals("string-length")) {
        assertArgsCount(name, args, 1);
        return stringLength(argVals[0]);
    } else if (name.equals("checklist") && args.length >= 2) {
        // non-standard
        if (args.length == 3 && argVals[2] instanceof XPathNodeset) {
            return checklist(argVals[0], argVals[1], ((XPathNodeset) argVals[2]).toArgList());
        } else {
            return checklist(argVals[0], argVals[1], subsetArgList(argVals, 2));
        }
    } else if (name.equals("weighted-checklist") && args.length >= 2 && args.length % 2 == 0) {
        // non-standard
        if (args.length == 4 && argVals[2] instanceof XPathNodeset && argVals[3] instanceof XPathNodeset) {
            Object[] factors = ((XPathNodeset) argVals[2]).toArgList();
            Object[] weights = ((XPathNodeset) argVals[3]).toArgList();
            if (factors.length != weights.length) {
                throw new XPathTypeMismatchException("weighted-checklist: nodesets not same length");
            }
            return checklistWeighted(argVals[0], argVals[1], factors, weights);
        } else {
            return checklistWeighted(argVals[0], argVals[1], subsetArgList(argVals, 2, 2), subsetArgList(argVals, 3, 2));
        }
    } else if (name.equals("regex")) {
        // non-standard
        assertArgsCount(name, args, 2);
        return regex(argVals[0], argVals[1]);
    } else if (name.equals("depend") && args.length >= 1) {
        // non-standard
        return argVals[0];
    } else if (name.equals("random")) {
        // non-standard
        assertArgsCount(name, args, 0);
        // calculated expressions may be recomputed w/o warning! use with caution!!
        return MathUtils.getRand().nextDouble();
    } else if (name.equals("once")) {
        assertArgsCount(name, args, 1);
        XPathPathExpr currentFieldPathExpr = XPathPathExpr.fromRef(evalContext.getContextRef());
        Object currValue = currentFieldPathExpr.eval(model, evalContext).unpack();
        if (currValue == null || toString(currValue).length() == 0) {
            // this is the "once" case
            return argVals[0];
        } else {
            return currValue;
        }
    } else if (name.equals("uuid") && (args.length == 0 || args.length == 1)) {
        // calculated expressions may be recomputed w/o warning! use with caution!!
        if (args.length == 0) {
            return PropertyUtils.genUUID();
        }
        int len = toInt(argVals[0]).intValue();
        return PropertyUtils.genGUID(len);
    } else if (name.equals("version")) {
        // non-standard
        assertArgsCount(name, args, 0);
        final String formVersion = (model instanceof FormInstance) ? ((FormInstance) model).formVersion : "";
        return formVersion == null ? "" : formVersion;
    } else if (name.equals("property")) {
        // non-standard
        // return a property defined by the property manager.
        // NOTE: Property should be immutable.
        // i.e., does not work with 'start' or 'end' property.
        assertArgsCount(name, args, 1);
        String s = toString(argVals[0]);
        return PropertyManager._().getSingularProperty(s);
    } else if (name.equals("pow") && (args.length == 2)) {
        // XPath 3.0
        double a = toDouble(argVals[0]);
        double b = toDouble(argVals[1]);
        return Math.pow(a, b);
    } else if (name.equals("enclosed-area") || name.equals("area")) {
        assertArgsCount(name, args, 1);
        Object argVal = argVals[0];
        if (!(argVal instanceof XPathNodeset)) {
            throw new XPathUnhandledException("function \'" + name + "\' requires a field as the parameter.");
        }
        Object[] argList = ((XPathNodeset) argVal).toArgList();
        int repeatSize = argList.length;
        List<GeoUtils.GPSCoordinates> gpsCoordinatesList;
        if (repeatSize == 1) {
            // Try to determine if the argument is of type GeoShapeData
            try {
                GeoShapeData geoShapeData = new GeoShapeData().cast(new UncastData(toString(argList[0])));
                if (geoShapeData.points.size() <= 2) {
                    return 0d;
                } else {
                    gpsCoordinatesList = new ArrayList<GeoUtils.GPSCoordinates>();
                    for (GeoPointData point : geoShapeData.points) {
                        gpsCoordinatesList.add(new GeoUtils.GPSCoordinates(point.getPart(0), point.getPart(1)));
                    }
                }
            } catch (Exception e) {
                throw new XPathTypeMismatchException("The function \'" + name + "\' received a value that does not represent GPS coordinates: " + argList[0]);
            }
        } else {
            if (repeatSize <= 2) {
                return 0d;
            } else {
                // treat the input as a series of GeoPointData
                gpsCoordinatesList = new ArrayList<GeoUtils.GPSCoordinates>();
                for (Object arg : argList) {
                    try {
                        GeoPointData geoPointData = new GeoPointData().cast(new UncastData(toString(arg)));
                        gpsCoordinatesList.add(new GeoUtils.GPSCoordinates(geoPointData.getPart(0), geoPointData.getPart(1)));
                    } catch (Exception e) {
                        throw new XPathTypeMismatchException("The function \'" + name + "\' received a value that does not represent GPS coordinates: " + arg);
                    }
                }
            }
        }
        return GeoUtils.calculateAreaOfGPSPolygonOnEarthInSquareMeters(gpsCoordinatesList);
    } else if (name.equals("digest") && (args.length == 2 || args.length == 3)) {
        return DigestAlgorithm.from((String) argVals[1]).digest((String) argVals[0], args.length == 3 ? Encoding.from((String) argVals[2]) : Encoding.BASE64);
    } else {
        // check for custom handler
        IFunctionHandler handler = funcHandlers.get(name);
        if (handler != null) {
            return evalCustomFunction(handler, argVals, evalContext);
        } else {
            throw new XPathUnhandledException("function \'" + name + "\'");
        }
    }
}
Also used : ArrayList(java.util.ArrayList) GeoPointData(org.javarosa.core.model.data.GeoPointData) IFunctionHandler(org.javarosa.core.model.condition.IFunctionHandler) XPathUnhandledException(org.javarosa.xpath.XPathUnhandledException) Date(java.util.Date) XPathUnhandledException(org.javarosa.xpath.XPathUnhandledException) UnpivotableExpressionException(org.javarosa.core.model.condition.pivot.UnpivotableExpressionException) IOException(java.io.IOException) XPathTypeMismatchException(org.javarosa.xpath.XPathTypeMismatchException) XPathArityException(org.javarosa.xpath.XPathArityException) DeserializationException(org.javarosa.core.util.externalizable.DeserializationException) GeoUtils(org.javarosa.core.util.GeoUtils) GeoShapeData(org.javarosa.core.model.data.GeoShapeData) UncastData(org.javarosa.core.model.data.UncastData) XPathNodeset(org.javarosa.xpath.XPathNodeset) ArrayList(java.util.ArrayList) List(java.util.List) XPathTypeMismatchException(org.javarosa.xpath.XPathTypeMismatchException) FormInstance(org.javarosa.core.model.instance.FormInstance)

Aggregations

XPathTypeMismatchException (org.javarosa.xpath.XPathTypeMismatchException)9 Date (java.util.Date)3 File (java.io.File)2 IOException (java.io.IOException)2 EvaluationContext (org.javarosa.core.model.condition.EvaluationContext)2 FormInstance (org.javarosa.core.model.instance.FormInstance)2 XPathNodeset (org.javarosa.xpath.XPathNodeset)2 XPathUnhandledException (org.javarosa.xpath.XPathUnhandledException)2 ArrayList (java.util.ArrayList)1 List (java.util.List)1 FormDef (org.javarosa.core.model.FormDef)1 FormIndex (org.javarosa.core.model.FormIndex)1 IFunctionHandler (org.javarosa.core.model.condition.IFunctionHandler)1 UnpivotableExpressionException (org.javarosa.core.model.condition.pivot.UnpivotableExpressionException)1 GeoPointData (org.javarosa.core.model.data.GeoPointData)1 GeoShapeData (org.javarosa.core.model.data.GeoShapeData)1 UncastData (org.javarosa.core.model.data.UncastData)1 InstanceInitializationFactory (org.javarosa.core.model.instance.InstanceInitializationFactory)1 TreeReference (org.javarosa.core.model.instance.TreeReference)1 RootTranslator (org.javarosa.core.reference.RootTranslator)1