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 91e74cd7c51 CAMEL-20931: camel-core - Add substring function to simple
language (#14682)
91e74cd7c51 is described below
commit 91e74cd7c517e412c83a691a7114c9d16b682a3e
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Jul 1 08:02:35 2024 +0200
CAMEL-20931: camel-core - Add substring function to simple language (#14682)
---
.../language/csimple/joor/OriginalSimpleTest.java | 26 +++++++++++
.../modules/languages/pages/simple-language.adoc | 40 +++++++++++++++++
.../camel/language/csimple/CSimpleHelper.java | 33 ++++++++++++++
.../language/simple/SimpleExpressionBuilder.java | 40 +++++++++++++++++
.../simple/ast/SimpleFunctionExpression.java | 52 ++++++++++++++++++++++
.../apache/camel/language/simple/SimpleTest.java | 51 +++++++++++++++++++++
.../camel/support/builder/ExpressionBuilder.java | 45 +++++++++++++++++++
7 files changed, 287 insertions(+)
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 3477bb46cf2..4c55bfb9b0b 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
@@ -249,6 +249,32 @@ public class OriginalSimpleTest extends
LanguageTestSupport {
assertExpression("${replace(",∅)}", "{foo: cheese}");
}
+ @Test
+ public void testSubstringExpression() {
+ exchange.getMessage().setBody("ABCDEFGHIJK");
+ // head
+ assertExpression("${substring(0)}", "ABCDEFGHIJK");
+ assertExpression("${substring(1)}", "BCDEFGHIJK");
+ assertExpression("${substring(3)}", "DEFGHIJK");
+ assertExpression("${substring(99)}", "");
+ // tail
+ assertExpression("${substring(0)}", "ABCDEFGHIJK");
+ assertExpression("${substring(-1)}", "ABCDEFGHIJ");
+ assertExpression("${substring(-3)}", "ABCDEFGH");
+ assertExpression("${substring(-99)}", "");
+ // head and tail
+ assertExpression("${substring(1,-1)}", "BCDEFGHIJ");
+ assertExpression("${substring(3,-3)}", "DEFGH");
+ assertExpression("${substring(1,-3)}", "BCDEFGH");
+ assertExpression("${substring(3,-1)}", "DEFGHIJ");
+ assertExpression("${substring(0,-1)}", "ABCDEFGHIJ");
+ assertExpression("${substring(1,0)}", "BCDEFGHIJK");
+ assertExpression("${substring(99,-99)}", "");
+ assertExpression("${substring(0,-99)}", "");
+ assertExpression("${substring(99,0)}", "");
+ assertExpression("${substring(0,0)}", "ABCDEFGHIJK");
+ }
+
@Test
public void testTrimSimpleExpressions() {
assertExpression(" \t${exchangeId}\n".trim(),
exchange.getExchangeId());
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 55782cdaf81..b4ffc73e284 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
@@ -246,6 +246,18 @@ To make it easier to replace single and double quotes,
then you can use XML esca
|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 `\"` as double quote, `\'` as single quote, and
`\∅` 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 |replace all the string values in 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.
+
|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
@@ -854,6 +866,34 @@ You can nest functions, such as shown below:
</setHeader>
----
+=== Substring
+
+You can use the `substring` function to more easily clip the message body.
+For example if the message body contains the following 10 letters `ABCDEFGHIJ`
then:
+
+[source,xml]
+----
+<setBody>
+ <simple>${substring(3)}</simple>
+</setBody>
+----
+
+Then the message body after the substring will be `DEFGHIJ`.
+If you want to clip from the end instead, then use negative values such as
`substring(-3)`.
+
+You can also clip from both ends at the same time such as `substring(1,-1)`
that will clip the first and last character in the String.
+
+If the number is higher than the length of the message body, then an empty
string is returned, for example `substring(99)`.
+
+Instead of the message body then a simple expression can be nested as input,
for example using a variable, as shown below:
+
+[source,xml]
+----
+<setBody>
+ <simple>${substring(1,-1,${variable.foo})}</simple>
+</setBody>
+----
+
=== Replacing double and single quotes
You can use the `replace` function to more easily replace all single or double
quotes in the message body,
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 13c09c92749..a540d1eabd6 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
@@ -483,6 +483,39 @@ public final class CSimpleHelper {
throw new IllegalArgumentException("function empty(%s) has unknown
type".formatted(type));
}
+ public static String substring(Exchange exchange, Object num1, Object
num2) {
+ int head =
exchange.getContext().getTypeConverter().tryConvertTo(int.class, exchange,
num1);
+ int tail =
exchange.getContext().getTypeConverter().tryConvertTo(int.class, exchange,
num2);
+ if (head < 0 && tail == 0) {
+ // if there is only one value and its negative then we want to
clip from tail
+ tail = head;
+ head = 0;
+ }
+ head = Math.abs(head);
+ tail = Math.abs(tail);
+ String text = exchange.getMessage().getBody(String.class);
+ if (text == null) {
+ return null;
+ }
+ int len = text.length();
+ if (head > 0) {
+ if (head <= len) {
+ text = text.substring(head);
+ } else {
+ text = "";
+ }
+ len = text.length();
+ }
+ if (tail > 0) {
+ if (tail <= len) {
+ text = text.substring(0, len - tail);
+ } else {
+ text = "";
+ }
+ }
+ return text;
+ }
+
public static int random(Exchange exchange, Object min, Object max) {
int num1 =
exchange.getContext().getTypeConverter().tryConvertTo(int.class, exchange, min);
int num2 =
exchange.getContext().getTypeConverter().tryConvertTo(int.class, exchange, 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 82d0a18b7b0..54e59bba477 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
@@ -234,6 +234,46 @@ public final class SimpleExpressionBuilder {
};
}
+ /**
+ * Substring string values from the expression
+ */
+ public static Expression substringExpression(final String expression,
final String head, final String tail) {
+ return new ExpressionAdapter() {
+ private Expression exp;
+ private Expression exp1;
+ private Expression exp2;
+
+ @Override
+ public void init(CamelContext context) {
+ exp =
context.resolveLanguage("simple").createExpression(expression);
+ exp.init(context);
+ exp1 = ExpressionBuilder.simpleExpression(head);
+ exp1.init(context);
+ exp2 = ExpressionBuilder.simpleExpression(tail);
+ exp2.init(context);
+ }
+
+ @Override
+ public Object evaluate(Exchange exchange) {
+ int num1 = exp1.evaluate(exchange, Integer.class);
+ int num2 = exp2.evaluate(exchange, Integer.class);
+ if (num1 < 0 && num2 == 0) {
+ // if there is only one value and its negative then we
want to clip from tail
+ num2 = num1;
+ num1 = 0;
+ }
+ num1 = Math.abs(num1);
+ num2 = Math.abs(num2);
+ return ExpressionBuilder.substring(exp, num1,
num2).evaluate(exchange, Object.class);
+ }
+
+ @Override
+ public String toString() {
+ return "substring(" + expression + "," + head + "," + tail +
")";
+ }
+ };
+ }
+
/**
* Hashes the value using the given algorithm
*/
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 200f9282372..27ca0bfab16 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
@@ -689,6 +689,33 @@ public class SimpleFunctionExpression extends
LiteralExpression {
return SimpleExpressionBuilder.replaceExpression(exp, from, to);
}
+ // substring function
+ remainder = ifStartsWithReturnRemainder("substring(", function);
+ if (remainder != null) {
+ String values = StringHelper.before(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substring(num)},
${substring(num,num)}, or ${substring(num,num,expression)} was: "
+ + function,
+ token.getIndex());
+ }
+ String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
false);
+ if (tokens.length > 3) {
+ throw new SimpleParserException(
+ "Valid syntax: ${replace(num,num,expression)} was: " +
function, token.getIndex());
+ }
+ String num1 = tokens[0];
+ String num2 = "0";
+ if (tokens.length > 1) {
+ num2 = tokens[1];
+ }
+ String exp = "${body}";
+ if (tokens.length == 3) {
+ exp = tokens[2];
+ }
+ return SimpleExpressionBuilder.substringExpression(exp, num1,
num2);
+ }
+
// random function
remainder = ifStartsWithReturnRemainder("random(", function);
if (remainder != null) {
@@ -1638,6 +1665,31 @@ public class SimpleFunctionExpression extends
LiteralExpression {
private String createCodeExpressionMisc(String function) {
String remainder;
+ // substring function
+ remainder = ifStartsWithReturnRemainder("substring(", function);
+ if (remainder != null) {
+ String values = StringHelper.before(remainder, ")");
+ if (values == null || ObjectHelper.isEmpty(values)) {
+ throw new SimpleParserException(
+ "Valid syntax: ${substring(num)},
${substring(num,num)} was: "
+ + function,
+ token.getIndex());
+ }
+ String[] tokens = StringQuoteHelper.splitSafeQuote(values, ',',
false);
+ if (tokens.length > 2) {
+ throw new SimpleParserException(
+ "Valid syntax: ${replace(num,num)} was: " + function,
token.getIndex());
+ }
+ String num1 = tokens[0];
+ String num2 = "0";
+ if (tokens.length > 1) {
+ num2 = tokens[1];
+ }
+ num1 = num1.trim();
+ num2 = num2.trim();
+ return "substring(exchange, " + num1 + ", " + num2 + ")";
+ }
+
// random function
remainder = ifStartsWithReturnRemainder("random(", 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 938a4110adb..46bec4cc7b7 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
@@ -2063,6 +2063,57 @@ public class SimpleTest extends LanguageTestSupport {
assertExpression("${replace(",',${header.foo})}", "{'foo':
'cheese'}");
}
+ @Test
+ public void testSubstringExpression() {
+ exchange.getMessage().setBody("ABCDEFGHIJK");
+ // head
+ assertExpression("${substring(0)}", "ABCDEFGHIJK");
+ assertExpression("${substring(1)}", "BCDEFGHIJK");
+ assertExpression("${substring(3)}", "DEFGHIJK");
+ assertExpression("${substring(99)}", "");
+ // tail
+ assertExpression("${substring(0)}", "ABCDEFGHIJK");
+ assertExpression("${substring(-1)}", "ABCDEFGHIJ");
+ assertExpression("${substring(-3)}", "ABCDEFGH");
+ assertExpression("${substring(-99)}", "");
+ // head and tail
+ assertExpression("${substring(1,-1)}", "BCDEFGHIJ");
+ assertExpression("${substring(3,-3)}", "DEFGH");
+ assertExpression("${substring(1,-3)}", "BCDEFGH");
+ assertExpression("${substring(3,-1)}", "DEFGHIJ");
+ assertExpression("${substring(0,-1)}", "ABCDEFGHIJ");
+ assertExpression("${substring(1,0)}", "BCDEFGHIJK");
+ assertExpression("${substring(99,-99)}", "");
+ assertExpression("${substring(0,-99)}", "");
+ assertExpression("${substring(99,0)}", "");
+ assertExpression("${substring(0,0)}", "ABCDEFGHIJK");
+
+ exchange.getMessage().setBody("Hello World");
+ exchange.getMessage().setHeader("foo", "1234567890");
+
+ // head
+ assertExpression("${substring(0,0,${header.foo})}", "1234567890");
+ assertExpression("${substring(1,0,${header.foo})}", "234567890");
+ assertExpression("${substring(3,0,${header.foo})}", "4567890");
+ assertExpression("${substring(99,0,${header.foo})}", "");
+ // tail
+ assertExpression("${substring(0,0,${header.foo})}", "1234567890");
+ assertExpression("${substring(0,-1,${header.foo})}", "123456789");
+ assertExpression("${substring(0,-3,${header.foo})}", "1234567");
+ assertExpression("${substring(0,-99,${header.foo})}", "");
+ // head and tail
+ assertExpression("${substring(1,-1,${header.foo})}", "23456789");
+ assertExpression("${substring(3,-3,${header.foo})}", "4567");
+ assertExpression("${substring(1,-3,${header.foo})}", "234567");
+ assertExpression("${substring(3,-1,${header.foo})}", "456789");
+ assertExpression("${substring(0,-1,${header.foo})}", "123456789");
+ assertExpression("${substring(1,0,${header.foo})}", "234567890");
+ assertExpression("${substring(99,-99,${header.foo})}", "");
+ assertExpression("${substring(0,-99,${header.foo})}", "");
+ assertExpression("${substring(99,0,${header.foo})}", "");
+ assertExpression("${substring(0,0,${header.foo})}", "1234567890");
+ }
+
@Test
public void testListRemoveByInstance() {
List<Object> data = new ArrayList<>();
diff --git
a/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
b/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
index 4b54b53f7db..19a0fdfe4d5 100644
---
a/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
+++
b/core/camel-support/src/main/java/org/apache/camel/support/builder/ExpressionBuilder.java
@@ -1841,6 +1841,51 @@ public class ExpressionBuilder {
};
}
+ /**
+ * Substring string values in the given expression.
+ */
+ public static Expression substring(
+ final Expression expression,
+ final int head, final int tail) {
+ return new ExpressionAdapter() {
+ @Override
+ public Object evaluate(Exchange exchange) {
+ String text = expression.evaluate(exchange, String.class);
+ if (text == null) {
+ return null;
+ }
+ int len = text.length();
+ if (head > 0) {
+ if (head <= len) {
+ text = text.substring(head);
+ } else {
+ text = "";
+ }
+ len = text.length();
+ }
+ if (tail > 0) {
+ if (tail <= len) {
+ text = text.substring(0, len - tail);
+ } else {
+ text = "";
+ }
+ }
+ return text;
+ }
+
+ @Override
+ public void init(CamelContext context) {
+ super.init(context);
+ expression.init(context);
+ }
+
+ @Override
+ public String toString() {
+ return "substring(" + expression + ", " + head + ", " + tail +
")";
+ }
+ };
+ }
+
/**
* Replaces string values in the given expression.
*/