如何使用Josson递归计算JSON对象至第二层级表达式
递归计算JSON对象中的表达式(基于Josson库)
问题说明
我们使用Josson库处理JSON对象,需要递归计算所有层级中包含**expression**子字段的节点,将表达式计算结果替换原节点。
原始JSON
{ "selectionModel": { "dp_speed": "0", "moc": "CI-0" }, "data": { "B": "220", "h2": "1000", "h6": "175", "weight": { "expression": "calc(B+h2)" }, "height": { "expression": "calc(B+h6)" }, "columnPipe": { "pipeTotalWeight": { "expression": "calc(if(length==0,680,700),length:$.data.columnPipe.pipeTotalLength)" }, "pipeTotalLength": 1200, "PipeCapLiters": { "expression": "calc(if(length==0,70,100),length:$.data.columnPipe.pipeTotalLength)" }, "pipeTopPipeqty": 1 } }, "tbl05FlangeMasterDischarge": { "flangeId": 3835, "flangetype": "RF", "size": 150 } }
期望输出
{ "selectionModel": { "dp_speed": "0", "moc": "CI-0" }, "data": { "B": "220", "h2": "1000", "h6": "175", "weight": 1220.0, "height": 395.0, "columnPipe": { "pipeTotalWeight": 700.0, "pipeTotalLength": 1200, "PipeCapLiters": 100.0, "pipeTopPipeqty": 1 } }, "tbl05FlangeMasterDischarge": { "flangeId": 3835, "flangetype": "RF", "size": 150 } }
当前问题
现有代码仅能处理第一层级的表达式(如data下的weight、height),无法递归处理更深层级(如data.columnPipe下的节点):
当前代码
String a = "{\"selectionModel\":{\"dp_speed\":\"0\",\"moc\":\"CI-0\"},\"data\":{\"B\":\"220\",\"h2\":\"1000\",\"h6\":\"175\",\"weight\":{\"expression\":\"calc(B+h2)\"},\"height\":{\"expression\":\"calc(B+h6)\"},\"columnPipe\":{\"pipeTotalWeight\":{\"expression\":\"calc(if(length==0,680,700),length:$.data.columnPipe.pipeTotalLength)\"},\"pipeTotalLength\":1200,\"PipeCapLiters\":{\"expression\":\"calc(if(length==0,70,100),length:$.data.columnPipe.pipeTotalLength)\"},\"pipeTopPipeqty\":1}},\"tbl05FlangeMasterDischarge\":{\"flangeId\":3835,\"flangetype\":\"RF\",\"size\":150}}"; Josson josson = Josson.fromJsonString(a); String expression = josson.getString("entries()" + ".concat('field('," + " key," + " value.entries()" + " .[isNotEmpty(value.expression)]*" + " .concat('.field(',key,': eval(',key,'.expression))')" + " .join()," + " ')')" + ".join('.')"); System.out.println(expression); System.out.println(josson.getNode(expression));
当前输出
field(selectionModel).field(data.field(weight: eval(weight.expression)).field(height: eval(height.expression))).field(tbl05FlangeMasterDischarge) {"selectionModel":{"dp_speed":"0","moc":"CI-0"},"data":{"B":"220","h2":"1000","h6":"175","weight":1220.0,"height":395.0,"columnPipe":{"pipeTotalWeight":{"expression":"calc(if(length==0,680,700),length:$.data.columnPipe.pipeTotalLength)"},"pipeTotalLength":1200,"PipeCapLiters":{"expression":"calc(if(length==0,70,100),length:$.data.columnPipe.pipeTotalLength)"},"pipeTopPipeqty":1}},"tbl05FlangeMasterDischarge":{"flangeId":3835,"flangetype":"RF","size":150}}
解决方案
通过定义递归函数生成Josson表达式,实现全层级的表达式计算:
修改后的代码
String a = "{\"selectionModel\":{\"dp_speed\":\"0\",\"moc\":\"CI-0\"},\"data\":{\"B\":\"220\",\"h2\":\"1000\",\"h6\":\"175\",\"weight\":{\"expression\":\"calc(B+h2)\"},\"height\":{\"expression\":\"calc(B+h6)\"},\"columnPipe\":{\"pipeTotalWeight\":{\"expression\":\"calc(if(length==0,680,700),length:$.data.columnPipe.pipeTotalLength)\"},\"pipeTotalLength\":1200,\"PipeCapLiters\":{\"expression\":\"calc(if(length==0,70,100),length:$.data.columnPipe.pipeTotalLength)\"},\"pipeTopPipeqty\":1}},\"tbl05FlangeMasterDischarge\":{\"flangeId\":3835,\"flangetype\":\"RF\",\"size\":150}}"; Josson josson = Josson.fromJsonString(a); // 定义递归函数,遍历所有层级对象处理表达式 String recursiveExpr = "def recurse(obj) {" + " obj.entries().concat('field(', key, " + " (value.type() == 'OBJECT' ? " + " (value.entries().[isNotEmpty(value.expression)]*.concat('.field(', key, ': eval(', key, '.expression))').join() + recurse(value))" + " : '')," + " ')').join('.')" + "}"; // 执行递归函数生成完整处理表达式 String expression = josson.getString(recursiveExpr + "; recurse($)"); System.out.println(expression); System.out.println(josson.getNode(expression));
逻辑说明
- 递归函数
recurse(obj)会遍历对象的每个键值对:- 若值为对象类型,先处理当前层级的
**expression**节点,再递归处理子对象 - 自动拼接生成包含所有层级的
field()链式表达式,嵌入eval()计算逻辑
- 若值为对象类型,先处理当前层级的
- 最终生成的表达式会递归处理所有层级的表达式节点,得到符合预期的输出。
生成的目标表达式
field(selectionModel).field(data.field(weight: eval(weight.expression)).field(height: eval(height.expression)).field(columnPipe.field(pipeTotalWeight: eval(pipeTotalWeight.expression)).field(PipeCapLiters: eval(PipeCapLiters.expression)))).field(tbl05FlangeMasterDischarge)
内容的提问来源于stack exchange,提问作者Pranav
相关产品推荐
相关产品推荐

