Home > Mobile >  evaluate JSON expression in child object
evaluate JSON expression in child object

Time:01-13

I am trying to evaluate json expression using Josson, but it gives invalid function error

String json ="{\"data\":{\"B\":\"calc(348 (96*$.SelectedPump.stg*$.ModelMaster.count))\"},\"SelectedPump\":{\"stg\":10,\"ab\":200},\"ModelMaster\":{\"count\":20}}";
        
Josson josson = Josson.fromJsonString(json.toString());
System.out.println(josson.getNode("data.eval(B)"));

Stacktrace:

Exception in thread "main" java.lang.IllegalArgumentException: Invalid function call eval() : Invalid function call calc() : Calc syntax error.
    at com.octomix.josson.FuncDispatcher.apply(FuncDispatcher.java:84)
    at com.octomix.josson.JossonCore.getPathBySteps(JossonCore.java:328)
    at com.octomix.josson.JossonCore.getPathBySteps(JossonCore.java:352)
    at com.octomix.josson.JossonCore.getPathBySteps(JossonCore.java:249)
    at com.octomix.josson.JossonCore.getPathByExpression(JossonCore.java:211)
    at com.octomix.josson.JossonCore.getNodeByExpression(JossonCore.java:147)
    at com.octomix.josson.JossonCore.getNodeByExpression(JossonCore.java:142)
    at com.octomix.josson.Josson.getNode(Josson.java:279)

CodePudding user response:

The variables inside the math equation cannot contains special characters. You need to use substitution. The variable name can whatever you want without special characters and .. So, the statement of B become...

calc(348 (96*A*B), A:SelectedPump.stg, B:ModelMaster.count)

The function eval() in query data.eval(B) works on node data. So the original evaluation statement needs $. to re-start from the root to get the value. For this revised version eval(data.B), eval() works on the root node with parameter data.B. And therefore, $. is not necessary.

String json =
    "{\n"  
    "    \"data\": {\n"  
    "        \"B\": \"calc(348 (96*A*B), A:SelectedPump.stg, B:ModelMaster.count)\"\n"  
    "    },\n"  
    "    \"SelectedPump\": {\n"  
    "        \"stg\": 10,\n"  
    "        \"ab\": 200\n"  
    "    },\n"  
    "    \"ModelMaster\": {\n"  
    "        \"count\": 20\n"  
    "    }\n"  
    "}";
Josson josson = Josson.fromJsonString(json);
System.out.println(josson.getNode("eval(data.B)"));
// Output: 19548.0

CodePudding user response:

Answer by Raymond Choi would be the best solution.


Alright, I have found a possible solution to this using Jossons template engine.

String json = "{\"data\":{\"B\":\"calc(348 (96*{{SelectedPump->stg}}*{{ModelMaster->count}}))\"},\"SelectedPump\":{\"stg\":10,\"ab\":200},\"ModelMaster\":{\"count\":20}}";

Jossons jossons = Jossons.fromJsonString(json);
String output = jossons.fillInPlaceholder("{\"s\":\"{{data->B}}\"}");
output = jossons.fillInPlaceholder(output);
System.out.println(output);
System.out.println(Josson.fromJsonString(output).getNode("$.eval(s)"));

It is necessary to adjust the JSON string to use placeholder to access the values from a different/nested node. We also have to create a new JSON string with a template that is filled in. Also also, it does sadly not recursively replace the placeholder, making it necessary to call jossons.fillInPlaceholder() two times. The first time it fetches the calculated formula and the second time it replaces the placeholder that are now present in the formula.

The output is:

output -> {"s":"calc(348 (96*10*20))"}
Josson.fromJsonString(output).getNode("$.eval(s)") -> 19548.0

The proposed code in the question fails, because Josson is not able to resolve nested/different node values. Pretty much as soon as we have a . present in the calc() formula, the syntax check fails. It is however possible to access nodes at the same level. So a JSON like this:

{
  "data" : {
    "B" : "calc(348 (96*SelectedPumpStg*ModelMasterCount))",
    "SelectedPumpStg" : 10,
    "ModelMasterCount" : 20
  }
}

can be evaluated by:

String json = "{\"data\":{\"B\":\"calc(348 (96*SelectedPumpStg*ModelMasterCount))\",\"SelectedPumpStg\":10,\"ModelMasterCount\":20}}";
Josson josson = Josson.fromJsonString(json.toString());
System.out.println(josson.getNode("data.eval(B)"));

resulting in the same: 19548.0.

Either way, the input JSON has to be adjusted to work with Josson

  • Related