Jolt
一个用 Java 编写的 JSON 到 JSON 的转换工具,其中转换的规则(Spec)本身也是一个 JSON;Jolt专注于转换 JSON 数据的结构,而不是处理数据
1. Spec匹配语法-LHS
LHS用来匹配并定位原始JSON中的key。
1.1 语法:「 key 」
- LHS
- 直接用原 json 中 key 名称一一对应匹配,图中 pointName, time 等字段
1.2 语法:「 key? 」
- LHS
- 对 modify-default-beta 操作生效
- 当 key 带有 ? 后缀,意味着仅当输入实际上有 key 字段时才会匹配
- 当 key 对应的 value 不为null时,映射后的值为原值;如果 value 为 null 则会用spec中设定的值填充
示例:
[
{
"pointName": "H_ZG_DT_Per7_hLPTExtrStmRef",
"time": "1623030600",
"value": "2319.208",
"status": 0,
"lzz": "aaa"
},
{
"pointName": "H_ZG_DT_Per7_hLPTIn",
"time": "1623030600",
"value": "3042.119",
"status": 0,
"lzz": null
},
{
"pointName": "H_ZG_DT_Per7_hLkA",
"time": "1623030600",
"value": "3209.765",
"status": 0
}
]
//lzz?字段指定了a,当原数据中存在这个字段,且value为null时会填充 a,否则会使用原来的value;当不存在lzz这个字段时会忽略不计
[
{
"operation": "modify-default-beta",
"spec": {
"*": {
"lzz?": "a"
}
}
}
]
1.3 语法:「 * 」
- LHS
- 可以匹配整个 key 字符串,图中用"*”匹配 JSON 数组下的全部 JSON 对象
- 也可以用于匹配key字符串的一部分,比如匹配 ’p-‘ 开头的 key 可以用 'p-'。( 的位置可以任意放)
1.4 语法:「 $ 」
- LHS
- 用来取 (或其他) 匹配到的节点的 key,一般结合 来使用
- $(0)表示当前对象的key,其中0可以省略;\$(0,5)表示取当前对象key的第5个星号部分
- $还可以用来将当前的key转换为新映射json的value
示例:
[
{
"pointName": "H_ZG_DT_Per7_hLPTExtrStmRef",
"time": "1623030600",
"value": "2319.208",
"status": 0
}
]
// "*_*_*_*_*" 会匹配到原json中pointName的value,因为它下面没有更下一层的key了;[&3]表示向上回退3层key,下面介绍映射语法会提到
[
{
"operation": "shift",
"spec": {
"*": {
"pointName": {
"*_*_*_*_*": {
"$(0,5)": "[&3].pointName",
"$": "[&3].srcName"
}
},
"*": "[&1].&"
}
}
}
]
//将key映射为value的方式
{
"rating": {
"primary": {
"value": 3,
"max": 5
},
"quality": {
"value": 3,
"max": 7
}
}
}
//#######
{
"rating": {
"*": { // 匹配"rating"下所有的key
"$": "ratings" // 将每个key映射到新json的ratings字段
}
}
}
结果:
{
"ratings" : [ "primary", "quality" ]
}
1.5 语法:「 | 」
- LHS
- 以or匹配多个key,映射到新的key
示列:
{
"x": [3,2,1,"go"],
"small": "small",
"BIG": "BIG",
"people": [
{
"firstName": "Bob",
"lastName": "Smith",
"address": {
"state": null
}
},
{
"firstName": "Sterling",
"lastName": "Archer"
}
]
}
//#########
[
{
"operation": "shift",
"spec": {
"BIG|small": "big-small",
"*": "&"
}
}
]
//结果
{
"x" : [ 3, 2, 1, "go" ],
"big-small" : [ "small", "BIG" ],
"people" : [ {
"firstName" : "Bob",
"lastName" : "Smith",
"address" : {
"state" : null
}
} ]
}
1.6 语法:「 @ 」
- LHS和RHS
- @表示将value映射到新的json的制定key中
- $和@分别匹配原JSON的key和value
LHS示例:
{
"foo": "aaa"
}
//#######
[
{
"operation": "shift",
"spec": {
"foo": {
"$": "place.key",
"@": "place.value"
}
}
}
]
//结果
{
"place": {
"key": "foo",
"value": "aaa"
}
}
RHS示例:
{
"author" : "Stephen Hawking",
"book" : "A Brief History of Time"
}
//########
[{
"operation": "shift",
"spec": {
"@book": "@author"
}
}]
//结果:
{
"Stephen Hawking": "A Brief History of Time"
}
2.Spec映射语法-RHS
RHS用来将LHS匹配到的值映射到最终结果JSON的指定位置
2.1 语法:「 . 」
- RHS默认使用扁平化的「.」结构来映射到新json结构
2.2 语法:「 & 」
- &表示取当前层的key作为映射后的key,& = &0 = &(0) = &(0,0)
- &1 表示取上一层key作为映射后的key
- &(0,1)表示取key的一部分,第二个参数是与通配符「*」一起使用的,表示取第几个「*」
- 在数组中时使用:[&1],可以参考 语法2.4
示例1:&和&2
{
"aoo": {
"boo": {
"coo": "value",
"doo": {
"foo": true
}
}
}
}
//########
{
"aoo": {
"boo": {
"doo": {
"foo": "&"
},
"*": "&2" //"&"得到的key是coo,"&1"是boo,"&2"是aoo
}
}
}
//结果
{
"aoo": "value",
"foo": true
}
示例2:&(0,1)
{
"tag-Pro": "Awesome",
"tag-Con": "Bogus"
}
//########
{
"tag-*": "&(0,1)" //"&(0,1)"表示取第1个「*」部分内容作为输出的key
}
//结果
{
"Pro": "Awesome",
"Con": "Bogus"
}
2.3 语法:「 @ 」
- 在RHS的作用和LHS一致,具体可参考 语法 2.6
2.4 语法:「 # 」
- LHS:表示常量
- RHS:只在数组中有效 ,比如“[#2]”,“[#2”]的意思是,向上两层并询问该节点有多少匹配,然后将其用作数组中的索引
LHS示例:
{
"ratings": {
"primary": 5,
"quality": 4,
"design": 5
}
}
//######
{
"ratings": {
"*": {
"#lezw": "Ratings[#2].Const",
"$": "Ratings[#2].Name",
"@": "Ratings[#2].Value"
}
}
}
//结果
{
"Ratings": [
{
"Const": "lezw",
"Name": "primary",
"Value": 5
},
{
"Const": "lezw",
"Name": "quality",
"Value": 4
},
{
"Const": "lezw",
"Name": "design",
"Value": 5
}
]
}
RHS示例:
{
"ratings": {
"primary": 5,
"quality": 4,
"design": 5
}
}
//######
{
"ratings": {
"*": {
"$": "Ratings[#2].Name",
"@": "Ratings[#2].Value"
}
}
}
//结果
{
"Ratings": [{
"Name": "primary",
"Value": 5
}, {
"Name": "quality",
"Value": 4
}, {
"Name": "design",
"Value": 5
}]
}
3.Spec操作类型
- Shift :复制输入json到输出json
- Default :为json树增加默认值
- Remove:从json树中去除数据
- sort:按字母顺序排序映射键值
- cardinality:修正输入数据的基数
- modify-overwrite-beta:总是写
- modify-default-beta:当键值对应的值是null时写入
- modify-define-beta:当键值不存在时写入
- custom:实现 Transform或ContextualTransform接口,可选择SpecDriven接口
- chainr:Chainr 是一种机制,可以把多个转换 Spec 连接在一起实现链式转换
3.1 shift
指定来自输入JSON的数据应该放在输出JSON中的什么位置,也就是输入JSON的数据应该如何进行移位
在Shift中,输入路径是JSON树结构,输出路径是扁平的点标记法路径
3.2 default
- 不破环原json结构,追加默认值
- 如果对应的字段已存在,不会修改原值,如果不存在,追加spec设置的值
示例:
{
"foo": "value"
}
//########
[
{
"operation": "defalut",
"spec": {
"foo": "key",
"boo": "value"
}
}
]
//结果
{
"foo": "value",
"boo": "value"
}
3.3 remove
- 删除原json中指定的key
3.4 cardinality
- 改变输入JSON数据元素的基数(对象和数组)
- 将对象改为数组或这将数组转换为对象
3.5 sort
- 递归地将JSON对象内的所有映射排序为新的已排序的LinkedHashMaps
- 按原json的key排序
3.6 modify
3.6.1 modify-overwrite-beta
- 总是写
3.6.2 modify-default-beta
- 当key对应的value是null时写
3.6.3 modify-define-beta
- 当key不存在时写入
3.7 custom
完全限定的Java ClassName:类实现Transform 或ContextualTransform接口,并且可以选择是SpecDriven 的(标记接口)
Transform
SpecDriven
3.8 chain
- Chain是一种机制,可以把多个转换Spec连接在一起
4.使用示例
4.1 给JSON Key加前缀
//输入为JSON Object,每个key都增加 ”ent:“ 前缀
{
"operation": "shift",
"spec": {
"*": {
"*": "ent:&"
}
}
}
4.2 数组映射为另外一个数组
//输入为JSON数组
[
{
"operation":"shift",
"spec":{
"E_TAB":{
"*":{
"AUFNR":["POList.[&1].MOCODE","POList.[&1].MOBOM"],
"AUART":"POList.[&1].MOTYPE",
"PLNBEZ":"POList.[&1].ITEMCODE",
"WERKS":"POList.[&1].ORGID",
"GAMNG":"POList.[&1].MOPLANQTY",
"GMEIN":"POList.[&1].MUOM",
"GSTRP":"POList.[&1].MOPLANSTARTDATE",
"GLTRP":"POList.[&1].MOPLANENDDATE",
"KDAUF_AUFK":"POList.[&1].ORDERNO",
"KDPOS_AUFK":"POList.[&1].ORDERSEQ",
"ERDAT":"POList.[&1].MDATE",
"ERFZEIT":"POList.[&1].MTIME",
"BSTKD":"POList.[&1].CUSORDERNO",
"IDNLF":"POList.[&1].NONSTANDARDNO",
"ZIDNL":"POList.[&1].CONFIGNO",
"AFNAM":"POList.[&1].APPUSER",
"ZOLD":"POList.[&1].AGINGLENGTH",
"LOEKZ":"POList.[&1].CANLEL",
"PHAS3":"POList.[&1].CLOSE",
"ZTEXT":"POList.[&1].SPECIALDEMAND",
"ZASSY":"POList.[&1].ASSYCX",
"ZZMAKTX":"POList.[&1].PREFERMATDEC",
"PHAS1":"POList.[&1].PHAS1",
"PHAS2":"POList.[&1].PHAS2"
}
}
}
},
{
"operation":"modify-define-beta",
"spec":{
"TransactionCode":null
}
}
]
4.3 替换JSON中指定key的值
方法1: JOLT转换DSL选择:Modify-Overwrite
{
"customer":"替换后的值"
}
方法2:DSL选择链式
[{
"operation": "modify-overwrite-beta",
"spec": {
"info": "ad"
}
}]
4.5 过滤JSON数组中某个字段匹配指定值的部分(QueryRecord)
1.使用移位操作,先指定流文件属性值searchKey和searchContainsValue,searchKey为准备过滤的字段,searchContainsValue为过滤的值
{
"*": {
"${searchKey}": {
"${searchContainsValue}*": {
"@2": "[]"
},
"*${searchContainsValue}*": {
"@2": "[]"
},
"*${searchContainsValue}": {
"@2": "[]"
}
}
}
}
eg: json
[
{ "KOSTL": "0100101010", "LTEXT": "办公室", "BUKRS": "0100", "PRCTR": "0100999999", "FUNC_AREA": "Y000" }
,
{ "KOSTL": "0100102010", "LTEXT": "人力资源部(停用)", "BUKRS": "0100", "PRCTR": "0100999999", "FUNC_AREA": "Y000" }
,
{ "KOSTL": "0100103010", "LTEXT": "财务资产管理部", "BUKRS": "0100", "PRCTR": "0100999999", "FUNC_AREA": "Y000" }
,
{ "KOSTL": "0100104010", "LTEXT": "资金运营管理中心", "BUKRS": "0100", "PRCTR": "0100999999", "FUNC_AREA": "Y000" }
,
{ "KOSTL": "0100105010", "LTEXT": "投资与金融产业部", "BUKRS": "0100", "PRCTR": "0100999999", "FUNC_AREA": "Y000" }
]
流文件属性:
searchContainsValue:停用
searchKey:LTEXT
4.6 JSON原样输出(数组及对象)
//JSONObject
{
"*":{
"@":"&0"
}
}
//JSONArray
{
"*": {
"@": "[&1]"
}
}
4.7 JSON新增字段
{
"MT_EBID2ECC_BR_T": {
"SALES_RECORD": {
"ZJBRQ": "2021-12-20",
"ZKBRQ": "2021-12-20",
"ZFSRQ2": "2021-12-20",
"ZGGRQ": "2021-12-20",
"ZFSRQ1": "2021-12-20",
"ZJBSJ": "09:00:00",
"ZKBSJ": "09:00:00"
},
"R_INDEX": "Z15_10010",
"MESSAGEHEDAER": {
"InterfaceId": "ZB_YSD",
"MessageId": 10010
},
"BIZ_IND": "Z15"
}
}
Jolt spec(MESSAGEHEDAER新增4个字段)
[ {
"operation" : "modify-define-beta",
"spec" : {
"MT_EBID2ECC_BR_T" : {
"MESSAGEHEDAER" : {
"Sender" : "ESB",
"SendTime" : "${now():format('HH:mm:ss')}",
"SendDate" : "${now():format('yyyy-MM-dd')}",
"Receiver" : "05"
}
}
}
} ]
4.8 JSON数组替换key名称
[{
"申请金额":1,
"客户性质":"OD",
"品牌名称":"滴露"
}]
Jolt spec
{
"*":{
"申请金额":"[&1].request_cost_cny",
"客户性质":"[&1].customer_type",
"品牌名称":"[&1].brand_name"
}
}
4.9 JSON对象转数组
{
"tradingPartner" : "78401",
"transactionReference" : "test2022022201",
"timeStamp" : "test2022022201",
"transactionDate" : "2022-02-19",
"companyCode" : "00784",
"detailLines": [
{
"documentType":"aaa"
}
]
}
Jolt Spec:
[
{
"operation" : "shift",
"spec" : {
"tradingPartner" : [ "[#0].M1PNID", "[#0].M1AN8" ],
"transactionReference" : "[#0].M1VR01",
"timeStamp" : "[#0].M1URRF",
"companyCode" : "[#0].M1EKCO",
"detailLines" : {
"0" : {
"documentType" : "[#0].M1EDCT"
}
}
}
}
]
或着:
[ {
"operation" : "shift",
"spec" : {
"*" : "[#2].&",
"detailLines" : {
"0" : {
"documentType" : "[#0].M1EDCT"
}
}
}
} ]
转换结果:
[ {
"M1PNID" : "78401",
"M1AN8" : "78401",
"M1VR01" : "test2022022201",
"M1URRF" : "test2022022201",
"M1EKCO" : "00784",
"M1EDCT" : "aaa"
} ]
4.10 substring函数使用
{
"Remarks": "COMMENTS:(87) Test Comments"
}
Jolt spec:
[
{
"operation": "modify-overwrite-beta",
"spec": {
"Remarks": "=substring(@(1,Remarks), 8, 26)"
}
},
{
"operation": "modify-overwrite-beta",
"spec": {
"Remarks": "=concat('C', @(1,Remarks))"
}
},
{
"operation": "modify-default-beta",
"spec": {
"Id": "=substring(@(1,Remarks), 3, 5)"
}
}
]
转换结果:
{
"Remarks" : "C:(87) Test Comment",
"Id" : "87"
}
.11 String相关函数示列
{
"string": "the QuIcK brOwn fox",
"zeroIndex": 0,
"threeIndex": 3,
"trimMe": " tuna "
}
Jolt spec :
[
{
"operation": "modify-overwrite-beta",
"spec": {
"lower": {
"leading": "=toLower(@(2,string))",
"trailing": "=toLower(^value)",
"custom1": "=toLower(bazinga)",
"custom2": "=toLower('yabadabadoo')",
"badArgs1": "=toLower(@2)"
},
"upper": {
"leading": "=toUpper(@(2,string))",
"trailing": "=toUpper(^value)",
"custom1": "=toUpper(bazinga)",
"custom2": "=toUpper('yabadabadoo')",
"badArgs1": "=toLower(@2)"
},
"join": "=join('_' , @(1,lower.leading) , , @(1,lower.trailing))",
"concat": {
"basic": "=concat(@(2,lower.leading) , ' ' , @(2,lower.trailing))",
"parens": "=concat(@(2,lower.leading) , ' (', @(2,lower.trailing), ')')"
},
"substring": {
"basic1": "=substring(@(2,string), 0, 9)",
"basic2": "=substring(@(2,string), 4, 9)",
"outOfBounds1": "=substring(@(2,string), -4, 9)", // start是负数,非法
"outOfBounds2": "=substring(@(2,string), 0, 200)",// end 超过字符串长度,非法
"outOfBounds3": "=substring(@(2,string), 0, 20)",
"badArgs1": "=substring(0, 9, @(2, substring))",
"badArgs2": "=substring(0, 4, 9)",
"badArgs3": "=substring('', 0, 0)",
"badArgs4": "=substring('abc', 0, 0)",
"badArgs5": "=substring('abc', 1, 1)",
"badArgs6": "=substring('abc', 1, 0)",
"badArgs7": "=substring('abc', 0, 1, 2)",
"badArgs8": "=substring('abc', 0)",
"custom1": "=substring('the quick brown fox', 0, 15)",
"custom2": "=substring('the quick brown fox', 16, 19)",
"advancedLookupRanges": "=substring(@(2,string), @(2,zeroIndex), @(2,threeIndex))"
},
"trim": {
"trimed": "=trim(@(2,trimMe))"
},
"trimMe": "=trim"
}
}
]
转换结果:
{
"string":"the QuIcK brOwn fox",
"zeroIndex":0,
"threeIndex":3,
"trimMe":"tuna",
"lower":{
"leading":"the quick brown fox",
"custom1":"bazinga",
"custom2":"yabadabadoo"
},
"upper":{
"leading":"THE QUICK BROWN FOX",
"custom1":"BAZINGA",
"custom2":"YABADABADOO"
},
"join":"the quick brown fox_",
"concat":{
"basic":"the quick brown fox ",
"parens":"the quick brown fox ()"
},
"substring":{
"basic1":"the QuIcK",
"basic2":"QuIcK",
"custom1":"the quick brown",
"custom2":"fox",
"advancedLookupRanges":"the"
},
"trim":{
"trimed":"tuna"
}
}
4.12 数组遍历并在数组中增加值
{
"date": "2022-09-03 19:23:53",
"device_name": "数控内圆磨床032-013",
"device_id": "1144",
"sensor": [
{
"sensor_id": "5836",
"value": "1",
"sensor_name": "设备状态"
},
{
"sensor_id": "5842",
"value": "",
"sensor_name": "主轴负载"
},
{
"sensor_id": "5842",
"value": "",
"sensor_name": "主轴负载"
}
],
"status": "1"
}
jolt spec
[
{
"operation": "shift",
"spec": {
"sensor": {
"*": {
"*": "[#2].&",
"@(2,date)": "[#2].date",
"@(2,device_name)": "[#2].device_name",
"@(2,device_id)": "[#2].device_id"
}
}
}
}
]
转换结果:
[
{
"date": "2022-09-03 19:23:53",
"device_name": "数控内圆磨床032-013",
"device_id": "1144",
"sensor_id": "5836",
"value": "1",
"sensor_name": "设备状态"
},
{
"date": "2022-09-03 19:23:53",
"device_name": "数控内圆磨床032-013",
"device_id": "1144",
"sensor_id": "5842",
"value": "",
"sensor_name": "主轴负载"
},
{
"date": "2022-09-03 19:23:53",
"device_name": "数控内圆磨床032-013",
"device_id": "1144",
"sensor_id": "5842",
"value": "",
"sensor_name": "主轴负载"
}
]
4.13 数组中提取指定字段(门户提取API名称和请求路径)
{
"code": 200000,
"msg": "success",
"data": {
"id": 2601,
"createTime": "2022-03-25T06:30:19.000+0000",
"updateTime": "2022-03-25T06:30:25.000+0000",
"creator": "admin@orchsym.com",
"updater": "admin@orchsym.com",
"name": "test",
"description": null,
"partnerAPIPrivilegeVos": [
{
"projectId": 501,
"apiId": 55701,
"uuid": "185a8ee8-8e5f-442e-be93-d14320ce9941",
"read": true,
"execute": true,
"anonymousExecute": true,
"callStatus": 0,
"portalGroupId": 401,
"routeId": 55601,
"portalGroupName": "Default",
"routeUuid": "a0fcb552-d4ca-4137-a3fc-6051c8eb3af3",
"versionId": 2701,
"frequency": null,
"iptable": null,
"callTimes": 0,
"intoAppTime": 1648189825607,
"alertLevel": null,
"swagger": {
"showEnvPath": true,
"httpPort": 80,
"schemes": [
"http",
"https"
],
"envId": 101,
"versionName": "0.3",
"uuid": "185a8ee8-8e5f-442e-be93-d14320ce9941",
"httpsPort": 443,
"routePath": "/invoce/",
"apiPath": "open",
"host": "esbtest.sinochemitc.com",
"name": "发票开具",
"alias": "bw",
"routeStatus": 2,
"apiStatus": 2,
"apiId": 55701
},
"projectApi": {
"id": 55701,
"createTime": null,
"updateTime": null,
"creator": null,
"updater": null,
"projectId": null,
"name": "发票开具",
"mockStatus": null,
"corsStatus": null,
"backendId": null,
"routeId": null,
"kongRouteId": null,
"status": 2,
"method": null,
"description": "",
"path": null,
"parameter": null,
"errorCode": null,
"mockResponse": null,
"corsConfig": null,
"versionId": null,
"properties": null,
"backendMessageLogConfig": null,
"response": null,
"uuid": "185a8ee8-8e5f-442e-be93-d14320ce9941",
"logoId": null,
"request": null,
"tagList": null
},
"routeName": "invoceOpenRoute",
"projectName": "百望发票业务",
"apiName": "发票开具",
"name": "发票开具",
"versionName": "0.3",
"appCreator": "",
"appName": "",
"privateConsumerId": null,
"enable": true,
"apiAuthApplication": null,
"alertLevels": null
}
],
"portalId": 401,
"partnerId": 1,
"privateConsumerId": "da23bf8b-e157-4e6f-9c15-c8759d975e20",
"authType": 1,
"appBasicAuth": null,
"appKey": {
"id": 901,
"createTime": "2022-03-25T06:30:19.000+0000",
"updateTime": "2022-03-25T06:30:25.000+0000",
"creator": "admin@orchsym.com",
"updater": "admin@orchsym.com",
"appId": 2601,
"appKey": "7cn01WbKDeWHJQta1V4YUZb5KLgAS1LB",
"expiredTime": null,
"kongAppName": "401_1_2601"
},
"partnerAppHmac": null,
"portalName": null,
"portalAlias": "por-bw",
"partnerName": null,
"kongAppName": "401_1_2601"
},
"originCode": 0,
"httpCode": 200,
"statusOk": true
}
jolt:
[
{
"operation": "shift",
"spec": {
"*": {
"partnerAPIPrivilegeVos": {
"*": {
"swagger": {
"host": "[#3].host",
"name": "[#3].name",
"routePath": "[#3].routePath",
"apiPath": "[#3].apiPath",
"alias": "[#3].projectPath",
"envId": "[#3].envId",
"@(3,portalAlias)": "[#3].portalPath",
"#https://": "[#3].protocol"
}
}
}
}
}
},
{
"operation": "modify-overwrite-beta",
"spec": {
"*": {
"path": "=concat(@(1,protocol),@(1,host),'/env-',@(1,envId),'/',@(1,portalPath),'/',@(1,projectPath),@(1,routePath), @(1,apiPath))"
}
}
},
{
"operation": "remove",
"spec": {
"*": {
"host": "",
"routePath": "",
"apiPath": "",
"projectPath": "",
"envId": "",
"protocol": "",
"portalPath": ""
}
}
}
]
4.14 将子节点层级提升到父节点
{
"Envelope": {
"Header": {
"@xmlns": "http://schemas.xmlsoap.org/soap/envelope/"
},
"Body": {
"request": {
"esbInfo": {
"attr2": "",
"attr3": "",
"attr1": "{\"bgy_zjcloud01\":\"Y\"}",
"requestTime": "2022-04-14 10:35:40:438",
"instId": "6cfff8a4-8666-4938-a8b8-33890844d3cb"
},
"requestInfo": {
"Item": {
"jirongmianji": 111452.02,
"dixiajianzhumianji": 14522.8,
"projectState": "在建",
"name": "广州增城派潭高滩碧桂园-二期(精装修)",
"code": "GQ.GZZCPTGTBG.06",
"taxType": "一般计税",
"jingguanmianji": 66119,
"kezubukeshoumianji": "",
"keshoumianji": 109007.16,
"bujirongmianji": "",
"pid": "GQ.GZZCPTGTBG",
"dishangjianzhumianji": 112380.71,
"zhandimianji": 114408.63,
"startDate": "",
"id": "e0b411cb-5169-40f7-a65e-7331f737a802",
"keshouchewei": 0,
"dixiachewei": "",
"jianzhumianji": 127453.41,
"productTypeList": {
"ProductType": [
{
"code": "CW004",
"description": "非人防地下室"
},
{
"code": "GY003",
"description": "一标平层公寓"
},
{
"code": "GY002",
"description": "二标LOFT公寓"
},
{
"code": "BS001",
"description": "二标田字拼别墅"
},
{
"code": "PT004",
"description": "千人会议厅"
},
{
"code": "GY003",
"description": "二标平层公寓"
},
{
"code": "BS003",
"description": "一标联排别墅"
},
{
"code": "BS002",
"description": "一标双拼别墅"
},
{
"code": "CW003",
"description": "人防地下室"
},
{
"code": "BS002",
"description": "一标别墅样板房"
}
]
},
"yuanjianmianji": 27803,
"bukezushoumianji": [
"",
""
],
"rongjilv": 0.97,
"valid": "",
"region_id": "027ad139-5018-e411-93ed-42f2e965677b",
"chewei": 421,
"dishangchewei": ""
}
}
},
"v1": "http://www.bgy.com.cn/CostingSB/Mycosting/v1.0",
"soapenv": "http://schemas.xmlsoap.org/soap/envelope/"
},
"soap-env": "http://schemas.xmlsoap.org/soap/envelope/"
}
}
- XML的Item去掉
- productTypeList 下的ProductType去掉
[
{
"operation": "shift",
"spec": {
"*": {
"*": {
"request": {
"requestInfo": {
"Item": {
"productTypeList": {
"ProductType": "&3.&1"
},
"*": "&2.&"
}
},
"esbInfo": {
"requestTime": "&1.&",
"instId": "&1.&"
}
}
}
}
}
}
]
4.15 去除JSON Key前缀
{
"v1:request": {
"v1:esbInfo": {
"v1:requestTime": "2022-04-14 10:35:40:438",
"v1:instId": "6cfff8a4-8666-4938-a8b8-33890844d3cb"
},
"v1:requestInfo": {
"v1:Item": {
"v1:id": "e0b411cb-5169-40f7-a65e-7331f737a802",
"v1:productTypeList": {
"v1:ProductType": [
{
"v1:code": "CW004",
}
]
},
"v1:region_id": "027ad139-5018-e411-93ed-42f2e965677b"
}
}
}
}
- 去除v1的前缀
[
{
"operation": "shift",
"spec": {
"*:*": {
"*:*": {
"*:*":"&(1,2).&(0,2)"
}
}
}
}
]
备注:&(1,2).&(0,2)
中,第一个数字表示取回退到第n层的key,第二个数字表示,用*
匹配key时的第n个部分,类似正则表达式的分组
4.16 JSON数组元素分组
需求:按照
SZEKCO
、SZEDOC
和SZEDCT
进行分组,并且将这 3 个字段提到上一级作为头部,剩余字段作为detailLines
[
{
"SZEKCO": "00784",
"SZEDOC": "1569304",
"SZEDCT": "SO",
"SZEDLN": "1000",
"SZLITM": "3032710 ",
"SZDSC1": "倍滑超薄装12只 ",
"SZUORG": "10000"
},
{
"SZEKCO": "00784",
"SZEDOC": "1569304",
"SZEDCT": "SO",
"SZEDLN": "2000",
"SZLITM": "3032711 ",
"SZDSC1": "倍滑超薄装3只 ",
"SZUORG": "20000"
},
{
"SZEKCO": "00785",
"SZEDOC": "1569304",
"SZEDCT": "SO",
"SZEDLN": "2000",
"SZLITM": "3032711 ",
"SZDSC1": "倍滑超薄装3只 ",
"SZUORG": "20000"
}
]
要求输出:
[
{
"SZEDCT": "00784",
"SZEDOC": "1569304",
"SZEKCO": "SO",
"detailLines": [
{
"SZEKCO": "00784",
"SZEDOC": "1569304",
"SZEDCT": "SO",
"SZEDLN": "1000",
"SZLITM": "3032710 ",
"SZDSC1": "倍滑超薄装12只 ",
"SZUORG": "10000"
},
{
"SZEKCO": "00784",
"SZEDOC": "1569304",
"SZEDCT": "SO",
"SZEDLN": "2000",
"SZLITM": "3032711 ",
"SZDSC1": "倍滑超薄装3只 ",
"SZUORG": "20000"
}
]
},
{
"SZEDCT": "00785",
"SZEDOC": "1569304",
"SZEKCO": "SO",
"detailLines": [
{
"SZEKCO": "00785",
"SZEDOC": "1569304",
"SZEDCT": "SO",
"SZEDLN": "2000",
"SZLITM": "3032711 ",
"SZDSC1": "倍滑超薄装3只 ",
"SZUORG": "20000"
}
]
}
]
JOLT Spec:
方式 1(通过将需要分组的字段组合成一个新字段,根据这个字段进行分组)
[
{
"operation": "modify-overwrite-beta",
"spec": {
"*": {
"Tag": "=concat(@(1,SZEKCO),'-',@(1,SZEDOC),'-',@(1,SZEDCT))"
}
}
},
{
"operation": "shift",
"spec": {
"*": {
"@": "@(0,Tag).detailLines.&"
}
}
},
{
"operation": "shift",
"spec": {
"*-*-*": {
"$(0,1)": "[#2].SZEKCO",
"$(0,2)": "[#2].SZEDOC",
"$(0,3)": "[#2].SZEDCT",
"detailLines": {
"*": {
"*": {
"@": "[#5].&3.[#3].&"
}
}
}
}
}
},
{
"operation": "remove",
"spec": {
"*": {
"detailLines": {
"*": {
"SZEKCO": "",
"SZEDOC": "",
"SZEDCT": "",
"Tag": ""
}
}
}
}
}
]方式2(将需要分组的字段作为输出的 key来分层)
[
{
"operation": "shift",
"spec": {
"*": {
"@": "@(1,SZEKCO).@(1,SZEDOC).@(1,SZEDCT).&"
}
}
},
{
"operation": "shift",
"spec": {
"*": {
"*": {
"*": {
"*": "&3-&2-&1.&"
}
}
}
}
},
{
"operation": "shift",
"spec": {
"*-*-*": {
"$(0,1)": "&1.SZEDCT",
"$(0,2)": "&1.SZEDOC",
"$(0,3)": "&1.SZEKCO",
"*": {
"*": "&2.detailLines.[#2].&"
}
}
}
},
{
"operation": "shift",
"spec": {
"*": "[]"
}
}
]
4.17 JSON对象往上提升层级
{
"3f8b72d1-c676-4d4b-b6ae-f5352ba8c0e7": {
"ab": "1",
"ac": "2"
}
}
Jolt spec
[
{
"operation": "shift",
"spec": {
"*": {
"@": ""
}
}
}
]