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

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


The following commit(s) were added to refs/heads/main by this push:
     new a528e9362ff9 Improved simple language doc such as sorting all 
functions and adding some more examples
a528e9362ff9 is described below

commit a528e9362ff9b286fe157d7c2f41d36fcf5f0cd5
Author: Claus Ibsen <[email protected]>
AuthorDate: Sat Jan 17 23:09:47 2026 +0100

    Improved simple language doc such as sorting all functions and adding some 
more examples
---
 .../org/apache/camel/catalog/languages/simple.json |   4 +-
 .../org/apache/camel/language/simple/simple.json   |   4 +-
 .../modules/languages/pages/simple-language.adoc   | 845 +++++++++------------
 .../camel/language/simple/SimpleConstants.java     |   4 +-
 4 files changed, 364 insertions(+), 493 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 c26c67656c9f..a6ab10fed80d 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
@@ -34,7 +34,7 @@
     "exchange": { "index": 8, "kind": "function", "displayName": "Exchange", 
"group": "function", "label": "function", "required": false, "javaType": 
"org.apache.camel.Exchange", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
current exchange", "ognl": true, "suffix": "}" },
     "exception": { "index": 9, "kind": "function", "displayName": "Exception", 
"group": "function", "label": "function", "required": false, "javaType": 
"java.lang.Exception", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The exception object 
on the exchange (also from caught exceptions), is null if no exception 
present.", "ognl": true, "suffix": "}" },
     "exception.message": { "index": 10, "kind": "function", "displayName": 
"Exception Message", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
exception message (also from caught exceptions), is null if no exception 
present.", "ognl": false, "suffix": "}" },
-    "exception.stackTrace": { "index": 11, "kind": "function", "displayName": 
"Exception Stacktrace", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
exception stacktrace (also from caught exceptions), is null if no exception 
present.", "ognl": false, "suffix": "}" },
+    "exception.stacktrace": { "index": 11, "kind": "function", "displayName": 
"Exception Stacktrace", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
exception stacktrace (also from caught exceptions), is null if no exception 
present.", "ognl": false, "suffix": "}" },
     "threadId": { "index": 12, "kind": "function", "displayName": "Thread Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the id of the 
current thread. Can be used for logging.", "ognl": false, "suffix": "}" },
     "threadName": { "index": 13, "kind": "function", "displayName": "Thread 
Name", "group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the name of the 
current thread. Can be used for logging.", "ognl": false, "suffix": "}" },
     "hostName": { "index": 14, "kind": "function", "displayName": "Host Name", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the local hostname 
(may be empty if not possible to resolve).", "ognl": false, "suffix": "}" },
@@ -78,7 +78,7 @@
     "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": "}" },
-    "isEmpty(exp)": { "index": 55, "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": "}" },
+    "isEmpty(exp)": { "index": 55, "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": 56, "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": 57, "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": 58, "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": "}" },
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 c26c67656c9f..a6ab10fed80d 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
@@ -34,7 +34,7 @@
     "exchange": { "index": 8, "kind": "function", "displayName": "Exchange", 
"group": "function", "label": "function", "required": false, "javaType": 
"org.apache.camel.Exchange", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
current exchange", "ognl": true, "suffix": "}" },
     "exception": { "index": 9, "kind": "function", "displayName": "Exception", 
"group": "function", "label": "function", "required": false, "javaType": 
"java.lang.Exception", "prefix": "${", "deprecated": false, "deprecationNote": 
"", "autowired": false, "secret": false, "description": "The exception object 
on the exchange (also from caught exceptions), is null if no exception 
present.", "ognl": true, "suffix": "}" },
     "exception.message": { "index": 10, "kind": "function", "displayName": 
"Exception Message", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
exception message (also from caught exceptions), is null if no exception 
present.", "ognl": false, "suffix": "}" },
-    "exception.stackTrace": { "index": 11, "kind": "function", "displayName": 
"Exception Stacktrace", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
exception stacktrace (also from caught exceptions), is null if no exception 
present.", "ognl": false, "suffix": "}" },
+    "exception.stacktrace": { "index": 11, "kind": "function", "displayName": 
"Exception Stacktrace", "group": "function", "label": "function", "required": 
false, "javaType": "String", "prefix": "${", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": "The 
exception stacktrace (also from caught exceptions), is null if no exception 
present.", "ognl": false, "suffix": "}" },
     "threadId": { "index": 12, "kind": "function", "displayName": "Thread Id", 
"group": "function", "label": "function", "required": false, "javaType": 
"long", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the id of the 
current thread. Can be used for logging.", "ognl": false, "suffix": "}" },
     "threadName": { "index": 13, "kind": "function", "displayName": "Thread 
Name", "group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the name of the 
current thread. Can be used for logging.", "ognl": false, "suffix": "}" },
     "hostName": { "index": 14, "kind": "function", "displayName": "Host Name", 
"group": "function", "label": "function", "required": false, "javaType": 
"String", "prefix": "${", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Returns the local hostname 
(may be empty if not possible to resolve).", "ognl": false, "suffix": "}" },
@@ -78,7 +78,7 @@
     "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": "}" },
