schibsted / jslt

JSON query and transformation language
Apache License 2.0
638 stars 120 forks source link

Apache Camel JSLT component. #194

Open Shubham-1994 opened 3 years ago

Shubham-1994 commented 3 years ago

How can I use custom functions in jslt component by providing it as query parameter. Where can I find a detailed document on this other than https://camel.apache.org/components/3.7.x/jslt-component.html

larsga commented 3 years ago

I'm not familiar with that component, so I don't really know. Why would you want to pass the functions as a query parameter, though? Can't you always pass the same ones?

Shubham-1994 commented 3 years ago

Hi @larsga, thank you for the response. Actually I am using Apache Camel framework in Spring boot and want to do complex JSON transformation so I came to find the link here in the README.md in the More Information section as "Apache Camel JSLT component" (https://camel.apache.org/components/3.7.x/jslt-component.html) Finally I was able to use it and could write few JSLT expressions. But later I need few advanced features like using my custom function in jslt expression. But in the Camel documentation on JSLT I could not find such use cases.

larsga commented 3 years ago

If you want to define the function in JSLT you can just do that inline.

def plusone(x)
  $x + 1

plusone(2)

I was thinking about JSLT functions defined in Java, which might be more tricky.

catull commented 3 years ago

@Shubham-1994 Your question is too open-ended.

Perhaps you can give us some Java code and JSON input, so we can better understand your use-case.

Shubham-1994 commented 3 years ago

Hi @larsga, this is how we define method in JSLT, however my use case need to write methods in Java and pass it to JSLT component. @catull I am using Spring boot for my project, where I am using Apache Camel framework for integration with external system. So, there I am using JSLT component to do JSON transformation. For example

from("file:C:/files?noop=true").convertBodyTo(String.class)
        .log("${body}")
        .to("jslt:output.jslt?prettyPrint=true")
        .log("${body}");

Here, in output.jslt is my JSLT expression, for example

[
    for (.) if (checkCity(.CITY)) 
       { "myLocationId": .ADDR_ID, 
         "address1": checkAddress1(.ADDR_LINE1, .ADDR_LINE2, .ADDR_LINE3, .ADDR_LINE4, .CITY), 
         "address2" : string(.ADDR_LINE2), 
        "address3" : checkAddress3(.ADDR_LINE3, .ADDR_LINE4), 
        "cityId" : checkCity(.CITY) 
      }
   ]

And For example my JSON object is [ {
"ADDR_ID" : "1a", "ADDR_LINE1" : "200 West Street", "ADDR_LINE2" : "New York", "ADDR_LINE3" : "NY 1082", "ADDR_LINE4" : "USA", "CITY" : "NewYork" }, {
"ADDR_ID" : "1b", "ADDR_LINE1" : null, "ADDR_LINE2" : null , "ADDR_LINE3" : null, "ADDR_LINE4" : null, "CITY" : "NewYork" }, {
"ADDR_ID" : "1c", "ADDR_LINE1" : "", "ADDR_LINE2" : null , "ADDR_LINE3" : "", "ADDR_LINE4" : "USA", "CITY" : "NewYork" }, {
"ADDR_ID" : "2a", "ADDR_LINE1" : "200 West Street", "ADDR_LINE2" : "New York", "ADDR_LINE3" : "NY 1082", "ADDR_LINE4" : "USA", "CITY" : "NY" } ]

So, here I want to pass a method from my Java code to JSLT component. This is what I am looking for.

catull commented 3 years ago

A couple of question, I still do not understand what you would like to achieve.

First off, in

[
    for (.) if (checkCity(.CITY)) 
       { "myLocationId": .ADDR_ID, 
         "address1": checkAddress1(.ADDR_LINE1, .ADDR_LINE2, .ADDR_LINE3, .ADDR_LINE4, .CITY), 
         "address2" : string(.ADDR_LINE2), 
        "address3" : checkAddress3(.ADDR_LINE3, .ADDR_LINE4), 
        "cityId" : checkCity(.CITY) 
      }
   ]

What does checkCity() do ? What does checkAddress1() do ? What does checkAdress3() do ?

My understanding is, since .ADDR_LINE2 is a String, this ought to suffice

  // ......
 "address2" : .ADDR_LINE2, 
 // ....
catull commented 3 years ago

Are those methods above (checkCity(), checkAddress1() and checkAddress3()) that you want to use in output.jstl ?

Shubham-1994 commented 3 years ago

@catull checkCity(), checkAddress1() and checkAddress3() these are just methods which will just do few "if" checks and return a value, which I have defined in JSLT file only, but my need is to define the method in Java and pass it to the JSLT component

catull commented 3 years ago

So, are these implemented in output.jstl ?

You cannot pass a Java-method into schibsted's JSLT engine.

The way I see it is that you pre- or post-process what the JSLT engine transforms, in those Java methods. Or, you implement the logic contained in those Java methods, in pure JSLT.

Perhaps it helps to understand that schibsted's JSLT engine offers JSON -> JSON transformation.

Your job is to feed it JSON objects, and to interpret its result.

ppalaga commented 3 years ago

@Shubham-1994 you may want to ask your Camel specific question on Camel Users mailing list users@camel.apache.org or on their Zulip chat https://camel.zulipchat.com/

ppalaga commented 3 years ago

It does not look like you can do that via a route URI. But you can customize the component programmatically, like the Camel folks do in their test https://github.com/apache/camel/blob/main/components/camel-jslt/src/test/java/org/apache/camel/component/jslt/JsltFunctionsTest.java#L40

cvsudheer108 commented 3 years ago

You can define a custom function in Jslt as follows, not sure if this is what you were looking for..

def sum(array) if ($array) $array[0] + sum($array[1 : ]) else 0

let idparts = split(.id, "-") let xxx = [for ($idparts) "x" * size(.)]

{ "sum" : sum(.array), "id" : join($xxx, "-"), "type" : "Anonymized-View",