I am using JSONata for performing JSON to JSON transformation.
For some unique reasons, I want to merge two JSONata expressions :
As an example :
Parent Expression:
var script = `
{
"data":
{
"name" : data.payload.Name.(FirstName & ' ' & LastName),
"alias": data.payload.Name.(Salutation & ' ' & FirstName),
"active": data.payload.Status = 'New' ? true : false,
"signature": "Have good day ," & data.payload.Name.FirstName & "!"
}
}
`;
Also I have few simple assignment kind of JSONata expression like :
Expression 1 :
{
"source" : source
}
Expression 2 :
{
"data": {
"email" : data.payload.Email
}
}
I would like to add above two expressions to expressions defined using script
.
So after adding these two expressions, I should be able to get :
var script = `
{
"source": source,
"data":
{
"name" : data.payload.Name.(FirstName & ' ' & LastName),
"alias": data.payload.Name.(Salutation & ' ' & FirstName),
"active": data.payload.Status = 'New' ? true : false,
"signature": "Have good day ," & data.payload.Name.FirstName & "!",
"email": data.payload.Email
}
}
`;
How do I do using javascript/JSONata ?
Background and constraints :
Child Expressions (expression 1 and 2 in the example) (that is supposed to be added into Parent expression) will always be simple assignment like "a" : x.y.z or "b" : x
.
Child Expressions may already be present in parent expression. In that case, it replaces assignment.
Also I want to delete some json paths from parent expression (ofcouse , if it is present) like If delete path data.Email
.
What I have done ? :
Once I have JSON, I look for path mentioned in child expression (like data.Email)
Once I have done processing above JSON, I convert it to JSONata script by removing quotes using bunch of regex and then applying unescape() method for decoding.
The problem with this approach is :
I think that your best bet might be to translate your expressions to the JSONata AST and then merge them into a new AST.
Here's a super simple example:
const ast1 = jsonata(expr1).ast();
const ast2 = jsonata(expr1).ast();
if (ast1.type !== "unary" || ast2.type!== "unary") throw Error("Only support unary expressions")
const combinedAst = {
"type": "unary",
"value": "{",
"lhs": [...ast1.lhs, ast2.lhs]
}
// TODO: Serialize the AST or inject it into jsonata()
The problem is what to do with your new AST. In my case I also wrote a custom serializer to turn the AST back into a JSONata string, and evaluate that.
AST for Expression 1
{
"type": "unary",
"value": "{",
"position": 1,
"lhs": [
[
{
"value": "source",
"type": "string",
"position": 13
},
{
"type": "path",
"steps": [
{
"value": "source",
"type": "name",
"position": 22
}
]
}
]
]
}
AST for Expression 2
{
"type": "unary",
"value": "{",
"position": 1,
"lhs": [
[
{
"value": "data",
"type": "string",
"position": 10
},
{
"type": "unary",
"value": "{",
"position": 13,
"lhs": [
[
{
"value": "email",
"type": "string",
"position": 26
},
{
"type": "path",
"steps": [
{
"value": "data",
"type": "name",
"position": 33
},
{
"value": "payload",
"type": "name",
"position": 41
},
{
"value": "Email",
"type": "name",
"position": 47
}
]
}
]
]
}
]
]
}
Combined AST
{
"type": "unary",
"value": "{",
"position": 1,
"lhs": [
[
{
"value": "source",
"type": "string",
"position": 12
},
{
"type": "path",
"steps": [
{
"value": "source",
"type": "name",
"position": 20
}
]
}
],
[
{
"value": "data",
"type": "string",
"position": 30
},
{
"type": "unary",
"value": "{",
"position": 33,
"lhs": [
[
{
"value": "email",
"type": "string",
"position": 46
},
{
"type": "path",
"steps": [
{
"value": "data",
"type": "name",
"position": 53
},
{
"value": "payload",
"type": "name",
"position": 61
},
{
"value": "Email",
"type": "name",
"position": 67
}
]
}
]
]
}
]
]
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With