-    "isEmpty(exp)": { "index": 55, "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": "}" },
+    "isEmpty(exp)": { "index": 55, "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": 56, "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": 57, "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": 58, "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": "}" },
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 1be00ca5da83..fd6b69599c7c 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
@@ -14,18 +14,14 @@
 
 The Simple Expression Language was a really simple language when it was
 created, but has since grown more powerful. It is primarily intended for
-being a very small and simple language for evaluating
-`Expression` or `Predicate` without requiring any new dependencies
-or knowledge of other scripting languages such as Groovy.
+being a very small and Camel specific scripting language used anywhere in Camel
+such as with xref:components:eips:enterprise-integration-patterns.adoc[EIPs] 
and
+xref:manual::routes.adoc[Route].
 
 The simple language is designed with intent to cover almost all the common use 
cases
 when little need for scripting in your Camel routes.
 
-However, for much more complex use cases, then a more powerful language is 
recommended such as:
-
-* xref:groovy-language.adoc[Groovy]
-* xref:mvel-language.adoc[MVEL]
-* xref:ognl-language.adoc[OGNL]
+However, for much more complex use cases, then a more powerful language is 
recommended such as: xref:groovy-language.adoc[Groovy].
 
 [NOTE]
 ====
@@ -34,12 +30,7 @@ language uses OGNL expressions, such as calling a method 
named `myMethod` on the
 At runtime the simple language will then us its built-in OGNL support which 
requires the `camel-bean` component.
 ====
 
-The simple language uses `$\{body}` placeholders for complex expressions or 
functions.
-
-[NOTE]
-====
-See also the xref:csimple-language.adoc[CSimple] language which is *compiled*.
-====
+The simple language uses `$\{body}` placeholders for dynamic expressions and 
functions.
 
 [TIP]
 ====
@@ -50,311 +41,141 @@ uses `$simple{ }` as placeholders. This can be used in 
situations to avoid clash
 Spring property placeholder together with Camel.
 ====
 
+[NOTE]
+====
+See also the xref:csimple-language.adoc[CSimple] language which is *pre 
compiled*.
+====
+
 == Simple Language options
 
 // language options: START
 include::partial$language-options.adoc[]
 // language options: END
 
