Repository: nifi-minifi-cpp Updated Branches: refs/heads/master e2e473267 -> cb5ae08b9
MINIFICPP-428 Added JSON escape/unescape functions to EL This closes #281. Signed-off-by: Marc Parisi <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/repo Commit: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/commit/cb5ae08b Tree: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/tree/cb5ae08b Diff: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/diff/cb5ae08b Branch: refs/heads/master Commit: cb5ae08b9e199edf3d91aafa6d04de5614650b28 Parents: e2e4732 Author: Andrew I. Christianson <[email protected]> Authored: Thu Mar 15 12:28:55 2018 -0400 Committer: Marc Parisi <[email protected]> Committed: Mon Mar 19 12:41:23 2018 -0400 ---------------------------------------------------------------------- EXPRESSIONS.md | 40 +++++++++++++++++++- extensions/expression-language/Expression.cpp | 31 +++++++++++++++ .../ExpressionLanguageTests.cpp | 24 ++++++++++++ 3 files changed, 93 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/cb5ae08b/EXPRESSIONS.md ---------------------------------------------------------------------- diff --git a/EXPRESSIONS.md b/EXPRESSIONS.md index ee633a7..371ddb4 100644 --- a/EXPRESSIONS.md +++ b/EXPRESSIONS.md @@ -200,6 +200,11 @@ token, filename. - [`indexOf`](#indexof) - [`lastIndexOf`](#lastindexof) +### Encode/Decode Functions + +- [`escapeJson`](#escapejson) +- [`unescapeJson`](#unescapejson) + ## Planned Features ### String Manipulation @@ -216,12 +221,10 @@ token, filename. ### Encode/Decode Functions -- `escapeJson` - `escapeXml` - `escapeCsv` - `escapeHtml3` - `escapeHtml4` -- `unescapeJson` - `unescapeXml` - `unescapeCsv` - `unescapeHtml3` @@ -1230,3 +1233,36 @@ following Expressions will provide the following results: | `${filename:lastIndexOf('.')}` | `20` | | `${filename:lastIndexOf('a')}` | `17` | | `${filename:lastIndexOf(' ')}` | `11` | + +### escapeJson + +**Description**: This function prepares the Subject to be inserted into JSON +document by escaping the characters in the String using Json String rules. The +function correctly escapes quotes and control-chars (tab, backslash, cr, ff, +etc.) + +**Subject Type**: String + +**Arguments**: No arguments + +**Return Type**: String + +**Examples**: + +If the "message" attribute is 'This is a "test!"', then the Expression +`${message:escapeJson()}` will return 'This is a \"test!\"' + +### unescapeJson + +**Description**: This function unescapes any Json literals found in the String. + +**Subject Type**: String + +**Arguments**: No arguments + +**Return Type**: String + +**Examples**: + +If the "message" attribute is 'This is a \"test!\"', then the Expression +`${message:unescapeJson()}` will return 'This is a "test!"' http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/cb5ae08b/extensions/expression-language/Expression.cpp ---------------------------------------------------------------------- diff --git a/extensions/expression-language/Expression.cpp b/extensions/expression-language/Expression.cpp index 091051f..2beba0b 100644 --- a/extensions/expression-language/Expression.cpp +++ b/extensions/expression-language/Expression.cpp @@ -22,6 +22,10 @@ #include <algorithm> #include <string> +#include "rapidjson/reader.h" +#include "rapidjson/writer.h" +#include "rapidjson/document.h" + #include <expression/Expression.h> #include <regex> #include "Driver.h" @@ -172,6 +176,29 @@ Value expr_lastIndexOf(const std::vector<Value> &args) { } } +Value expr_escapeJson(const std::vector<Value> &args) { + const std::string &arg_0 = args[0].asString(); + rapidjson::StringBuffer buf; + rapidjson::Writer<rapidjson::StringBuffer> writer(buf); + writer.String(arg_0.c_str()); + std::string result(buf.GetString()); + return Value(result.substr(1, result.length()-2)); +} + +Value expr_unescapeJson(const std::vector<Value> &args) { + std::stringstream arg_0_ss; + arg_0_ss << "\"" << args[0].asString() << "\""; + rapidjson::Reader reader; + rapidjson::StringStream ss(arg_0_ss.str().c_str()); + rapidjson::Document doc; + doc.ParseStream(ss); + if (doc.IsString()) { + return Value(std::string(doc.GetString())); + } else { + return Value(); + } +} + #ifdef EXPRESSION_LANGUAGE_USE_REGEX Value expr_replace(const std::vector<Value> &args) { @@ -497,6 +524,10 @@ Expression make_dynamic_function(const std::string &function_name, return make_dynamic_function_incomplete<expr_indexOf>(function_name, args, 1); } else if (function_name == "lastIndexOf") { return make_dynamic_function_incomplete<expr_lastIndexOf>(function_name, args, 1); + } else if (function_name == "escapeJson") { + return make_dynamic_function_incomplete<expr_escapeJson>(function_name, args, 0); + } else if (function_name == "unescapeJson") { + return make_dynamic_function_incomplete<expr_unescapeJson>(function_name, args, 0); #ifdef EXPRESSION_LANGUAGE_USE_REGEX } else if (function_name == "replace") { return make_dynamic_function_incomplete<expr_replace>(function_name, args, 2); http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/cb5ae08b/libminifi/test/expression-language-tests/ExpressionLanguageTests.cpp ---------------------------------------------------------------------- diff --git a/libminifi/test/expression-language-tests/ExpressionLanguageTests.cpp b/libminifi/test/expression-language-tests/ExpressionLanguageTests.cpp index a4a8899..f427c15 100644 --- a/libminifi/test/expression-language-tests/ExpressionLanguageTests.cpp +++ b/libminifi/test/expression-language-tests/ExpressionLanguageTests.cpp @@ -1016,3 +1016,27 @@ TEST_CASE("If Else 2", "[expressionIfElse2]") { // NOLINT flow_file_a->addAttribute("filename", "An example file.txt"); REQUIRE("no" == expr({flow_file_a}).asString()); } + +TEST_CASE("Encode JSON", "[expressionEncodeJSON]") { // NOLINT + auto expr = expression::compile("${message:escapeJson()}"); + + auto flow_file_a = std::make_shared<MockFlowFile>(); + flow_file_a->addAttribute("message", "This is a \"test!\""); + REQUIRE("This is a \\\"test!\\\"" == expr({flow_file_a}).asString()); +} + +TEST_CASE("Decode JSON", "[expressionDecodeJSON]") { // NOLINT + auto expr = expression::compile("${message:unescapeJson()}"); + + auto flow_file_a = std::make_shared<MockFlowFile>(); + flow_file_a->addAttribute("message", "This is a \\\"test!\\\""); + REQUIRE("This is a \"test!\"" == expr({flow_file_a}).asString()); +} + +TEST_CASE("Encode Decode JSON", "[expressionEncodeDecodeJSON]") { // NOLINT + auto expr = expression::compile("${message:escapeJson():unescapeJson()}"); + + auto flow_file_a = std::make_shared<MockFlowFile>(); + flow_file_a->addAttribute("message", "This is a \"test!\""); + REQUIRE("This is a \"test!\"" == expr({flow_file_a}).asString()); +}
