Skip to content

Commit 2c441a3

Browse files
authored
Allow escaped json to survive rendering (#5)
* add option to .dump() strings instead of .get<std::string>() * strip leading and trailing " to preserve expected behavior * add comments * update single include * don't run push CI * remove R formatting attempting to appease windows compiler * put push back to match upstream and reduce complexity
1 parent e35f106 commit 2c441a3

File tree

5 files changed

+46
-2
lines changed

5 files changed

+46
-2
lines changed

include/inja/config.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ struct ParserConfig {
8080
*/
8181
struct RenderConfig {
8282
bool throw_at_missing_includes {true};
83+
bool escape_strings {};
8384
};
8485

8586
} // namespace inja

include/inja/environment.hpp

+5
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ class Environment {
8888
lexer_config.notation = notation;
8989
}
9090

91+
/// Sets the config for rendering strings raw or escaped
92+
void set_escape_strings(bool escape_strings) {
93+
render_config.escape_strings = escape_strings;
94+
}
95+
9196
/// Sets the element notation syntax
9297
void set_search_included_templates_in_files(bool search_in_files) {
9398
parser_config.search_included_templates_in_files = search_in_files;

include/inja/renderer.hpp

+14-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,20 @@ class Renderer : public NodeVisitor {
5555

5656
void print_data(const std::shared_ptr<json> value) {
5757
if (value->is_string()) {
58-
*output_stream << value->get_ref<const json::string_t&>();
58+
std::string val;
59+
if (config.escape_strings) {
60+
// get the value as a dump() to properly escape values
61+
val = value->dump();
62+
63+
// strip the leading and trailing " characters that are added by dump()
64+
// if C++20 is adopted, val.starts_with and val.ends_with would clean this up a bit
65+
val = val.substr(0,1) == "\"" && val.substr(val.length()-1,1) == "\""
66+
? val.substr(1, val.length()-2)
67+
: val;
68+
} else {
69+
val = value->get_ref<const json::string_t&>();
70+
}
71+
*output_stream << val;
5972
} else if (value->is_number_integer()) {
6073
*output_stream << value->get<const json::number_integer_t>();
6174
} else if (value->is_null()) {

single_include/inja/inja.hpp

+20-1
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,7 @@ struct ParserConfig {
906906
*/
907907
struct RenderConfig {
908908
bool throw_at_missing_includes {true};
909+
bool escape_strings {};
909910
};
910911

911912
} // namespace inja
@@ -2150,7 +2151,20 @@ class Renderer : public NodeVisitor {
21502151

21512152
void print_data(const std::shared_ptr<json> value) {
21522153
if (value->is_string()) {
2153-
*output_stream << value->get_ref<const json::string_t&>();
2154+
std::string val;
2155+
if (config.escape_strings) {
2156+
// get the value as a dump() to properly escape values
2157+
val = value->dump();
2158+
2159+
// strip the leading and trailing " characters that are added by dump()
2160+
// if C++20 is adopted, val.starts_with and val.ends_with would clean this up a bit
2161+
val = val.substr(0,1) == "\"" && val.substr(val.length()-1,1) == "\""
2162+
? val.substr(1, val.length()-2)
2163+
: val;
2164+
} else {
2165+
val = value->get_ref<const json::string_t&>();
2166+
}
2167+
*output_stream << val;
21542168
} else if (value->is_number_integer()) {
21552169
*output_stream << value->get<const json::number_integer_t>();
21562170
} else if (value->is_null()) {
@@ -2803,6 +2817,11 @@ class Environment {
28032817
lexer_config.notation = notation;
28042818
}
28052819

2820+
/// Sets the config for rendering strings raw or escaped
2821+
void set_escape_strings(bool escape_strings) {
2822+
render_config.escape_strings = escape_strings;
2823+
}
2824+
28062825
/// Sets the element notation syntax
28072826
void set_search_included_templates_in_files(bool search_in_files) {
28082827
parser_config.search_included_templates_in_files = search_in_files;

test/test-renderer.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ TEST_CASE("types") {
1818
data["relatives"]["brother"] = "Chris";
1919
data["relatives"]["sister"] = "Jenny";
2020
data["vars"] = {2, 3, 4, 0, -1, -2, -3};
21+
data["quoted"] = "\"quoted value\"";
2122
data["json_pointers"]["example.com"] = "online";
2223
data["json_pointers"]["and/or"] = "slash";
2324
data["json_pointers"]["and~or"] = "tilde";
@@ -42,6 +43,11 @@ TEST_CASE("types") {
4243
CHECK(env.render("{{ @name }}", data) == "@name");
4344
CHECK(env.render("{{ $name }}", data) == "$name");
4445

46+
CHECK(env.render("{\"Value\":\"{{ quoted }}\"}", data) == "{\"Value\":\"\"quoted value\"\"}");
47+
env.set_escape_strings(true);
48+
CHECK(env.render("{\"Value\":\"{{ quoted }}\"}", data) == "{\"Value\":\"\\\"quoted value\\\"\"}");
49+
env.set_escape_strings(false);
50+
4551
env.set_element_notation(inja::ElementNotation::Pointer);
4652
CHECK(env.render("{{ json_pointers/example.com }}", data) == "online");
4753
CHECK(env.render("{{ json_pointers/and~1or }}", data) == "slash");

0 commit comments

Comments
 (0)