-== Variables
-
-[width="100%",cols="10%,10%,80%",options="header",]
-|=======================================================================
-|Variable |Type |Description
-
-|camelId |String |the CamelContext name
-
-|camelContext.*OGNL* |Object |the CamelContext invoked using a Camel OGNL 
expression.
-
-|exchange |Exchange |the Exchange
-
-|exchange.*OGNL* |Object |the Exchange invoked using a Camel
-OGNL expression.
-
-|exchangeId |String |the exchange id
-
-|id |String |the message id
-
-|logExchange |String | Dumps the exchange for logging purpose (uses 
`ExchangeFormatter` to format the output).
-
-|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 the consumer is able to extract the timestamp from the source event.
-If the message has no timestamp, then 0 is returned.
-
-|body |Object |the body
-
-|body.*OGNL* |Object |the body invoked using a Camel OGNL expression.
-
-|bodyAs(_type_) |Type |Converts the body to the given type determined by its
-classname. The converted body can be null.
-
-|bodyAs(_type_).*OGNL* |Object |Converts the body to the given type determined 
by its
-classname and then invoke methods using a Camel OGNL expression. The
-converted body can be null.
-
-|bodyType |Class |The message body class type
-
-|bodyOneLine | String | Converts the body to a String and removes all 
line-breaks, so the string is in one line.
-
-|prettyBody | String | Converts the body to a String, and attempts to pretty 
print if JSon or XML; otherwise the body is returned as the String value.
-
-|originalBody | Object | The original incoming body (only available if 
allowUseOriginalMessage=true).
-
-|mandatoryBodyAs(_type_) |Type |Converts the body to the given type determined 
by its
-classname, and expects the body to be not null.
-
-|mandatoryBodyAs(_type_).*OGNL* |Object |Converts the body to the given type 
determined by its
-classname and then invoke methods using a Camel OGNL expression.
-
-|header.foo |Object |refer to the foo header
-
-|header[foo] |Object |refer to the foo header
-
-|headers.foo |Object |refer to the foo header
-
-|headers:foo |Object |refer to the foo header
-
-|headers[foo] |Object |refer to the foo header
-
-|header.foo[bar] |Object |regard foo header as a map and perform lookup on the
-map with bar as the key
-
-|header.foo.*OGNL* |Object |refer to the foo header and invoke its value using 
a
-Camel OGNL expression.
-
-|headerAs(_key_,_type_) |Type |converts the header to the given type 
determined by its
-classname
-
-|headers |Map |refer to the headers
-|headers.size |int |The number of headers
-
-|variable.foo |Object |refer to the foo variable
-
-|variable[foo] |Object |refer to the foo variable
-
-|variable.foo.*OGNL* |Object |refer to the foo variable and invoke its
-value using a Camel OGNL expression.
-
-|variableAs(_key_,_type_) |Type |converts the variable to the given type 
determined by its
-classname
-
-|variables |Map |refer to the variables
-|variables.size |int |The number of variables
-
-|exchangeProperty.foo |Object |refer to the foo property on the exchange
-
-|exchangeProperty[foo] |Object |refer to the foo property on the exchange
-
-|exchangeProperty.foo.*OGNL* |Object |refer to the foo property on the 
exchange and invoke its
-value using a Camel OGNL expression.
-
-|messageAs(_type_) |Type |Converts the message to the given type determined by 
its
-classname. The converted message can be null.
-
-|messageAs(_type_).*OGNL* |Object |Converts the message to the given type 
determined by its
-classname and then invoke methods using a Camel OGNL expression. The
-converted message can be null.
-
-|sys.foo |String |refer to the JVM system property
-
-|sysenv.foo |String |refer to the system environment variable
-
-|env.foo |String |refer to the system environment variable
-
-|exception |Object |refer to the exception object on the exchange, is *null* if
-no exception set on exchange. Will fall back and grab caught exceptions
-(`Exchange.EXCEPTION_CAUGHT`) if the Exchange has any.
-
-|exception.*OGNL* |Object |refer to the exchange exception invoked using a 
Camel OGNL
-expression object
-
-|exception.message |String |refer to the `exception.message` on the exchange, 
is *null* if no
-exception set on exchange. Will fall back and grab caught exceptions
-(`Exchange.EXCEPTION_CAUGHT`) if the Exchange has any.
-
-|exception.stacktrace |String |refer to the exception.stracktrace on the 
exchange, is
-*null* if no exception set on exchange. Will fall back and grab caught
-exceptions (`Exchange.EXCEPTION_CAUGHT`) if the Exchange has any.
-
-|date:_command_ |Date |evaluates to a 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 (available with a File 
consumer).
-Command accepts offsets such as: `now-24h` or `header.xxx+1h` or even 
`now+1h30m-100`.
-
-|date:_command:pattern_ |String |Date formatting using 
`java.text.SimpleDateFormat` patterns.
-
-|date-with-timezone:_command:timezone:pattern_ |String |Date formatting using 
`java.text.SimpleDateFormat` timezones and patterns.
-
-|bean:_bean expression_ |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:type:fqnClassName`.
-
-|properties:key:default |String |Lookup a property 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 `!`.
-
-|fromRouteId |String |Returns the original route id where this exchange was 
created.
-
-|routeId |String |Returns the route id of the current route the
-Exchange is being routed.
-
-|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.
-
-|stepId |String |Returns the id of the current step the
-Exchange is being routed.
-
-|threadId |String |Returns the id of the current thread. Can be used for
-logging.
-
-|threadName |String |Returns the name of the current thread. Can be used for
-logging.
-
-|hostname |String |Returns the local hostname (may be empty if not possible to 
resolve).
-
-|ref:xxx |Object |To look up a bean from the Registry with
-the given id.
-
-|type:name.field |Object |To refer to a type or field by its FQN name. To 
refer to a
- field, you can append .FIELD_NAME. For example, you can refer to the
-constant field from Exchange as: `org.apache.camel.Exchange.FILE_NAME`
-
-|empty(type) |depends on parameter |Creates a new empty object of the type 
given as parameter. The type-parameter-Strings are case-insensitive. +
-
-`string` -> empty String +
-`list`   -> empty ArrayList +
-`map`    -> empty LinkedHashMap +
-
-|list(val1,val2,...) | java.util.ArrayList | The list function creates an 
ArrayList with the given set of values.
-
-|map(key1,value1,...) | java.util.LinkedHashMap | The map function creates a 
LinkedHashMap with the given set of pairs.
-
-|null |null |represents a *null*
-
-|random(value) |Integer |returns a random Integer between 0 (included) and 
_value_
-(excluded)
-
-|random(min,max) |Integer |returns a random Integer between _min_ (included) 
and
-_max_ (excluded)
-
-|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,exp) |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.
-
-|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.
-
-|substringBefore(exp,before) |String |Returns a substring of the message 
body/expression that comes before. Returns null if nothing comes before.
-|substringAfter(exp,before) |String |Returns a substring of the message 
body/expression that comes after. Returns null if nothing comes after.
-|substringBetween(exp,after,before) |String |Returns a substring of the 
message body/expression that are between before and after. Returns null if 
nothing comes between.
-
-|split(exp,separator)|String[] |Splits the message body/expression as a String 
value using the separator into a String array
-
-|collate(group) |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.
-
-|capitalize(exp) |String |Capitalizes the message body/expression as a String 
value (upper case every words)
-
-|normalizeWhitespace(exp) |String |Normalizes the whitespace in the message 
body (or expression) by cleaning up excess whitespaces.
-
-|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.
-
-|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}')`.
-
-|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 |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.
-
-|trim(exp) |String |The trim function trims the message body (or expression) 
by removing all leading and trailing white spaces.
-
-|concat(exp,exp,separator) |String |Performs a string concat using two 
expressions (message body as default) with optional separator
-
-|convertTo(exp,type) |Object |Converts the message body (or expression) to the 
specified type.
-|convertTo(exp,type).*OGNL* |Object |Converts the message body (or expression) 
to the specified type and then invoke methods using a Camel OGNL expression.
-
-|length(exp) |int |The payload length (number of bytes) of the message body 
(or expression).
-
-|size(exp) |int |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.
-
-|uppercase(exp) |String |Uppercases the message body (or expression)
-
-|lowercase(exp) |String |Lowercases the message body (or expression)
-
-|uuid(type) |String |Returns a UUID using the Camel `UuidGenerator`.
-You can choose between `default`, `classic`, `short`, `simple` and `random` as 
the type.
-If no type is given, the 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_.
-
-|hash(exp,algorithm) |String |Returns a hashed value (string in hex decimal) 
using JDK MessageDigest.
-The algorithm can be SHA-256 (default) or SHA3-256.
-
-|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 | 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.
-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.
-
-|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 | 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.
-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.
-
-|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.
-
-|pretty(exp) | String | Converts the inlined expression to a String, and 
attempts to pretty print if JSon or XML, otherwise the expression is returned 
as the String value.
+== Built-in Functions
 
