This is an automated email from the ASF dual-hosted git repository.

fmariani pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git

commit a3aba7638ed241ca7d4f4ca7e60f3e31579a76f5
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Jan 19 07:22:10 2026 +0100

    CAMEL-22871: camel-core - Add simple function to assign a variable (#20865)
---
 .../org/apache/camel/catalog/languages/simple.json |  61 +++++----
 .../language/csimple/joor/OriginalSimpleTest.java  |  51 +++++++
 .../jsonpath/JsonPathSimpleSetVariableTest.java    |  99 ++++++++++++++
 .../org/apache/camel/language/simple/simple.json   |  61 +++++----
 .../modules/languages/pages/simple-language.adoc   | 121 ++++++++++++++++-
 .../camel/language/csimple/CSimpleHelper.java      |  24 ++++
 .../camel/language/simple/SimpleConstants.java     |   6 +
 .../language/simple/SimpleExpressionBuilder.java   |  84 ++++++++++++
 .../simple/ast/SimpleFunctionExpression.java       | 146 +++++++++++++++++++++
 .../apache/camel/language/simple/SimpleTest.java   |  73 +++++++++++
 10 files changed, 666 insertions(+), 60 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
index 12c163c5398f..98ce8768f5ad 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/languages/simple.json
@@ -75,34 +75,37 @@
     "substringBetween(exp,after,before)": { "index": 49, "kind": "function", 
"displayName": "Substring Between", "group": "function", "label": "function", 
"required": false, "javaType": "int", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Returns a random number between min (included) and max (excluded).", "ognl": 
false, "suffix": "}" },
     "split(exp,separator)": { "index": 50, "kind": "function", "displayName": 
"Split String Values", "group": "function", "label": "function", "required": 
false, "javaType": "String[]", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Splits the message body\/expression as a String value using the separator into 
a String array", "ognl": false, "suffix": "}" },
     "capitalize(exp)": { "index": 51, "kind": "function", "displayName": 
"Capitalize String Values", "group": "function", "label": "function", 
"required": false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Capitalizes the message body\/expression as a String value (upper case every 
words)", "ognl": false, "suffix": "}" },
-    "random(min,max)": { "index": 52, "kind": "function", "displayName": 
"Random", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Returns a substring of 
the message body\/expression that are between after and before. Returns null if 
nothing comes between.", "ognl": false, "suffix": "}" },
-    "skip(num)": { "index": 53, "kind": "function", "displayName": "Skip First 
Items from the Message Body", "group": "function", "label": "function", 
"required": false, "javaType": "java.util.Iterator", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The skip function iterates the message body and skips 
the first number of items. This can be used with the Splitter EIP to split a 
message body and skip the first N number of  [...]
-    "convertTo(exp,type)": { "index": 54, "kind": "function", "displayName": 
"Convert To", "group": "function", "label": "function", "required": false, 
"javaType": "", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Converts the message body 
(or expression) to the specified type.", "ognl": true, "suffix": "}" },
-    "trim(exp)": { "index": 55, "kind": "function", "displayName": "Trim", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The trim function trims 
the message body (or expression) by removing all leading and trailing white 
spaces.", "ognl": false, "suffix": "}" },
-    "normalizeWhitespace(exp)": { "index": 56, "kind": "function", 
"displayName": "Normalize Whitspace", "group": "function", "label": "function", 
"required": false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Normalizes the whitespace in the message body (or expression) by cleaning up 
excess whitespaces.", "ognl": false, "suffix": "}" },
-    "length(exp)": { "index": 57, "kind": "function", "displayName": "Length", 
"group": "function", "label": "function", "required": false, "javaType": "int", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The payload length (number of bytes) of the 
message body (or expression).", "ognl": false, "suffix": "}" },
-    "size(exp)": { "index": 58, "kind": "function", "displayName": "Size", 
"group": "function", "label": "function", "required": false, "javaType": "int", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The size of the message body (or expression). 
If the payload is java.util.Collection or java.util.Map based then the size is 
the number of elements; otherwise the payload size in bytes.", "ognl": false, 
"suffix": "}" },
-    "uppercase(exp)": { "index": 59, "kind": "function", "displayName": 
"Uppercase", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Uppercases the message 
body (or expression)", "ognl": false, "suffix": "}" },
-    "lowercase(exp)": { "index": 60, "kind": "function", "displayName": 
"Lowercase", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Lowercases the message 
body (or expression)", "ognl": false, "suffix": "}" },
-    "concat(exp,exp,separator)": { "index": 61, "kind": "function", 
"displayName": "Concat", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Performs a string concat using two expressions (message body as default) with 
optional separator", "ognl": false, "suffix": "}" },
-    "collate(num)": { "index": 62, "kind": "function", "displayName": "Group 
Message Body into Sub Lists", "group": "function", "label": "function", 
"required": false, "javaType": "java.util.Iterator", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The collate function iterates the message body and 
groups the data into sub lists of specified size. This can be used with the 
Splitter EIP to split a message body and group\/ba [...]
-    "join(separator,prefix,exp)": { "index": 63, "kind": "function", 
"displayName": "Join", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
join function iterates the message body\/expression and joins the data into a 
string. The separator is by default a comma. The prefix is optional. The join 
uses the message body as source by default.  [...]
-    "messageHistory(boolean)": { "index": 64, "kind": "function", 
"displayName": "Print Message History", "group": "function", "label": 
"function", "required": false, "javaType": "String", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The message history of the current exchange (how it has 
been routed). This is similar to the route stack-trace message history the 
error handler logs in case of an unhandled exception. The b [...]
-    "uuid(type)": { "index": 65, "kind": "function", "displayName": "Generate 
UUID", "group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns a UUID using the 
Camel `UuidGenerator`. You can choose between `default`, `classic`, `short` and 
`simple` as the type. If no type is given, the default is used. It is also 
possible to use a custom `UuidG [...]
-    "hash(exp,algorithm)": { "index": 66, "kind": "function", "displayName": 
"Compute Hash Value", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Returns a hashed value (string in hex decimal) of the message body\/expression 
using JDK MessageDigest. The algorithm can be SHA-256 (default) or SHA3-256.", 
"ognl": false, "suffix": "}" },
-    "empty(type)": { "index": 67, "kind": "function", "displayName": "Create 
Empty Object", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Creates a new empty 
object (decided by type). Use `string` to create an empty String. Use `list` to 
create an empty `java.util.ArrayList`. Use `map` to create an empty 
`java.util.LinkedHashMap`.", "ognl": [...]
-    "iif(predicate,trueExp,falseExp)": { "index": 68, "kind": "function", 
"displayName": "If Then Else", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Evaluates the predicate and returns the value of trueExp or falseExp. This 
function is similar to the ternary operator in Java.", "ognl": false, "suffix": 
"}" },
-    "list(val...)": { "index": 69, "kind": "function", "displayName": "Create 
List of values", "group": "function", "label": "function", "required": false, 
"javaType": "java.util.ArrayList", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
list function creates an ArrayList with the given set of values.", "ognl": 
false, "suffix": "}" },
-    "map(key1,value1,...)": { "index": 70, "kind": "function", "displayName": 
"Create Map of pairs", "group": "function", "label": "function", "required": 
false, "javaType": "java.util.LinkedHashMap", "prefix": "${", "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "The map function creates a LinkedHashMap with the given set of 
pairs.", "ognl": false, "suffix": "}" },
-    "attachments": { "index": 71, "kind": "function", "displayName": 
"Attachments", "group": "function", "label": "function", "required": false, 
"javaType": "java.util.Map", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "All 
the attachments as a Map<String,DataHandler.", "ognl": false, "suffix": "}" },
-    "attachments.size": { "index": 72, "kind": "function", "displayName": 
"Attachments", "group": "function", "label": "function", "required": false, 
"javaType": "int", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The number of attachments. 
Is 0 if there are no attachments.", "ognl": false, "suffix": "}" },
-    "attachmentContentAsText": { "index": 73, "kind": "function", 
"displayName": "Attachment Content As Text", "group": "function", "label": 
"function", "required": false, "javaType": "String", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The content of the attachment as text (ie String).", 
"ognl": false, "suffix": "}" },
-    "attachmentContent": { "index": 74, "kind": "function", "displayName": 
"Attachment Content", "group": "function", "label": "function", "required": 
false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
content of the attachment", "ognl": false, "suffix": "}" },
-    "attachmentContentAs(type)": { "index": 75, "kind": "function", 
"displayName": "Attachment Content As", "group": "function", "label": 
"function", "required": false, "javaType": "Object", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The content of the attachment, converted to the given 
type.", "ognl": false, "suffix": "}" },
-    "attachmentHeader(key,name)": { "index": 76, "kind": "function", 
"displayName": "Attachment Header", "group": "function", "label": "function", 
"required": false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
attachment header with the given name.", "ognl": false, "suffix": "}" },
-    "attachmentHeader(key,name,type)": { "index": 77, "kind": "function", 
"displayName": "Attachment Header", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
attachment header with the given name, converted to the given type.", "ognl": 
false, "suffix": "}" },
-    "attachment(key)": { "index": 78, "kind": "function", "displayName": 
"Attachment", "group": "function", "label": "function", "required": false, 
"javaType": "jakarta.activation.DataHandler", "prefix": "${", "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "The DataHandler for the given attachment.", "ognl": true, 
"suffix": "}" },
-    "base64Encode(exp)": { "index": 79, "kind": "function", "displayName": 
"Base64 Encode", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Base64 encodes the 
message body (or expression)", "ognl": false, "suffix": "}" },
-    "base64Decode(exp)": { "index": 80, "kind": "function", "displayName": 
"Base64 Decode", "group": "function", "label": "function", "required": false, 
"javaType": "byte[]", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Base64 decodes the 
message body (or expression)", "ognl": false, "suffix": "}" }
+    "setHeader(name,type,exp)": { "index": 52, "kind": "function", 
"displayName": "Set Header", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sets a message header with the given expression (optional converting to the 
given type)", "ognl": false, "suffix": "}" },
+    "setVariable(name,type,exp)": { "index": 53, "kind": "function", 
"displayName": "Set Variable", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sets a variable with the given expression (optional converting to the given 
type)", "ognl": false, "suffix": "}" },
+    "random(min,max)": { "index": 54, "kind": "function", "displayName": 
"Random", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Returns a substring of 
the message body\/expression that are between after and before. Returns null if 
nothing comes between.", "ognl": false, "suffix": "}" },
+    "skip(num)": { "index": 55, "kind": "function", "displayName": "Skip First 
Items from the Message Body", "group": "function", "label": "function", 
"required": false, "javaType": "java.util.Iterator", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The skip function iterates the message body and skips 
the first number of items. This can be used with the Splitter EIP to split a 
message body and skip the first N number of  [...]
+    "convertTo(exp,type)": { "index": 56, "kind": "function", "displayName": 
"Convert To", "group": "function", "label": "function", "required": false, 
"javaType": "", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Converts the message body 
(or expression) to the specified type.", "ognl": true, "suffix": "}" },
+    "isEmpty(exp)": { "index": 57, "kind": "function", "displayName": "Is 
Empty", "group": "function", "label": "function", "required": false, 
"javaType": "boolean", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Whether the message 
body (or expression) is null or empty (list\/map types are tested if they have 
0 elements).", "ognl": false, "suffix": "}" },
+    "trim(exp)": { "index": 58, "kind": "function", "displayName": "Trim", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The trim function trims 
the message body (or expression) by removing all leading and trailing white 
spaces.", "ognl": false, "suffix": "}" },
+    "normalizeWhitespace(exp)": { "index": 59, "kind": "function", 
"displayName": "Normalize Whitspace", "group": "function", "label": "function", 
"required": false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Normalizes the whitespace in the message body (or expression) by cleaning up 
excess whitespaces.", "ognl": false, "suffix": "}" },
+    "length(exp)": { "index": 60, "kind": "function", "displayName": "Length", 
"group": "function", "label": "function", "required": false, "javaType": "int", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The payload length (number of bytes) of the 
message body (or expression).", "ognl": false, "suffix": "}" },
+    "size(exp)": { "index": 61, "kind": "function", "displayName": "Size", 
"group": "function", "label": "function", "required": false, "javaType": "int", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The size of the message body (or expression). 
If the payload is java.util.Collection or java.util.Map based then the size is 
the number of elements; otherwise the payload size in bytes.", "ognl": false, 
"suffix": "}" },
+    "uppercase(exp)": { "index": 62, "kind": "function", "displayName": 
"Uppercase", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Uppercases the message 
body (or expression)", "ognl": false, "suffix": "}" },
+    "lowercase(exp)": { "index": 63, "kind": "function", "displayName": 
"Lowercase", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Lowercases the message 
body (or expression)", "ognl": false, "suffix": "}" },
+    "concat(exp,exp,separator)": { "index": 64, "kind": "function", 
"displayName": "Concat", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Performs a string concat using two expressions (message body as default) with 
optional separator", "ognl": false, "suffix": "}" },
+    "collate(num)": { "index": 65, "kind": "function", "displayName": "Group 
Message Body into Sub Lists", "group": "function", "label": "function", 
"required": false, "javaType": "java.util.Iterator", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The collate function iterates the message body and 
groups the data into sub lists of specified size. This can be used with the 
Splitter EIP to split a message body and group\/ba [...]
+    "join(separator,prefix,exp)": { "index": 66, "kind": "function", 
"displayName": "Join", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
join function iterates the message body\/expression and joins the data into a 
string. The separator is by default a comma. The prefix is optional. The join 
uses the message body as source by default.  [...]
+    "messageHistory(boolean)": { "index": 67, "kind": "function", 
"displayName": "Print Message History", "group": "function", "label": 
"function", "required": false, "javaType": "String", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The message history of the current exchange (how it has 
been routed). This is similar to the route stack-trace message history the 
error handler logs in case of an unhandled exception. The b [...]
+    "uuid(type)": { "index": 68, "kind": "function", "displayName": "Generate 
UUID", "group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns a UUID using the 
Camel `UuidGenerator`. You can choose between `default`, `classic`, `short` and 
`simple` as the type. If no type is given, the default is used. It is also 
possible to use a custom `UuidG [...]
+    "hash(exp,algorithm)": { "index": 69, "kind": "function", "displayName": 
"Compute Hash Value", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Returns a hashed value (string in hex decimal) of the message body\/expression 
using JDK MessageDigest. The algorithm can be SHA-256 (default) or SHA3-256.", 
"ognl": false, "suffix": "}" },
+    "empty(type)": { "index": 70, "kind": "function", "displayName": "Create 
Empty Object", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Creates a new empty 
object (decided by type). Use `string` to create an empty String. Use `list` to 
create an empty `java.util.ArrayList`. Use `map` to create an empty 
`java.util.LinkedHashMap`.", "ognl": [...]
+    "iif(predicate,trueExp,falseExp)": { "index": 71, "kind": "function", 
"displayName": "If Then Else", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Evaluates the predicate and returns the value of trueExp or falseExp. This 
function is similar to the ternary operator in Java.", "ognl": false, "suffix": 
"}" },
+    "list(val...)": { "index": 72, "kind": "function", "displayName": "Create 
List of values", "group": "function", "label": "function", "required": false, 
"javaType": "java.util.ArrayList", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
list function creates an ArrayList with the given set of values.", "ognl": 
false, "suffix": "}" },
+    "map(key1,value1,...)": { "index": 73, "kind": "function", "displayName": 
"Create Map of pairs", "group": "function", "label": "function", "required": 
false, "javaType": "java.util.LinkedHashMap", "prefix": "${", "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "The map function creates a LinkedHashMap with the given set of 
pairs.", "ognl": false, "suffix": "}" },
+    "attachments": { "index": 74, "kind": "function", "displayName": 
"Attachments", "group": "function", "label": "function", "required": false, 
"javaType": "java.util.Map", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "All 
the attachments as a Map<String,DataHandler.", "ognl": false, "suffix": "}" },
+    "attachments.size": { "index": 75, "kind": "function", "displayName": 
"Attachments", "group": "function", "label": "function", "required": false, 
"javaType": "int", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The number of attachments. 
Is 0 if there are no attachments.", "ognl": false, "suffix": "}" },
+    "attachmentContentAsText": { "index": 76, "kind": "function", 
"displayName": "Attachment Content As Text", "group": "function", "label": 
"function", "required": false, "javaType": "String", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The content of the attachment as text (ie String).", 
"ognl": false, "suffix": "}" },
+    "attachmentContent": { "index": 77, "kind": "function", "displayName": 
"Attachment Content", "group": "function", "label": "function", "required": 
false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
content of the attachment", "ognl": false, "suffix": "}" },
+    "attachmentContentAs(type)": { "index": 78, "kind": "function", 
"displayName": "Attachment Content As", "group": "function", "label": 
"function", "required": false, "javaType": "Object", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The content of the attachment, converted to the given 
type.", "ognl": false, "suffix": "}" },
+    "attachmentHeader(key,name)": { "index": 79, "kind": "function", 
"displayName": "Attachment Header", "group": "function", "label": "function", 
"required": false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
attachment header with the given name.", "ognl": false, "suffix": "}" },
+    "attachmentHeader(key,name,type)": { "index": 80, "kind": "function", 
"displayName": "Attachment Header", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
attachment header with the given name, converted to the given type.", "ognl": 
false, "suffix": "}" },
+    "attachment(key)": { "index": 81, "kind": "function", "displayName": 
"Attachment", "group": "function", "label": "function", "required": false, 
"javaType": "jakarta.activation.DataHandler", "prefix": "${", "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "The DataHandler for the given attachment.", "ognl": true, 
"suffix": "}" },
+    "base64Encode(exp)": { "index": 82, "kind": "function", "displayName": 
"Base64 Encode", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Base64 encodes the 
message body (or expression)", "ognl": false, "suffix": "}" },
+    "base64Decode(exp)": { "index": 83, "kind": "function", "displayName": 
"Base64 Decode", "group": "function", "label": "function", "required": false, 
"javaType": "byte[]", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Base64 decodes the 
message body (or expression)", "ognl": false, "suffix": "}" }
   }
 }
diff --git 
a/components/camel-csimple-joor/src/test/java/org/apache/camel/language/csimple/joor/OriginalSimpleTest.java
 
b/components/camel-csimple-joor/src/test/java/org/apache/camel/language/csimple/joor/OriginalSimpleTest.java
index 485f1a20a4ea..5baf41eb3c38 100644
--- 
a/components/camel-csimple-joor/src/test/java/org/apache/camel/language/csimple/joor/OriginalSimpleTest.java
+++ 
b/components/camel-csimple-joor/src/test/java/org/apache/camel/language/csimple/joor/OriginalSimpleTest.java
@@ -2617,6 +2617,57 @@ public class OriginalSimpleTest extends 
LanguageTestSupport {
         assertEquals("carlsberg", s);
     }
 
+    @Test
+    public void testSetHeader() {
+        exchange.getMessage().setBody("Hello World");
+
+        Expression expression = 
context.resolveLanguage("csimple").createExpression("${setHeader(foo,${body})}");
+        Object s = expression.evaluate(exchange, String.class);
+        assertNull(s);
+        assertEquals("Hello World", exchange.getMessage().getHeader("foo"));
+
+        exchange.getMessage().setBody("123");
+        expression = 
context.resolveLanguage("csimple").createExpression("${setHeader(bar,int,${body})}");
+        s = expression.evaluate(exchange, String.class);
+        assertNull(s);
+        assertIsInstanceOf(Integer.class, 
exchange.getMessage().getHeader("bar"));
+        assertEquals(123, exchange.getMessage().getHeader("bar"));
+
+        // null should remove the variable
+        expression = 
context.resolveLanguage("csimple").createExpression("${setHeader(bar,${null})}");
+        s = expression.evaluate(exchange, String.class);
+        assertNull(s);
+        assertNull(exchange.getMessage().getHeader("bar"));
+    }
+
+    @Test
+    public void testSetVariable() {
+        exchange.getVariables().clear();
+        assertEquals(0, exchange.getVariables().size());
+        exchange.getMessage().setBody("Hello World");
+
+        Expression expression = 
context.resolveLanguage("csimple").createExpression("${setVariable(foo,${body})}");
+        Object s = expression.evaluate(exchange, String.class);
+        assertNull(s);
+        assertEquals("Hello World", exchange.getVariable("foo"));
+        assertEquals(1, exchange.getVariables().size());
+
+        exchange.getMessage().setBody("123");
+        expression = 
context.resolveLanguage("csimple").createExpression("${setVariable(bar,int,${body})}");
+        s = expression.evaluate(exchange, String.class);
+        assertNull(s);
+        assertIsInstanceOf(Integer.class, exchange.getVariable("bar"));
+        assertEquals(123, exchange.getVariable("bar"));
+        assertEquals(2, exchange.getVariables().size());
+
+        // null should remove the variable
+        expression = 
context.resolveLanguage("csimple").createExpression("${setVariable(bar,${null})}");
+        s = expression.evaluate(exchange, String.class);
+        assertNull(s);
+        assertNull(exchange.getVariable("bar"));
+        assertEquals(1, exchange.getVariables().size());
+    }
+
     @Override
     protected String getLanguageName() {
         return "csimple";
diff --git 
a/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathSimpleSetVariableTest.java
 
b/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathSimpleSetVariableTest.java
new file mode 100644
index 000000000000..a3a4afaf652f
--- /dev/null
+++ 
b/components/camel-jsonpath/src/test/java/org/apache/camel/jsonpath/JsonPathSimpleSetVariableTest.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.jsonpath;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+
+public class JsonPathSimpleSetVariableTest extends CamelTestSupport {
+
+    private final String MAPPING = """
+            {
+              "id": "${jsonpath($.id)}",
+              "type": "${header.type}",
+              "amount": ${jsonpath($.amount)},
+              "status": "${iif(${jsonpath($.amount)} > 100,HIGH,LOW)}"
+            }
+            """;
+
+    private final String MAPPING2 = """
+            ${setVariable(myVar,${jsonpath($.amount)})}
+            {
+              "id": "${jsonpath($.id)}",
+              "type": "${header.type}",
+              "amount": ${jsonpath($.amount)},
+              "status": "${iif(${variable.myVar} > 100,HIGH,LOW)}"
+            }
+            """;
+
+    private final String EXPECTED = """
+            {
+              "id": "123",
+              "type": "silver",
+              "amount": 444,
+              "status": "HIGH"
+            }""";
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            @Override
+            public void configure() {
+                from("direct:start")
+                        .transform().simple(MAPPING)
+                        .log("${body}")
+                        .to("mock:order");
+
+                from("direct:start2")
+                        
.transform().simple(MAPPING2).transform().simple("${trim()}")
+                        .log("${body}")
+                        .to("mock:order");
+            }
+        };
+    }
+
+    @Test
+    public void testMapping() throws Exception {
+        getMockEndpoint("mock:order").expectedBodiesReceived(EXPECTED);
+
+        template.sendBodyAndHeader("direct:start", """
+                {
+                  "id": 123,
+                  "amount": 444
+                }
+                """, "type", "silver");
+
+        MockEndpoint.assertIsSatisfied(context);
+    }
+
+    @Test
+    public void testMapping2() throws Exception {
+        getMockEndpoint("mock:order").expectedBodiesReceived(EXPECTED);
+
+        template.sendBodyAndHeader("direct:start2", """
+                {
+                  "id": 123,
+                  "amount": 444
+                }
+                """, "type", "silver");
+
+        MockEndpoint.assertIsSatisfied(context);
+    }
+
+}
diff --git 
a/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
 
b/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
index 12c163c5398f..98ce8768f5ad 100644
--- 
a/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
+++ 
b/core/camel-core-languages/src/generated/resources/META-INF/org/apache/camel/language/simple/simple.json
@@ -75,34 +75,37 @@
     "substringBetween(exp,after,before)": { "index": 49, "kind": "function", 
"displayName": "Substring Between", "group": "function", "label": "function", 
"required": false, "javaType": "int", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Returns a random number between min (included) and max (excluded).", "ognl": 
false, "suffix": "}" },
     "split(exp,separator)": { "index": 50, "kind": "function", "displayName": 
"Split String Values", "group": "function", "label": "function", "required": 
false, "javaType": "String[]", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Splits the message body\/expression as a String value using the separator into 
a String array", "ognl": false, "suffix": "}" },
     "capitalize(exp)": { "index": 51, "kind": "function", "displayName": 
"Capitalize String Values", "group": "function", "label": "function", 
"required": false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Capitalizes the message body\/expression as a String value (upper case every 
words)", "ognl": false, "suffix": "}" },
-    "random(min,max)": { "index": 52, "kind": "function", "displayName": 
"Random", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Returns a substring of 
the message body\/expression that are between after and before. Returns null if 
nothing comes between.", "ognl": false, "suffix": "}" },
-    "skip(num)": { "index": 53, "kind": "function", "displayName": "Skip First 
Items from the Message Body", "group": "function", "label": "function", 
"required": false, "javaType": "java.util.Iterator", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The skip function iterates the message body and skips 
the first number of items. This can be used with the Splitter EIP to split a 
message body and skip the first N number of  [...]
-    "convertTo(exp,type)": { "index": 54, "kind": "function", "displayName": 
"Convert To", "group": "function", "label": "function", "required": false, 
"javaType": "", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Converts the message body 
(or expression) to the specified type.", "ognl": true, "suffix": "}" },
-    "trim(exp)": { "index": 55, "kind": "function", "displayName": "Trim", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The trim function trims 
the message body (or expression) by removing all leading and trailing white 
spaces.", "ognl": false, "suffix": "}" },
-    "normalizeWhitespace(exp)": { "index": 56, "kind": "function", 
"displayName": "Normalize Whitspace", "group": "function", "label": "function", 
"required": false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Normalizes the whitespace in the message body (or expression) by cleaning up 
excess whitespaces.", "ognl": false, "suffix": "}" },
-    "length(exp)": { "index": 57, "kind": "function", "displayName": "Length", 
"group": "function", "label": "function", "required": false, "javaType": "int", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The payload length (number of bytes) of the 
message body (or expression).", "ognl": false, "suffix": "}" },
-    "size(exp)": { "index": 58, "kind": "function", "displayName": "Size", 
"group": "function", "label": "function", "required": false, "javaType": "int", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The size of the message body (or expression). 
If the payload is java.util.Collection or java.util.Map based then the size is 
the number of elements; otherwise the payload size in bytes.", "ognl": false, 
"suffix": "}" },
-    "uppercase(exp)": { "index": 59, "kind": "function", "displayName": 
"Uppercase", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Uppercases the message 
body (or expression)", "ognl": false, "suffix": "}" },
-    "lowercase(exp)": { "index": 60, "kind": "function", "displayName": 
"Lowercase", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Lowercases the message 
body (or expression)", "ognl": false, "suffix": "}" },
-    "concat(exp,exp,separator)": { "index": 61, "kind": "function", 
"displayName": "Concat", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Performs a string concat using two expressions (message body as default) with 
optional separator", "ognl": false, "suffix": "}" },
-    "collate(num)": { "index": 62, "kind": "function", "displayName": "Group 
Message Body into Sub Lists", "group": "function", "label": "function", 
"required": false, "javaType": "java.util.Iterator", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The collate function iterates the message body and 
groups the data into sub lists of specified size. This can be used with the 
Splitter EIP to split a message body and group\/ba [...]
-    "join(separator,prefix,exp)": { "index": 63, "kind": "function", 
"displayName": "Join", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
join function iterates the message body\/expression and joins the data into a 
string. The separator is by default a comma. The prefix is optional. The join 
uses the message body as source by default.  [...]
-    "messageHistory(boolean)": { "index": 64, "kind": "function", 
"displayName": "Print Message History", "group": "function", "label": 
"function", "required": false, "javaType": "String", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The message history of the current exchange (how it has 
been routed). This is similar to the route stack-trace message history the 
error handler logs in case of an unhandled exception. The b [...]
-    "uuid(type)": { "index": 65, "kind": "function", "displayName": "Generate 
UUID", "group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns a UUID using the 
Camel `UuidGenerator`. You can choose between `default`, `classic`, `short` and 
`simple` as the type. If no type is given, the default is used. It is also 
possible to use a custom `UuidG [...]
-    "hash(exp,algorithm)": { "index": 66, "kind": "function", "displayName": 
"Compute Hash Value", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Returns a hashed value (string in hex decimal) of the message body\/expression 
using JDK MessageDigest. The algorithm can be SHA-256 (default) or SHA3-256.", 
"ognl": false, "suffix": "}" },
-    "empty(type)": { "index": 67, "kind": "function", "displayName": "Create 
Empty Object", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Creates a new empty 
object (decided by type). Use `string` to create an empty String. Use `list` to 
create an empty `java.util.ArrayList`. Use `map` to create an empty 
`java.util.LinkedHashMap`.", "ognl": [...]
-    "iif(predicate,trueExp,falseExp)": { "index": 68, "kind": "function", 
"displayName": "If Then Else", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Evaluates the predicate and returns the value of trueExp or falseExp. This 
function is similar to the ternary operator in Java.", "ognl": false, "suffix": 
"}" },
-    "list(val...)": { "index": 69, "kind": "function", "displayName": "Create 
List of values", "group": "function", "label": "function", "required": false, 
"javaType": "java.util.ArrayList", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
list function creates an ArrayList with the given set of values.", "ognl": 
false, "suffix": "}" },
-    "map(key1,value1,...)": { "index": 70, "kind": "function", "displayName": 
"Create Map of pairs", "group": "function", "label": "function", "required": 
false, "javaType": "java.util.LinkedHashMap", "prefix": "${", "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "The map function creates a LinkedHashMap with the given set of 
pairs.", "ognl": false, "suffix": "}" },
-    "attachments": { "index": 71, "kind": "function", "displayName": 
"Attachments", "group": "function", "label": "function", "required": false, 
"javaType": "java.util.Map", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "All 
the attachments as a Map<String,DataHandler.", "ognl": false, "suffix": "}" },
-    "attachments.size": { "index": 72, "kind": "function", "displayName": 
"Attachments", "group": "function", "label": "function", "required": false, 
"javaType": "int", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The number of attachments. 
Is 0 if there are no attachments.", "ognl": false, "suffix": "}" },
-    "attachmentContentAsText": { "index": 73, "kind": "function", 
"displayName": "Attachment Content As Text", "group": "function", "label": 
"function", "required": false, "javaType": "String", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The content of the attachment as text (ie String).", 
"ognl": false, "suffix": "}" },
-    "attachmentContent": { "index": 74, "kind": "function", "displayName": 
"Attachment Content", "group": "function", "label": "function", "required": 
false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
content of the attachment", "ognl": false, "suffix": "}" },
-    "attachmentContentAs(type)": { "index": 75, "kind": "function", 
"displayName": "Attachment Content As", "group": "function", "label": 
"function", "required": false, "javaType": "Object", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The content of the attachment, converted to the given 
type.", "ognl": false, "suffix": "}" },
-    "attachmentHeader(key,name)": { "index": 76, "kind": "function", 
"displayName": "Attachment Header", "group": "function", "label": "function", 
"required": false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
attachment header with the given name.", "ognl": false, "suffix": "}" },
-    "attachmentHeader(key,name,type)": { "index": 77, "kind": "function", 
"displayName": "Attachment Header", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
attachment header with the given name, converted to the given type.", "ognl": 
false, "suffix": "}" },
-    "attachment(key)": { "index": 78, "kind": "function", "displayName": 
"Attachment", "group": "function", "label": "function", "required": false, 
"javaType": "jakarta.activation.DataHandler", "prefix": "${", "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "The DataHandler for the given attachment.", "ognl": true, 
"suffix": "}" },
-    "base64Encode(exp)": { "index": 79, "kind": "function", "displayName": 
"Base64 Encode", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Base64 encodes the 
message body (or expression)", "ognl": false, "suffix": "}" },
-    "base64Decode(exp)": { "index": 80, "kind": "function", "displayName": 
"Base64 Decode", "group": "function", "label": "function", "required": false, 
"javaType": "byte[]", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Base64 decodes the 
message body (or expression)", "ognl": false, "suffix": "}" }
+    "setHeader(name,type,exp)": { "index": 52, "kind": "function", 
"displayName": "Set Header", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sets a message header with the given expression (optional converting to the 
given type)", "ognl": false, "suffix": "}" },
+    "setVariable(name,type,exp)": { "index": 53, "kind": "function", 
"displayName": "Set Variable", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Sets a variable with the given expression (optional converting to the given 
type)", "ognl": false, "suffix": "}" },
+    "random(min,max)": { "index": 54, "kind": "function", "displayName": 
"Random", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Returns a substring of 
the message body\/expression that are between after and before. Returns null if 
nothing comes between.", "ognl": false, "suffix": "}" },
+    "skip(num)": { "index": 55, "kind": "function", "displayName": "Skip First 
Items from the Message Body", "group": "function", "label": "function", 
"required": false, "javaType": "java.util.Iterator", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The skip function iterates the message body and skips 
the first number of items. This can be used with the Splitter EIP to split a 
message body and skip the first N number of  [...]
+    "convertTo(exp,type)": { "index": 56, "kind": "function", "displayName": 
"Convert To", "group": "function", "label": "function", "required": false, 
"javaType": "", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Converts the message body 
(or expression) to the specified type.", "ognl": true, "suffix": "}" },
+    "isEmpty(exp)": { "index": 57, "kind": "function", "displayName": "Is 
Empty", "group": "function", "label": "function", "required": false, 
"javaType": "boolean", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Whether the message 
body (or expression) is null or empty (list\/map types are tested if they have 
0 elements).", "ognl": false, "suffix": "}" },
+    "trim(exp)": { "index": 58, "kind": "function", "displayName": "Trim", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The trim function trims 
the message body (or expression) by removing all leading and trailing white 
spaces.", "ognl": false, "suffix": "}" },
+    "normalizeWhitespace(exp)": { "index": 59, "kind": "function", 
"displayName": "Normalize Whitspace", "group": "function", "label": "function", 
"required": false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Normalizes the whitespace in the message body (or expression) by cleaning up 
excess whitespaces.", "ognl": false, "suffix": "}" },
+    "length(exp)": { "index": 60, "kind": "function", "displayName": "Length", 
"group": "function", "label": "function", "required": false, "javaType": "int", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The payload length (number of bytes) of the 
message body (or expression).", "ognl": false, "suffix": "}" },
+    "size(exp)": { "index": 61, "kind": "function", "displayName": "Size", 
"group": "function", "label": "function", "required": false, "javaType": "int", 
"prefix": "${", "deprecated": false, "deprecationNote": "", "autowired": false, 
"secret": false, "description": "The size of the message body (or expression). 
If the payload is java.util.Collection or java.util.Map based then the size is 
the number of elements; otherwise the payload size in bytes.", "ognl": false, 
"suffix": "}" },
+    "uppercase(exp)": { "index": 62, "kind": "function", "displayName": 
"Uppercase", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Uppercases the message 
body (or expression)", "ognl": false, "suffix": "}" },
+    "lowercase(exp)": { "index": 63, "kind": "function", "displayName": 
"Lowercase", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Lowercases the message 
body (or expression)", "ognl": false, "suffix": "}" },
+    "concat(exp,exp,separator)": { "index": 64, "kind": "function", 
"displayName": "Concat", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Performs a string concat using two expressions (message body as default) with 
optional separator", "ognl": false, "suffix": "}" },
+    "collate(num)": { "index": 65, "kind": "function", "displayName": "Group 
Message Body into Sub Lists", "group": "function", "label": "function", 
"required": false, "javaType": "java.util.Iterator", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The collate function iterates the message body and 
groups the data into sub lists of specified size. This can be used with the 
Splitter EIP to split a message body and group\/ba [...]
+    "join(separator,prefix,exp)": { "index": 66, "kind": "function", 
"displayName": "Join", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
join function iterates the message body\/expression and joins the data into a 
string. The separator is by default a comma. The prefix is optional. The join 
uses the message body as source by default.  [...]
+    "messageHistory(boolean)": { "index": 67, "kind": "function", 
"displayName": "Print Message History", "group": "function", "label": 
"function", "required": false, "javaType": "String", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The message history of the current exchange (how it has 
been routed). This is similar to the route stack-trace message history the 
error handler logs in case of an unhandled exception. The b [...]
+    "uuid(type)": { "index": 68, "kind": "function", "displayName": "Generate 
UUID", "group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns a UUID using the 
Camel `UuidGenerator`. You can choose between `default`, `classic`, `short` and 
`simple` as the type. If no type is given, the default is used. It is also 
possible to use a custom `UuidG [...]
+    "hash(exp,algorithm)": { "index": 69, "kind": "function", "displayName": 
"Compute Hash Value", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Returns a hashed value (string in hex decimal) of the message body\/expression 
using JDK MessageDigest. The algorithm can be SHA-256 (default) or SHA3-256.", 
"ognl": false, "suffix": "}" },
+    "empty(type)": { "index": 70, "kind": "function", "displayName": "Create 
Empty Object", "group": "function", "label": "function", "required": false, 
"javaType": "Object", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Creates a new empty 
object (decided by type). Use `string` to create an empty String. Use `list` to 
create an empty `java.util.ArrayList`. Use `map` to create an empty 
`java.util.LinkedHashMap`.", "ognl": [...]
+    "iif(predicate,trueExp,falseExp)": { "index": 71, "kind": "function", 
"displayName": "If Then Else", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Evaluates the predicate and returns the value of trueExp or falseExp. This 
function is similar to the ternary operator in Java.", "ognl": false, "suffix": 
"}" },
+    "list(val...)": { "index": 72, "kind": "function", "displayName": "Create 
List of values", "group": "function", "label": "function", "required": false, 
"javaType": "java.util.ArrayList", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
list function creates an ArrayList with the given set of values.", "ognl": 
false, "suffix": "}" },
+    "map(key1,value1,...)": { "index": 73, "kind": "function", "displayName": 
"Create Map of pairs", "group": "function", "label": "function", "required": 
false, "javaType": "java.util.LinkedHashMap", "prefix": "${", "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "The map function creates a LinkedHashMap with the given set of 
pairs.", "ognl": false, "suffix": "}" },
+    "attachments": { "index": 74, "kind": "function", "displayName": 
"Attachments", "group": "function", "label": "function", "required": false, 
"javaType": "java.util.Map", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "All 
the attachments as a Map<String,DataHandler.", "ognl": false, "suffix": "}" },
+    "attachments.size": { "index": 75, "kind": "function", "displayName": 
"Attachments", "group": "function", "label": "function", "required": false, 
"javaType": "int", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The number of attachments. 
Is 0 if there are no attachments.", "ognl": false, "suffix": "}" },
+    "attachmentContentAsText": { "index": 76, "kind": "function", 
"displayName": "Attachment Content As Text", "group": "function", "label": 
"function", "required": false, "javaType": "String", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The content of the attachment as text (ie String).", 
"ognl": false, "suffix": "}" },
+    "attachmentContent": { "index": 77, "kind": "function", "displayName": 
"Attachment Content", "group": "function", "label": "function", "required": 
false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
content of the attachment", "ognl": false, "suffix": "}" },
+    "attachmentContentAs(type)": { "index": 78, "kind": "function", 
"displayName": "Attachment Content As", "group": "function", "label": 
"function", "required": false, "javaType": "Object", "prefix": "${", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "The content of the attachment, converted to the given 
type.", "ognl": false, "suffix": "}" },
+    "attachmentHeader(key,name)": { "index": 79, "kind": "function", 
"displayName": "Attachment Header", "group": "function", "label": "function", 
"required": false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
attachment header with the given name.", "ognl": false, "suffix": "}" },
+    "attachmentHeader(key,name,type)": { "index": 80, "kind": "function", 
"displayName": "Attachment Header", "group": "function", "label": "function", 
"required": false, "javaType": "Object", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
attachment header with the given name, converted to the given type.", "ognl": 
false, "suffix": "}" },
+    "attachment(key)": { "index": 81, "kind": "function", "displayName": 
"Attachment", "group": "function", "label": "function", "required": false, 
"javaType": "jakarta.activation.DataHandler", "prefix": "${", "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "The DataHandler for the given attachment.", "ognl": true, 
"suffix": "}" },
+    "base64Encode(exp)": { "index": 82, "kind": "function", "displayName": 
"Base64 Encode", "group": "function", "label": "function", "required": false, 
"javaType": "String", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Base64 encodes the 
message body (or expression)", "ognl": false, "suffix": "}" },
+    "base64Decode(exp)": { "index": 83, "kind": "function", "displayName": 
"Base64 Decode", "group": "function", "label": "function", "required": false, 
"javaType": "byte[]", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "Base64 decodes the 
message body (or expression)", "ognl": false, "suffix": "}" }
   }
 }
diff --git 
a/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
 
b/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
index 80afa17b55e8..10c2374a50d6 100644
--- 
a/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
+++ 
b/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc
@@ -59,8 +59,125 @@ include::partial$language-options.adoc[]
 == Variables
 
 [width="100%",cols="10%,10%,80%",options="header",]
-|=======================================================================
-|Variable |Type |Description
+|====
+|Function |Response Type |Description
+|`bean(name.method)` | `Object` | Invoking a bean expression using the 
xref:components::bean-component.adoc[Bean] language. Specifying a method name, 
you must use dot as the separator. We also support the ?method=methodname 
syntax that is used by the xref:components::bean-component.adoc[Bean] 
component. Camel will by default lookup a bean by the given name. However, if 
you need to refer to a bean class (such as calling a static method), then you 
can prefix with the type, such as `bean:ty [...]
+|`body._OGNL_` | `Object` | The body invoked using a Camel _OGNL syntax_. For 
example to invoke the `getCountryCode` on the message body, you can use 
`${body.getCountryCode()}`. In the message body is a POJO then you can use a 
short-hand syntax `${body.countryCode}`.
+|`bodyAs(type)._OGNL_` | `Object` | Converts the body to the given type 
determined by its classname and then invoke methods using a Camel _OGNL syntax_.
+|`bodyAs(type)` | `<T>` | Converts the body to the given type determined by 
its classname.
+|`bodyOneLine` | `String` | Converts the body to a String and removes all 
line-breaks, so the string is in one line.
+|`bodyType` | `Class` | The message body class.
+|`body` | `Object` | The message body
+|`camelContext._OGNL_` | `Object` | The CamelContext invoked using Camel _OGNL 
syntax_.
+|`camelId` | `String` | The name of the Camel application (ie `CamelContext`).
+|`capitalize()` | `String` | Capitalizes the message body as a String value 
(upper case every words)
+|`capitalize(exp)` | `String` | Capitalizes the expression as a String value 
(upper case every words)
+|`collate(size)` | `List` | The collate function iterates the message body and 
groups the data into sub lists of specified size. This can be used with the 
Splitter EIP to split a message body and group/batch the split sub message into 
a group of N sub lists. This method works similar to the collate method in 
Groovy.
+|`concat(exp,exp,separator` | `String` | Performs a string concat using two 
expressions (message body as default) with optional separator (uses comma by 
default).
+|`convertTo(exp,type)._OGNL_` | `Object` | Converts the expression to the 
specified type and then invoke methods using a Camel _OGNL syntax_.
+|`convertTo(exp,type)` | `<T>` | Converts the expression to the specified type.
+|`convertTo(type)` | `<T>` | Converts the message body to the specified type.
+|`date-with-timezone:command:timezone:pattern` | `String` | Date formatting 
using `java.text.SimpleDateFormat` timezones and patterns. See `data:command` 
function for additional documentation on the commands.
+|`date:command:pattern` | `String` | Date formatting using 
`java.text.SimpleDateFormat` patterns. See `data:command` function for 
additional documentation on the commands.
+|`date:command` | `Date` | Evaluates to a `java.util.Date` object. Supported 
commands are: `now` for current timestamp, `exchangeCreated` for the timestamp 
when the current exchange was created, `header.xxx` to use the `Long/Date` 
object in the header with the key xxx. `variable.xxx` to use the `Long/Date` in 
the variable with the key xxx. `exchangeProperty.xxx` to use the `Long/Date` 
object in the exchange property with the key xxx. `file` for the last modified 
timestamp of the file (on [...]
+|`empty(kind)` | `<T>` | Creates a new empty object of the given kind. The 
`string` kind creates an empty `String` object. The `list` creates an empty 
`ArrayList`, and `map` creates an empty `LinkedHashMap` object.
+|`env.key` | `String` | Refers to the OS system environment variable with the 
given key. For example `env.HOME` to refer to the home directory.
+|`exception._OGNL_` | `Object` | Same as `exception` and then invoke Camel 
_OGNL syntax_.
+|`exception.message` | `String` | The message from the `Exchange` object. See 
`exception` for more details.
+|`exception.stacktrace` | `String` | The stacktrace from the `Exchange` 
object. See `exception` for more details.
+|`exception` | `Throwable` | The `Exception` object on the exchange, is `null` 
if no exception is set on the `Exchange`. Will fallback and grab any caught 
exceptions stored as exchange property (`Exchange.EXCEPTION_CAUGHT`)
+|`exchange._OGNL_` | `Object` | The current `Exchange` invoked using Camel 
_OGNL syntax_.
+|`exchangeId` | `String` | The id of the current `Exchange`.
+|`exchangeProperty.key._OGNL_` | `Object` | Same as `exchangeProperty.key` and 
then invoke Camel _OGNL syntax_.
+|`exchangeProperty.key` | `Object` | Returns the value of the exchange 
property with the given key. Returns `null` if the property does not exists.
+|`exchange` | `Exchange` | The current `Exchange` object.
+|`fromRouteId` | `String` | Returns the original route id where this 
`Exchange` was created.
+|`hash(exp,algorithm)` | `String` | Returns a hashed value (string in hex 
decimal) of the given expression. The algorithm can be `SHA-256` (default) or 
`SHA3-256`.
+|`header.key._OGNL_` | `Object` | Same as `header.key` and then invoke Camel 
_OGNL syntax_.
+|`header.key` | `Object` | The message header with the given key.
+|`headerAs(key,type)` | `<T>` | The message header with the given key, 
converted to the given type.
+|`header[key]._OGNL_` | `Object` | *Deprecated* Same as `header[key]` and then 
invoke Camel _OGNL syntax_.
+|`header[key]` | `Object` | *Deprecated* The message header with the given key.
+|`headers.key` | `Object` | *Deprecated* The message header with the given key.
+|`headers.size` | `int` | The number of headers
+|`headers:key` | `Object` | *Deprecated* The message header with the given key.
+|`headers[key]` | `Object` | *Deprecated* The message header with the given 
key.
+|`headers` | `Map` | All the message headers as a `java.util.Map`.
+|`hostname` | `String` | Returns the local hostname (may be `null` if not 
possible to resolve).
+|`id` | `String` | The message id
+|`iif(predicate,trueExp,falseExp`) | `Object` | Evaluates the predicate 
expression and returns the value of _trueExp_ if the predicate is `true`, 
otherwise the value of `falseExp` is returned. This function is similar to the 
ternary operator in Java.
+|`isEmpty(exp)` | `boolean` | Whether the expression is `null` or empty 
(list/map types are tested if they have 0 elements).
+|`isEmpty()` | `boolean` | Whether the message body is `null` or empty 
(list/map types are tested if they have 0 elements).
+|`join(separator,prefix,exp` | `String` | The join function iterates the 
message body (by default) and joins the data into a `String`. The separator is 
by default a comma. The prefix is optional. The join uses the message body as 
source by default. It is possible to refer to another source (simple language) 
such as a header via the exp parameter. For example 
`join('&','id=','$\{header.ids}')`
+|`jq(exp)` | `Object` | When working with JSon data, then this allows using 
the JQ language, for example, to extract data from the message body (in JSon 
format). This requires having camel-jq JAR on the classpath.
+|`jq(input,exp)` | `Object` | Same as `jp(exp)` but to use the _input_ 
expression as the source of the JSon document.
+|`jsonpath(exp)` | `Object` | "When working with JSon data, then this allows 
using the JsonPath language, for example, to extract data from the message body 
(in JSon format). This requires having camel-jsonpath JAR on the classpath.
+|`jsonpath(input,exp)` | `Object` | Same as `jsonpath(exp)` but to use the 
_input_ expression as the source of the JSon document.
+|`length()` | `int` | The payload length (number of bytes) of the message body
+|`length(exp)` | `int` | The payload length (number of bytes) of the 
expression.
+|`list(val1,val2,...)` | `List` | The list function creates an 
`java.util.ArrayList` with the given set of values.
+|`logExchange` | `String` | Dumps the exchange for logging purpose (uses 
`ExchangeFormatter` to format the output).
+|`lowercase()` | `String` | Lowercases the message body
+|`lowercase(exp)` | `String` | Lowercases the expression
+|`mandatoryBodyAs(type)._OGNL_` | `Object` | Same as `mandatoryBodyAs(type)` 
and then invoke Camel _OGNL syntax_.
+|`mandatoryBodyAs(type)` | `<T>` | Converts the message body to the given type 
determined by its classname. If the body is `null` then an exception is thrown.
+|`map(key1,value1,...)` | `Map` | The map function creates a 
`java.util.LinkedHashMap` with the given set of pairs.
+|`messageAs(type)._OGNL_` | `Object` | Same as `messageAs(type)` and then 
invoke Camel _OGNL syntax_.
+|`messageAs(type)` | `<T>` | Converts the message to the given type determined 
by its classname.
+|`messageHistory` | `String` | The message history of the current exchange 
(how it has been routed). This is similar to the route stack-trace message 
history the error handler logs in case of an unhandled exception.
+|`messageHistory(false)` | `String` | Same as `messageHistory` but without the 
exchange details (only includes the route stack-trace). This can be used if you 
do not want to log sensitive data from the message itself.
+|`messageTimestamp` | `long` | The message timestamp (millis since epoc) that 
this message originates from. Some systems like JMS, Kafka, AWS have a 
timestamp on the event/message that Camel received. This method returns the 
timestamp if a timestamp exists. The message timestamp and exchange created are 
different. An exchange always has a created timestamp which is the local 
timestamp when Camel created the exchange. The message timestamp is only 
available in some Camel components when t [...]
+|`normalizeWhitespace()` | `String` | Normalizes the whitespace in the message 
body by cleaning up excess whitespaces.
+|`normalizeWhitespace(exp)` | `String` | Normalizes the whitespace in the 
expression by cleaning up excess whitespaces.
+|`null` | `null` | Returns a `null` value.
+|`originalBody` | `Object` | The original incoming message body (only 
available if Camel has been configured with `allowUseOriginalMessage=true`).
+|`pretty(exp)` | `String` | Converts the expression to a `String`, and 
attempts to pretty print (if JSon or XML) otherwise return the value as-is.
+|`prettyBody` | `String` | Converts the message body to a `String`, and 
attempts to pretty print (if JSon or XML) otherwise return the value as-is.
+|`properties:key:default` | `String` | Lookup a property placeholder with the 
given key. If the key does not exist nor has a value, then an optional default 
value can be specified.
+|`propertiesExist:key` | `boolean` | Checks whether a property placeholder 
with the given key exists or not. The result can be negated by prefixing the 
key with `!`.
+|`random(max)` | `int` | Returns a random `Integer` between 0 (included) and 
max (excluded).
+|`random(min,max)` | `int` | Returns a random `Integer` between min (included) 
and max (excluded),
+|`ref:key` | `Object` | To look up a bean from the Camel 
xref:manual::registry.adoc[Registry] with the given key.
+|`replace(from,to)` | `String` | Replace all the string values in the message 
body. To make it easier to replace single and double quotes, then you can use 
XML escaped values `\&quot;` as double quote, `\&apos;` as single quote, and 
`\&empty;` as empty value.
+|`replace(from,to,ex[])` | `String` | Replace all the string values in the 
given expression. To make it easier to replace single and double quotes, then 
you can use XML escaped values `\&quot;` as double quote, `\&apos;` as single 
quote, and `\&empty;` as empty value.
+|`routeGroup` | `String` | Returns the route group of the current route the 
`Exchange` is being routed. Not all routes have a group assigned, so this may 
be `null`.
+|`routeId` | `String` | Returns the route id of the current route the 
`Exchange` is being routed.
+|`setHeader(name,type,exp)` | `null` | Sets a message header with the given 
expression (optional converting to the given type).
+|`setVariable(name,type,exp)` | `null` | Sets a variable with the given 
expression (optional converting to the given type).
+|`size()` | `int` | The size of the message body. If the payload is 
`java.util.Collection` or `java.util.Map` based then the size is the number of 
elements; otherwise the payload size in bytes.
+|`size(exp)` | `int` | The size of the expression. If the payload is 
`java.util.Collection` or `java.util.Map` based then the size is the number of 
elements; otherwise the payload size in bytes.
+|`skip(number)` | `Iterator` | The skip function iterates the message body and 
skips the first number of items. This can be used with the Splitter EIP to 
split a message body and skip the first N number of items.
+|`split(exp,separator)` | `String[]` | Splits the expression as a `String` 
value using the separator into a `String` array. The separator is comma by 
default.
+|`split(separator)` | `String[]` | Splits the message body as a `String` value 
using the separator into a `String` array. The separator is comma by default.
+|`stepId` | `String` | Returns the id of the current step the `Exchange` is 
being routed. Returns `null` if there are no steps.
+|`substring(num1)` | `String` | Returns a substring of the message body. If 
the number is positive, then the returned string is clipped from the beginning. 
If the number is negative, then the returned string is clipped from the ending.
+|`substring(num1,num2)` | `String` | Returns a substring of the message body. 
If the number is positive, then the returned string is clipped from the 
beginning. If the number is negative, then the returned string is clipped from 
the ending.
+|`substring(num1,num2,exp)` | `String` | Returns a substring of the given 
expression. If the number is positive, then the returned string is clipped from 
the beginning. If the number is negative, then the returned string is clipped 
from the ending.
+|`substringAfter(after)` | `String` | Returns a substring of the message body 
that comes after. Returns `null` if nothing comes after.
+|`substringAfter(exp,after)` | `String` | Returns a substring of the 
expression that comes after. Returns `null` if nothing comes after.
+|`substringBefore(before)` | `String` | Returns a substring of the message 
body that comes before. Returns `null` if nothing comes before.
+|`substringBefore(exp,before)` | `String` | Returns a substring of the 
expression that comes before. Returns `null` if nothing comes before.
+|`substringBetween(after,before)` | `String` | Returns a substring of the 
message body that are between before and after. Returns `null` if nothing comes 
between.
+|`substringBetween(exp,after,before)` | `String` | Returns a substring of the 
expression that are between before and after. Returns `null` if nothing comes 
between.
+|`sys.key` | `String` | *Deprecated* To lookup the JVM system property with 
the given key.
+|`sysenv.key` | `String` | To lookup the JVM system property with the given 
key.
+|`threadId` | `String` | Returns the id of the current thread.
+|`threadName` | `String` | Returns the name of the current thread.
+|`trim()` | `String` | The trim function trims the message body by removing 
all leading and trailing white spaces.
+|`trim(exp)` | `String` | The trim function trims the expression by removing 
all leading and trailing white spaces.
+|`type:name.field` | `Object` | To refer to a type or field by its fully 
qualified classname. For example: `type:org.apache.camel.Exchange.FILE_NAME`.
+|`uppercase()` | `String` | Uppercases the message body
+|`uppercase(exp)` | `String` | Uppercases the expression
+|`uuid(kind)` | `String` | Returns a UUID using the Camel `UuidGenerator`. You 
can choose kind between `default`, `classic`, `short`, `simple` and `random` as 
the kind. If no kind is given, then `default` is used. It is also possible to 
use a custom `UuidGenerator` and bind the bean to the 
xref:manual::registry.adoc[Registry] with an id. For example 
`${uuid(myGenerator)}` where the id is `myGenerator`.
+|`variable.key._OGNL_` | `Object` | To look up the variable with the given key 
and then invoke Camel _OGNL syntax_.
+|`variable.key` | `Object` | To look up the variable with the given key.
+|`variableAs(key,type)` | `<T>` | To look up the variable with the given key, 
and convert the value to the given type determined by its classname
+|`variable[key]` | `Object` | *Deprecated* To look up the variable with the 
given key.
+|`variables.size` | `int` | The number of `Exchange` variables
+|`variables` | `Map` | All the variables from the current `Exchange` as a 
`java.util.Map`.
+|`xpath(exp)` | `Object` | When working with XML data, then this allows using 
the XPath language, for example, to extract data from the message body (in XML 
format). This requires having camel-xpath JAR on the classpath.
+|`xpath(input,exp)` | `Object` | When working with XML data, then this allows 
using the XPath language, for example, to extract data from the message body 
(in XML format). This requires having camel-xpath JAR on the classpath. For 
input you can choose `header:key`, `exchangeProperty:key` or `variable:key` to 
use as input for the JSon payload instead of the message body.
+|====
 
 |camelId |String |the CamelContext name
 
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleHelper.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleHelper.java
index 5c1e240c2a75..850d72d40480 100644
--- 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleHelper.java
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/csimple/CSimpleHelper.java
@@ -958,4 +958,28 @@ public final class CSimpleHelper {
         }
     }
 
+    public static Object setHeader(Exchange exchange, String name, Class<?> 
type, Object value) {
+        if (type != null && value != null) {
+            value = convertTo(exchange, type, value);
+        }
+        if (value != null) {
+            exchange.getMessage().setHeader(name, value);
+        } else {
+            exchange.getMessage().removeHeader(name);
+        }
+        return null;
+    }
+
+    public static Object setVariable(Exchange exchange, String name, Class<?> 
type, Object value) {
+        if (type != null && value != null) {
+            value = convertTo(exchange, type, value);
+        }
+        if (value != null) {
+            exchange.setVariable(name, value);
+        } else {
+            exchange.removeVariable(name);
+        }
+        return null;
+    }
+
 }
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleConstants.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleConstants.java
index 325deb308034..569ac086a221 100644
--- 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleConstants.java
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleConstants.java
@@ -192,6 +192,12 @@ public final class SimpleConstants {
               label = "function",
               javaType = "String", displayName = "Capitalize String Values")
     public static final String CAPITALIZE = "capitalize(exp)";
+    @Metadata(description = "Sets a message header with the given expression 
(optional converting to the given type)",
+              label = "function", javaType = "Object")
+    public static final String SET_HEADER = "setHeader(name,type,exp)";
+    @Metadata(description = "Sets a variable with the given expression 
(optional converting to the given type)",
+              label = "function", javaType = "Object")
+    public static final String SET_VARIABLE = "setVariable(name,type,exp)";
     @Metadata(description = "Returns a substring of the message 
body/expression that are between after and before. Returns null if nothing 
comes between.",
               label = "function", javaType = "String")
     public static final String RANDOM = "random(min,max)";
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
index 362e499a58d8..616d3ef42ee8 100644
--- 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java
@@ -824,6 +824,90 @@ public final class SimpleExpressionBuilder {
         };
     }
 
+    /**
+     * Sets the message header with the given expression value
+     */
+    public static Expression setHeaderExpression(final String name, final 
String type, final String expression) {
+        return new ExpressionAdapter() {
+            private ClassResolver classResolver;
+            private Expression exp;
+
+            @Override
+            public void init(CamelContext context) {
+                classResolver = context.getClassResolver();
+                exp = 
context.resolveLanguage("simple").createExpression(expression);
+                exp.init(context);
+            }
+
+            @Override
+            public Object evaluate(Exchange exchange) {
+                Class<?> clazz = Object.class;
+                if (type != null) {
+                    try {
+                        clazz = classResolver.resolveMandatoryClass(type);
+                    } catch (ClassNotFoundException e) {
+                        throw 
CamelExecutionException.wrapCamelExecutionException(exchange, e);
+                    }
+                }
+                Object value = exp.evaluate(exchange, clazz);
+                if (value != null) {
+                    exchange.getMessage().setHeader(name, value);
+                } else {
+                    exchange.getMessage().removeHeader(name);
+                }
+                // does not return anything
+                return null;
+            }
+
+            @Override
+            public String toString() {
+                return "setHeader(" + name + "," + expression + ")";
+            }
+        };
+    }
+
+    /**
+     * Sets the variable with the given expression value
+     */
+    public static Expression setVariableExpression(final String name, final 
String type, final String expression) {
+        return new ExpressionAdapter() {
+            private ClassResolver classResolver;
+            private Expression exp;
+
+            @Override
+            public void init(CamelContext context) {
+                classResolver = context.getClassResolver();
+                exp = 
context.resolveLanguage("simple").createExpression(expression);
+                exp.init(context);
+            }
+
+            @Override
+            public Object evaluate(Exchange exchange) {
+                Class<?> clazz = Object.class;
+                if (type != null) {
+                    try {
+                        clazz = classResolver.resolveMandatoryClass(type);
+                    } catch (ClassNotFoundException e) {
+                        throw 
CamelExecutionException.wrapCamelExecutionException(exchange, e);
+                    }
+                }
+                Object value = exp.evaluate(exchange, clazz);
+                if (value != null) {
+                    exchange.setVariable(name, value);
+                } else {
+                    exchange.removeVariable(name);
+                }
+                // does not return anything
+                return null;
+            }
+
+            @Override
+            public String toString() {
+                return "setVariable(" + name + "," + expression + ")";
+            }
+        };
+    }
+
     /**
      * Replaces string values from the expression
      */
diff --git 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
index 76fc383aaf0f..c197cadf638c 100644
--- 
a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
+++ 
b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java
@@ -748,6 +748,61 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
     private Expression createSimpleExpressionMisc(String function) {
         String remainder;
 
+        // setHeader function
+        remainder = ifStartsWithReturnRemainder("setHeader(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${setHeader(name,exp)} or 
${setHeader(name,type,exp)} was: " + function,
+                        token.getIndex());
+            }
+            String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',', 
false);
+            if (tokens.length < 2 || tokens.length > 3) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${setHeader(name,exp)} or 
${setHeader(name,type,exp)} was: " + function,
+                        token.getIndex());
+            }
+            String name = tokens[0];
+            String exp;
+            String type = null;
+            if (tokens.length == 3) {
+                type = tokens[1];
+                exp = tokens[2];
+            } else {
+                exp = tokens[1];
+            }
+            type = StringHelper.removeQuotes(type);
+            return SimpleExpressionBuilder.setHeaderExpression(name, type, 
exp);
+        }
+        // setVariable function
+        remainder = ifStartsWithReturnRemainder("setVariable(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${setVariable(name,exp)} or 
${setVariable(name,type,exp)} was: " + function,
+                        token.getIndex());
+            }
+            String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',', 
false);
+            if (tokens.length < 2 || tokens.length > 3) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${setVariable(name,exp)} or 
${setVariable(name,type,exp)} was: " + function,
+                        token.getIndex());
+            }
+            String name = tokens[0];
+            String exp;
+            String type = null;
+            if (tokens.length == 3) {
+                type = tokens[1];
+                exp = tokens[2];
+            } else {
+                exp = tokens[1];
+            }
+            type = StringHelper.removeQuotes(type);
+            return SimpleExpressionBuilder.setVariableExpression(name, type, 
exp);
+        }
+
         // replace function
         remainder = ifStartsWithReturnRemainder("replace(", function);
         if (remainder != null) {
@@ -2086,6 +2141,97 @@ public class SimpleFunctionExpression extends 
LiteralExpression {
     private String createCodeExpressionMisc(String function) {
         String remainder;
 
+        // setHeader function
+        remainder = ifStartsWithReturnRemainder("setHeader(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${setHeader(name,exp)} or 
${setHeader(name,type,exp)} was: " + function,
+                        token.getIndex());
+            }
+            String[] tokens = codeSplitSafe(values, ',', true, true);
+            if (tokens.length < 2 || tokens.length > 3) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${setHeader(name,exp)} or 
${setHeader(name,type,exp)} was: " + function,
+                        token.getIndex());
+            }
+            // single quotes should be double quotes
+            for (int i = 1; i < tokens.length; i++) {
+                String s = tokens[i];
+                if (StringHelper.isSingleQuoted(s)) {
+                    s = StringHelper.removeLeadingAndEndingQuotes(s);
+                    s = StringQuoteHelper.doubleQuote(s);
+                    tokens[i] = s;
+                }
+            }
+            // name must be in double quote as its a string value
+            String name = StringHelper.removeLeadingAndEndingQuotes(tokens[0]);
+            name = StringQuoteHelper.doubleQuote(name);
+            String exp;
+            String type = null;
+            if (tokens.length == 3) {
+                type = tokens[1];
+                exp = tokens[2];
+            } else {
+                exp = tokens[1];
+            }
+            if (type != null) {
+                type = StringHelper.removeQuotes(type);
+                type = type.trim();
+                type = appendClass(type);
+                type = type.replace('$', '.');
+            } else {
+                type = "null";
+            }
+            return "Object value = " + exp + ";\n        return 
setHeader(exchange, " + name + ", " + type + ", value);";
+        }
+        // setVariable function
+        remainder = ifStartsWithReturnRemainder("setVariable(", function);
+        if (remainder != null) {
+            String values = StringHelper.beforeLast(remainder, ")");
+            if (values == null || ObjectHelper.isEmpty(values)) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${setVariable(name,exp)} or 
${setVariable(name,type,exp)} was: " + function,
+                        token.getIndex());
+            }
+            String[] tokens = codeSplitSafe(values, ',', true, true);
+            if (tokens.length < 2 || tokens.length > 3) {
+                throw new SimpleParserException(
+                        "Valid syntax: ${setVariable(name,exp)} or 
${setVariable(name,type,exp)} was: " + function,
+                        token.getIndex());
+            }
+            // single quotes should be double quotes
+            for (int i = 1; i < tokens.length; i++) {
+                String s = tokens[i];
+                if (StringHelper.isSingleQuoted(s)) {
+                    s = StringHelper.removeLeadingAndEndingQuotes(s);
+                    s = StringQuoteHelper.doubleQuote(s);
+                    tokens[i] = s;
+                }
+            }
+            // name must be in double quote as its a string value
+            String name = StringHelper.removeLeadingAndEndingQuotes(tokens[0]);
+            name = StringQuoteHelper.doubleQuote(name);
+            String exp;
+            String type = null;
+            if (tokens.length == 3) {
+                type = tokens[1];
+                exp = tokens[2];
+            } else {
+                exp = tokens[1];
+            }
+            if (type != null) {
+                type = StringHelper.removeQuotes(type);
+                type = type.trim();
+                type = appendClass(type);
+                type = type.replace('$', '.');
+            } else {
+                type = "null";
+            }
+            return "Object value = " + exp + ";\n        return 
setVariable(exchange, " + name + ", " + type + ", value);";
+        }
+
         // substring function
         remainder = ifStartsWithReturnRemainder("substring(", function);
         if (remainder != null) {
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
index cf87eba403be..a43191c1c61d 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java
@@ -2861,6 +2861,79 @@ public class SimpleTest extends LanguageTestSupport {
         assertExpression(exchange, "${pretty(${body})}", "{\n\t\"name\": 
\"Jack\",\n\t\"id\": 123\n}\n");
     }
 
+    @Test
+    public void testSetHeader() {
+        exchange.getMessage().setBody("Hello World");
+
+        Expression expression = 
context.resolveLanguage("simple").createExpression("${setHeader(foo,${body})}");
+        Object s = expression.evaluate(exchange, String.class);
+        assertNull(s);
+        assertEquals("Hello World", exchange.getMessage().getHeader("foo"));
+
+        exchange.getMessage().setBody("123");
+        expression = 
context.resolveLanguage("simple").createExpression("${setHeader(bar,int,${body})}");
+        s = expression.evaluate(exchange, String.class);
+        assertNull(s);
+        assertIsInstanceOf(Integer.class, 
exchange.getMessage().getHeader("bar"));
+        assertEquals(123, exchange.getMessage().getHeader("bar"));
+
+        // null should remove the variable
+        expression = 
context.resolveLanguage("simple").createExpression("${setHeader(bar,${null})}");
+        s = expression.evaluate(exchange, String.class);
+        assertNull(s);
+        assertNull(exchange.getMessage().getHeader("bar"));
+    }
+
+    @Test
+    public void testSetVariable() {
+        exchange.getVariables().clear();
+        assertEquals(0, exchange.getVariables().size());
+        exchange.getMessage().setBody("Hello World");
+
+        Expression expression = 
context.resolveLanguage("simple").createExpression("${setVariable(foo,${body})}");
+        Object s = expression.evaluate(exchange, String.class);
+        assertNull(s);
+        assertEquals("Hello World", exchange.getVariable("foo"));
+        assertEquals(1, exchange.getVariables().size());
+
+        exchange.getMessage().setBody("123");
+        expression = 
context.resolveLanguage("simple").createExpression("${setVariable(bar,int,${body})}");
+        s = expression.evaluate(exchange, String.class);
+        assertNull(s);
+        assertIsInstanceOf(Integer.class, exchange.getVariable("bar"));
+        assertEquals(123, exchange.getVariable("bar"));
+        assertEquals(2, exchange.getVariables().size());
+
+        // null should remove the variable
+        expression = 
context.resolveLanguage("simple").createExpression("${setVariable(bar,${null})}");
+        s = expression.evaluate(exchange, String.class);
+        assertNull(s);
+        assertNull(exchange.getVariable("bar"));
+        assertEquals(1, exchange.getVariables().size());
+    }
+
+    @Test
+    public void testSetVariableMapping() {
+        exchange.getVariables().clear();
+        assertEquals(0, exchange.getVariables().size());
+        exchange.getMessage().setBody("Hello World");
+
+        String map = """
+                ${setVariable(count,${body.length})}
+                Input: ${body}
+                Bytes: ${variable.count}
+                """;
+        String exp = """
+
+                Input: Hello World
+                Bytes: 11
+                """;
+
+        Expression expression = 
context.resolveLanguage("simple").createExpression(map);
+        String out = expression.evaluate(exchange, String.class);
+        assertEquals(exp, out);
+    }
+
     private void assertExpressionCreateNewEmpty(
             String type, Class<?> expectedClass, 
java.util.function.Predicate<Object> isEmptyAssertion) {
         Object value = evaluateExpression("${empty(%s)}".formatted(type), 
null);

Reply via email to