XPTY0004: Required item type of first operand of '>' is numeric; supplied value has item type xs:string

VijayD :

The toComplie string contains all the definitions of the functions like sum, multiply, etc. appended by if ($a > 0) then (iaf:numeric-equal(iaf:numeric-multiply($b, $c), $d)) else (true())

The snippet executing this is :

XQueryExecutable queryExecutable = xqueryCompiler.compile(toCompile.toString());
XQueryEvaluator xqueryEvaluator = queryExecutable.load();

//setExternalVariables(): function used to set the variables for the test contains below line
        xqueryEvaluator.setExternalVariable(new QName(memberName), value);
setExternalVariables(xqueryEvaluator,assertionExpression);

xqueryResult = xqueryEvaluator.evaluate();

Which throws an exception as below:

XPTY0004: Required item type of the first operand of '>' is numeric; supplied value has item type xs:string


Please let me know if any more information is needed to understand the question. Is this because of the else part, or something else?

EDIT: In setExternalVariables(), I'm adding the variables using below line, using for-each loop. value variable is of type net.sf.saxon.s9api.XdmValue

xqueryEvaluator.setExternalVariable(new QName(memberName), value);

In setExternalVariables() method,

// FACT_VALUE_FORMAT:%s;%s --  where first string is value and second gives information about precision.
//current option
XdmAtomicValue atomicValue = new XdmAtomicValue(String.format(FACT_VALUE_FORMAT, fact.getValue(),getPrecision(fact.getDecimals())));
// alternative 1
atomicValue = new XdmAtomicValue(getDoubleValue(fact));
//alternative 2
atomicValue = new XdmAtomicValue(getStringValue(fact));

In getDoubleValue(),

    String precision = fact.getDecimals();
    BigDecimal value = new BigDecimal(fact.getValue());
    if((precision != null ) && (precision.equals(INF_STRING) == false )){
        if(Integer.parseInt(precision)>0){
            NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
            DecimalFormat df = (DecimalFormat)nf;

            // If the decimal value is greater than 0, then we need the decimal precision correct to n places of decimal
            df.setMaximumFractionDigits(Integer.parseInt(precision) + 1);
            double doublePrecision = Math.pow(10,-Integer.parseInt(precision))/2;
            df.setMaximumFractionDigits(Integer.parseInt(precision) + 1);
            precision = df.format(doublePrecision);
            System.out.println("doublePrecision\t:\t"+doublePrecision);
            return (double) Math.round(value.doubleValue() * doublePrecision) / doublePrecision;
        }else{

            int scale = (int) Math.pow(10, -Integer.parseInt(precision));
            System.out.println("scale\t:\t"+scale);
            return (double) Math.round(value.doubleValue() * scale) / scale;

        }
    }
    return value.doubleValue();

In getStringValue(),

    String value = fact.getValue();
    String decimal = fact.getDecimals();
    String DOT = "\\.";
    if(value.contains(".")){
        final int parseInt = Integer.parseInt(decimal);
        if(parseInt>0){
            String[]split = value.split(DOT);
            value = split[0];
            if(parseInt>=value.length()){
                return "0";
            }
            for (int i = 0; i < parseInt; i++) {
                char[] array =value.toCharArray();
                array[value.length()-i-1]="0".charAt(0);
                value = new String(array);
            }
        }else{
            final int parseNegativeInt = -Integer.parseInt(decimal);
            String[]split = value.split(DOT);
            String tempValue = split[1];
            if(tempValue.length()>parseNegativeInt){
                tempValue = tempValue.substring(0, parseNegativeInt);
            }
            value = split[0]+"."+tempValue;
        }
    }
    return value;

Current implementation and alternative(2) does not work for the rule mentioned above, and when I'm returning double, it transforms big numbers into expression containing char E, for e.g. 5.12344E12, which fails in other rules.

Error on line 199 of module with no systemId: FORG0001: Cannot convert string "1.089563E9" to xs:decimal: invalid character 'E' at iaf:splitValueThreshold() (module with no systemId#20) at iaf:numeric-equal() (module with no systemId#343)

Please suggest any other option.

Ghislain Fourny :

I second Martin's suggestion (I had first overlooked BigDecimal vs. BigDecimalValue).

Some alternatives also come to my mind based on Saxon's documentation:

atomicValue = new XdmAtomicValue(
    new BigDecimalValue(getDoubleValue(fact))
);

or to avoid going through doubles or BigDecimal, something like:

atomicValue = new XdmAtomicValue(
    (BigDecimalValue)BigDecimalValue.makeDecimalValue(getStringValue(fact), true)
);
// potentially adding an "instance of BigDecimalValue" check in the middle
// or bypassing all checks with 'false' instead of 'true'

Note: I am not sure I fully understand the issue that arises in other rules if an xs:double is passed instead of an xs:decimal. I suspect that there may be some casting back to xs:string involved in these other rules, as this is where an E could be introduced. XPath comparisons between numeric values of any types should be seamless.

In general (but I am only guessing here as I do not know the details involved, apart from seeing usage of EBA's interval arithmetic functions in the rule), I think it is probably a nice idea to align the types used in or passed to XBRL Formula rules with the original XBRL concept types (use xs:decimal for xbrli:decimalItemType (r) or xbrli:monetaryItemType (m), but xs:double for xbrli:doubleItemType, etc), as the lexical spaces will then match those used in the XBRL instances.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=467416&siteId=1