-|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.
+The Simple language has many built-in functions which allows access to various 
part of Camel and the current `Exchange`, the message payload such as body and 
headers, and much more.
 
-|=======================================================================
-
-== Attachment functions
+[width="100%",cols="10%,10%,80%",options="header",]
+|====
+|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(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.
+|`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.
+|`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.
+|`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.
+|====
+
+=== Attachment functions
 
 From *Camel 4.10* onwards then Camel has built-in attachment functions making 
it easy to obtain
 details from attachments stored on the Camel Message such as from HTTP file 
uploads, email with file attachments etc.
@@ -362,38 +183,37 @@ details from attachments stored on the Camel Message such 
as from HTTP file uplo
 This requires having `camel-attachments` JAR on the classpath.
 
 [width="100%",cols="10%,10%,80%",options="header",]
-|=======================================================================
-|Function |Type |Description
-
-|attachments |Map | All the attachments as a `Map<String,DataHandler>`.
-|attachments.size | int | The number of attachments. Is 0 if there are no 
attachments.
-|attachmentContentAsText(key) | String | The content of the attachment as text 
(ie `String`).
-|attachmentContent(key) | Object | The content of the attachment.
-|attachmentContentAs(key,_type_) | Object | The content of the attachment, 
converted to the given type.
-|attachmentHeader(key,name) | Object | The attachment header with the given 
name.
-|attachmentHeaderAs(key,name,_type_) | Object | The attachment header with the 
given name, converted to the given type.
-|attachment[key] | DataHandler | The `DataHandler` for the given attachment.
-|attachment.*OGNL* | Object | refer to the foo attachment on the exchange and 
invoke its value using a Camel OGNL expression.
-|=======================================================================
-
-== Base64 functions
+|====
+|Function |Response Type |Description
+|`attachment._key_._OGNL_` | `Object` | Refer to the attachment with the given 
key on the `Exchange` and invoke its value using a Camel _OGNL syntax_.
+|`attachmentContent(_key_)` | `Object` | The content of the attachment.
+|`attachmentContentAs(_key_,type)` | `Object` | The content of the attachment, 
converted to the given type.
+|`attachmentContentAsText(_key_)` | `String` | The content of the attachment 
as text (ie `String`).
+|`attachmentHeader(key,name)` | `Object` | The attachment header with the 
given name.
+|`attachmentHeaderAs(_key_,name,type)` | `<T>` | The attachment header with 
the given name, converted to the given type.
+|`attachment[key]` | `DataHandler` | The `jakarta.activation.DataHandler` for 
the given attachment.
+|`attachments.size` | `int` | The number of attachments. Is 0 if there are no 
attachments.
+|`attachments` | `Map` | All the attachments as a 
`Map<String,jakarta.activation.DataHandler>`.
+|====
+
+=== Base64 functions
 
 From *Camel 4.18* onwards then Camel has built-in base64 functions to make it 
easy to encode/decode.
 
 This requires having `camel-base64` JAR on the classpath.
 
 [width="100%",cols="10%,10%,80%",options="header",]
-|=======================================================================
-|Function |Type |Description
-
-|base64Encode(exp) |String |Base64 encodes the message body (or expression)
-|base64Decode(exp) |byte[] |Base64 decodes the message body (or expression)
-|=======================================================================
-
+|====
+|Function |Response Type |Description
+|`base64Decode()` | `byte[]` |Base64 decodes the message body
+|`base64Decode(exp)` | `byte[]` |Base64 decodes the expression
+|`base64Encode()` | `String` |Base64 encodes the message body
+|`base64Encode(exp)` | `String` |Base64 encodes the expression
+|====
 
 == OGNL expression support
 
-The xref:simple-language.adoc[Simple] and xref:simple-language.adoc[Bean] 
languages support a Camel xref:ognl-language.adoc[OGNL] notation for invoking 
beans in a chain like fashion.
+The xref:simple-language.adoc[Simple] and xref:simple-language.adoc[Bean] 
languages support a _OGNL like_ notation for invoking methods (using 
reflection) in a fluent builder like style.
 
 https://en.wikipedia.org/wiki/OGNL[OGNL] (Object-Graph Navigation Language) is 
a powerful expression language used in Java. In Camel you can use OGNL dot 
notation to invoke methods. If you for instance have a body that contains a 
POJO that has a `getFamilyName` method then
 you can construct the Simple syntax as follows:
@@ -417,64 +237,67 @@ Camel's OGNL support is for invoking methods only. You 
cannot access fields. Cam
 When using *OGNL* then `camel-bean` JAR is required to be on the classpath.
 ====
 
-=== OGNL Variables
+=== Functions supporting OGNL
 
-The following variables support OGNL:
+The following functions support _OGNL syntax_:
 
 [width="100%",options="header",]
-|=======================================================================
-|Variable
-|camelContext
-|exchange
-|exception
-|body
-|bodyAs(type)
-|messageAs(type)
-|header.foo
-|exchangeProperty.foo
-|variable.foo
-|=======================================================================
-
+|====
+|Variable | Response Type | Description
+|`attachment._key_._OGNL_` | `Object` | Refer to the attachment with the given 
key on the `Exchange`. This requires having camel-attachments JAR on classpath.
+|`bodyAs(type)` | `<T>` | The message body converted to the given type
+|`body` | `Object` | The message body
+|`camelContext` | `CamelContext` | The `CamelContext`
+|`convertTo(exp,type)` | `<T>` | Converts the expression to the specified type
+|`exception` | `Throwable` | If the exchange failed due to an exception
+|`exchangeProperty._key_` | `Object` | The value from the exchange property 
with the given key
+|`exchange` | `Exchange` | The current `Exchange`
+|`header._key_` | `Object` | The value from the message header with the given 
key
+|`mandatoryBodyAs(type)` | `<T>` | The message body converted to the given type
+|`messageAs(type)` | `<T>` | The `org.apache.camel.Message` as a specialized 
instance
+|`variable._key_` | `Object` | The value from the variable with the given key
+|====
 
 === Basic OGNL examples
 
-Suppose the Message IN body contains a POJO which has a `getAddress()`
+Suppose the Message body contains a POJO which has a `getAddress()`
 method. Then you can use Camel OGNL notation to access the address object:
 
 [source,java]
---------------------------------
+----
 simple("${body.address}")
 simple("${body.address.street}")
 simple("${body.address.zip}")
---------------------------------
+----
 
 Camel understands the shorthand names for getters, but you can invoke
 any method or use the real name such as:
 
 [source,java]
---------------------------------------
+----
 simple("${body.address}")
 simple("${body.getAddress.getStreet}")
+simple("${body.getAddress().getStreet()}")
 simple("${body.address.getZip}")
 simple("${body.doSomething}")
---------------------------------------
+----
 
-You can also use the null safe operator (`?.`) to avoid NPE if, for
-example, the body does NOT have an address
+You can also use the null safe operator (`?.`) to avoid `NullPointerException` 
if, for example,
+the body does NOT have an address:
 
 [source,java]
-----------------------------------
+----
 simple("${body?.address?.street}")
-----------------------------------
+----
 
 === Advanced OGNL examples
 
 It is also possible to index in `Map` or `List` types, so you can do:
 
 [source,java]
----------------------------
+----
 simple("${body[foo].name}")
----------------------------
+----
 
 To assume the body is `Map` based and look up the value with `foo` as
 key, and invoke the `getName` method on that value.
@@ -483,95 +306,102 @@ If the key has space, then you *must* enclose the key 
with quotes, for
  example, 'foo bar':
 
 [source,java]
----------------------------------
+----
 simple("${body['foo bar'].name}")
----------------------------------
+----
 
 You can access the `Map` or `List` objects directly using their key name
 (with or without dots) :
 
 [source,java]
-------------------------------
+----
 simple("${body[foo]}")
 simple("${body[this.is.foo]}")
-------------------------------
+----
 
 Suppose there was no value with the key `foo` then you can use the null
 safe operator to avoid the NPE as shown:
 
 [source,java]
-----------------------------
+----
 simple("${body[foo]?.name}")
-----------------------------
+----
 
 You can also access `List` types, for example, to get lines from the
 address you can do:
 
 [source,java]
-----------------------------------
+----
 simple("${body.address.lines[0]}")
 simple("${body.address.lines[1]}")
 simple("${body.address.lines[2]}")
-----------------------------------
+----
 
 There is a special `last` keyword which can be used to get the last
 value from a list.
 
 [source,java]
--------------------------------------
+----
 simple("${body.address.lines[last]}")
--------------------------------------
+----
 
 And to get the 2nd last you can subtract a number, so we can use
 `last-1` to indicate this:
 
 [source,java]
----------------------------------------
+----
 simple("${body.address.lines[last-1]}")
----------------------------------------
+----
 
 And the third last is, of course:
 
 [source,java]
----------------------------------------
+----
 simple("${body.address.lines[last-2]}")
----------------------------------------
+----
 
 And you can call the size method on the list with
 
 [source,java]
-------------------------------------
+----
 simple("${body.address.lines.size}")
-------------------------------------
+----
 
 Camel supports the length field for Java arrays as well, e.g.:
 
 [source,java]
----------------------------------------------------
+----
 String[] lines = new String[]{"foo", "bar", "cat"};
-exchange.getIn().setBody(lines);
+exchange.getMessage().setBody(lines);
 
 simple("There are ${body.length} lines")
----------------------------------------------------
+----
+
+[TIP]
+====
+You can also use the *length* function from *Camel 4.18*: `simple("There are 
${length()} lines")`
+====
 
-And yes, you can combine this with the operator support as shown below:
+And yes, you can combine this with the Simple operators such as checking if a 
zip code is larger than 1000:
 
 [source,java]
-------------------------------------
+----
 simple("${body.address.zip} > 1000")
-------------------------------------
+----
 
 == Operator support
 
-The parser is limited to only support a single operator.
+The simple language has limited support for operators that are used in 
predicates to evaluate whether a condition is either _true_ or _false_.
 
-To enable it, the left value must be enclosed in `${ }`. The syntax is:
+Camel operators require the left value must be enclosed in `${ }`.
+The syntax is:
 
---------------------------
+[source,text]
+----
 ${leftValue} OP rightValue
---------------------------
+----
 
-Where the `rightValue` can be a String literal enclosed in `' '`,
+Where the `rightValue` can be a string literal enclosed in `' '`,
 `null`, a constant value or another expression enclosed in `${ }`.
 
 IMPORTANT: There *must* be spaces around the operator.
@@ -583,110 +413,76 @@ you can use `>` comparison for numeric values.
 The following operators are supported:
 
 [width="100%",cols="50%,50%",options="header",]
-|===
+|====
 |Operator |Description
-
-|== |equals
-
-|=~ |equals ignore case (will ignore case when comparing String values)
-
-|> |greater than
-
-|>= |greater than or equals
-
-|< |less than
-
-|+<=+ |less than or equals
-
-|!= |not equals
-
-|!=~ |not equals ignore case (will ignore case when comparing String values)
-
-|contains |For testing if contains in a string-based value
-
-|!contains |For testing if it does not contain in a string-based value
-
-|~~ |For testing if contains by ignoring case sensitivity in a string-based 
value
-
-|!~~ |For testing if it does not contain by ignoring case sensitivity in a 
string-based value
-
-|regex |For matching against a given regular expression pattern defined as a
-String value
-
-|!regex |For not matching against a given regular expression pattern defined 
as a
-String value
-
-|in |For matching if in a set of values, each element must be separated by
-comma. If you want to include an empty value, then it must be defined using 
double comma, e.g. `',, bronze,silver,gold'`, which
-is a set of four values with an empty value and then the three medals.
-
-|!in |For matching if not in a set of values, each element must be separated
-by comma. If you want to include an empty value, then it must be defined using 
double comma, e.g. `',,bronze,silver,gold'`, which
-is a set of four values with an empty value and then the three medals.
-
-|is |For matching if the left-hand side type is an instance of the value.
-
-|!is |For matching if the left-hand side type is not an instance of the value.
-
-|range |For matching if the left-hand side is within a range of values defined
-as numbers: `from..to`.
-
-|!range |For matching if the left-hand side is not within a range of values
-defined as numbers: `from..to`.
-
-|startsWith |For testing if the left-hand side string starts with the 
right-hand string.
-|!startsWith |For testing if the left-hand side string does not start with the 
right-hand string.
-
-|endsWith |For testing if the left-hand side string ends with the right-hand 
string.
-|!endsWith |For testing if the left-hand side string does not end with the 
right-hand string.
-
-|===
+|`==` | equals
+|`=~` | equals ignore case (will ignore case when comparing String values)
+|`>` | greater than
+|`>=` | greater than or equals
+|`<` | less than
+|`+<=+` | less than or equals
+|`!=` | not equals
+|`!=~` | not equals ignore case (will ignore case when comparing String values)
+|`~~` | For testing if contains by ignoring case sensitivity in a string-based 
value
+|`!~~` | For testing if it does not contain by ignoring case sensitivity in a 
string-based value
+|`contains` | For testing if contains in a string-based value
+|`!contains` | For testing if it does not contain in a string-based value
+|`endsWith` | For testing if the left-hand side string ends with the 
right-hand string.
+|`!endsWith` | For testing if the left-hand side string does not end with the 
right-hand string.
+|`in` | For matching if in a set of values, each element must be separated by 
comma. If you want to include an empty value, then it must be defined using 
double comma, e.g. `',, bronze,silver,gold'`, which is a set of four values 
with an empty value and then the three medals.
+|`!in` | For matching if not in a set of values, each element must be 
separated by comma. If you want to include an empty value, then it must be 
defined using double comma, e.g. `',,bronze,silver,gold'`, which is a set of 
four values with an empty value and then the three medals.
+|`is` | For matching if the left-hand side type is an instance of the value.
+|`!is` | For matching if the left-hand side type is not an instance of the 
value.
+|`range` | For matching if the left-hand side is within a range of values 
defined as numbers: `from..to`.
+|`!range` | For matching if the left-hand side is not within a range of values 
defined as numbers: `from..to`.
+|`regex` | For matching against a given regular expression pattern defined as 
a String value
+|`!regex` | For not matching against a given regular expression pattern 
defined as a String value
+|`startsWith` | For testing if the left-hand side string starts with the 
right-hand string.
+|`!startsWith` | For testing if the left-hand side string does not start with 
the right-hand string.
+|====
 
 And the following unary operators can be used:
 
 [width="100%",cols="50%,50%",options="header",]
-|===
+|====
 |Operator |Description
+|`++` | To increment a number by one. The left-hand side must be a function, 
otherwise parsed as literal.
+|`--` | To decrement a number by one. The left-hand side must be a function, 
otherwise parsed as literal.
+|====
 
-|++ |To increment a number by one. The left-hand side must be a
-function, otherwise parsed as literal.
-
-|-- |To decrement a number by one. The left-hand side must be a
-function, otherwise parsed as literal.
-
-|\n |To use newline character.
+And the following special symbols:
 
-|\t |To use tab character.
-
-|\r |To use carriage return character.
-
-|\} |To use the `}` character as text. This may be needed when building a JSon 
structure with the simple language.
-|===
+[width="100%",cols="50%,50%",options="header",]
+|====
+|Symbol |Description
+|`\n` | To use newline character.
+|`\t` | To use tab character.
+|`\r` | To use carriage return character.
+|`\}` | To use the `}` character as text. This may be needed when building a 
JSon structure with the simple language.
+|====
 
 And the following logical operators can be used to group expressions:
 
 [width="100%",cols="50%,50%",options="header",]
-|===
+|====
 |Operator |Description
-
-|&& |The logical and operator is used to group two expressions.
-
-| \|\| |The logical or operator is used to group two expressions.
-|===
+|`&&` | The logical and operator is used to group two expressions.
+|`\|\|` | The logical or operator is used to group two expressions.
+|====
 
 The syntax for AND is:
 
 [source,text]
-----------------------------------------------------------
+----
 ${leftValue} OP rightValue && ${leftValue} OP rightValue
-----------------------------------------------------------
+----
 
 And the syntax for OR is:
 
 [source,text]
----------------------------------------------------------
+----
 ${leftValue} OP rightValue || ${leftValue} OP rightValue
----------------------------------------------------------
+----
 
 Some examples:
 
@@ -715,9 +511,10 @@ simple("${header.bar}++")
 When you compare with different types such as String and int, then you
 have to take a bit of care. Camel will use the type from the left-hand side
 as first priority. And fallback to the right-hand side type if both values
-couldn't be compared based on that type. +
- This means you can flip the values to enforce a specific type. Suppose
-the bar value above is a String. Then you can flip the equation:
+couldn't be compared based on that type. This means you can flip the values
+to enforce a specific type. Suppose the bar value above is a String.
+
+Then you can flip the equation:
 
 [source,java]
 ----
@@ -750,16 +547,14 @@ simple("${header.date} == ${date:now:yyyyMMdd}")
 simple("${header.type} == ${bean:orderService?method=getOrderType}")
 ----
 
-And an example with `contains`, testing if the title contains the word
-Camel
+And an example with `contains`, testing if the title contains the word Camel
 
 [source,java]
 ----
 simple("${header.title} contains 'Camel'")
 ----
 
-And an example with regex, testing if the number header is a 4-digit
-value:
+And an example with regex, testing if the number header is a 4-digit value:
 
 [source,java]
 ----
@@ -767,8 +562,8 @@ simple("${header.number} regex '\\d{4}'")
 ----
 
 And finally an example if the header equals any of the values in the
-list. Each element must be separated by comma, and no space around. +
- This also works for numbers etc., as Camel will convert each element
+list. Each element must be separated by comma, and no space around.
+This also works for numbers etc., as Camel will convert each element
 into the type of the left-hand side.
 
 [source,java]
@@ -791,8 +586,7 @@ String
 simple("${header.type} is 'java.lang.String'")
 ----
 
-We have added a shorthand for all `java.lang` types, so you can write it
-as:
+We have added a shorthand for all `java.lang` types, so you can write it as:
 
 [source,java]
 ----
@@ -832,10 +626,9 @@ order:
 </from>
 ----
 
-=== Using and / or
+=== Combining multiple expression using AND / OR
 
-If you have two expressions you can combine them with the `&&` or `||`
-operator.
+If you have two expressions you can combine them with the `&&` (and) or `||` 
(or) operator.
 
 For instance:
 
@@ -851,19 +644,19 @@ And of course the `||` is also supported. The sample 
would be:
 simple("${header.title} contains 'Camel' || ${header.type'} == 'gold'")
 -----
 
-== Examples
+== EIP Examples
 
 In the XML DSL sample below, we filter based on a header value:
 
 [source,xml]
---------------------------------------------
+----
 <from uri="seda:orders">
    <filter>
        <simple>${header.foo}</simple>
        <to uri="mock:fooOrders"/>
    </filter>
 </from>
---------------------------------------------
+----
 
 The Simple language can be used for the predicate test above in the
 Message Filter pattern, where we test if the
@@ -880,8 +673,7 @@ from("seda:orders")
         .to("seda:fooOrders");
 ----
 
-You can also use the simple language for simple text concatenations such
-as:
+You can also use the simple language for simple text concatenations such as:
 
 [source,java]
 ----
@@ -1003,6 +795,35 @@ Instead of the message body then a simple expression can 
be nested as input, for
 </setBody>
 ----
 
+=== Substring Before, After, or Between
+
+In *Camel 4.18* there are additional substring methods to make it easier to 
select a part of a string.
+
+For example suppose the message body contains 'Hello great big World how are 
you', then you select different parts:
+
+[source,java]
+----
+// select text before `World` -> `Hello great big `
+.setHeader("foo", simple("${substringBefore('World'}"))
+
+// select text after `World` -> ` how are you`
+.setHeader("foo2", simple("${substringAfter('World'}"))
+
+// select text between `great` ... `how` -> ` big World `
+.setHeader("foo2", simple("${substringBetween('great', 'how'}"))
+
+// NOTE: and you can wrap this with trim to remove spaces:
+
+// select text before `World` -> `Hello great big`
+.setHeader("foo", simple("$trim{${substringBefore('World'}}")})
+
+// select text after `World` -> `how are you`
+.setHeader("foo2", simple("$trim{${substringAfter('World'}}"))
+
+// select text between `great` ... `how` -> `big World`
+.setHeader("foo2", simple("$trim{${substringBetween('great', 'how'}}"))
+----
+
 === Replacing double and single quotes
 
 You can use the `replace` function to more easily replace all single or double 
