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());
+}

Reply via email to