quotes in the message body,
@@ -1099,4 +920,54 @@ e.g., to refer to a file on the classpath you can do:
 .setHeader("myHeader").simple("resource:classpath:mysimple.txt")
 ----
 
+== Pretty XML or JSon
+
+From *Camel 4.18* onwards then the Simple language can _pretty format_ the 
output.
+
+In Java DSL you turn this on via the `boolean` parameter that is set as `true` 
below:
+
+[source,java]
+----
+from("direct:xml")
+    .setBody().simple("<person><name>Jack</name></person>", true)
+    .to("mock:result");
+
+from("direct:json")
+    .setBody().simple("{ \"name\": \"Jack\", \"age\": 44 }", true)
+    .to("mock:result");
+
+from("direct:text")
+    .setBody().simple("Hello ${body}", true)
+    .to("mock:result");
+----
+
+In YAML DSL you specific `pretty: true` as follows:
+
+[source,yaml]
+----
+route:
+  from:
+    uri: direct:xml
+    steps:
+      - setBody:
+          simple:
+            expression: "<person><name>Jack</name></person>"
+            pretty: true
+      - to:
+          uri: mock:result
+----
+
+And in XML DSL you use the pretty attribute to true as show below:
+
+[source,xml]
+----
+<route>
+  <from uri="direct:json"/>
+  <setBody>
+    <simple pretty="true">{ "name": "Jack", "age": 44 }</simple>
+  </setBody>
+  <to uri="mock:result"/>
+</route>
+----
+
 include::spring-boot:partial$starter.adoc[]
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 8cadeb3cf323..ab20fab19918 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
@@ -56,7 +56,7 @@ public final class SimpleConstants {
     public static final String EXCEPTION_MESSAGE = "exception.message";
     @Metadata(description = "The exception stacktrace (also from caught 
exceptions), is null if no exception present.",
               javaType = "String", label = "function", displayName = 
"Exception Stacktrace")
-    public static final String EXCEPTION_STACKTRACE = "exception.stackTrace";
+    public static final String EXCEPTION_STACKTRACE = "exception.stacktrace";
     @Metadata(description = "Returns the id of the current thread. Can be used 
for logging.", javaType = "long",
               label = "function")
     public static final String THREAD_ID = "threadId";
@@ -202,7 +202,7 @@ public final class SimpleConstants {
     @Metadata(description = "Converts the message body (or expression) to the 
specified type.",
               label = "function,ognl", displayName = "Convert To")
     public static final String CONVERT_TO = "convertTo(exp,type)";
-    @Metadata(description = "Whether the message body (or expression) is null 
or empty (list/map types are tested if they have 0 elements).)",
+    @Metadata(description = "Whether the message body (or expression) is null 
or empty (list/map types are tested if they have 0 elements).",
               label = "function", javaType = "boolean", displayName = "Is 
Empty")
     public static final String IS_EMPTY = "isEmpty(exp)";
     @Metadata(description = "The trim function trims the message body (or 
expression) by removing all leading and trailing white spaces.",

Reply via email to