Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wishlist #65

Closed
jwaterloo opened this issue May 1, 2015 · 10 comments
Closed

Wishlist #65

jwaterloo opened this issue May 1, 2015 · 10 comments

Comments

@jwaterloo
Copy link

A common use case in web development is the need for flatten and unflatten functions, that is the ability to flatten a json object into a map of javascript assignment strings and vice versa.

{
"member1" : true,
"member2" : "Hello World",
"member3" : [1, {"member4" : 4, "member5" : 6.5}, 3]
}

into

prefix "whatever"

key = whatever.member1
value = true
key = whatever.member2
value = "Hello World"
key = whatever.member3[0]
value = 1
key = whatever.member1[1].member4
value = 4
key = whatever.member1[1].member5
value = 6.5
key = whatever.member3[2]
value = 3

function sighatures would be something like

map<string, json_primitive_that_insn't_object_or_array> flatten(json_object_or_array, symbol_name);
json_object_or_array unflatten(map<string, json_primitive_that_insn't_object_or_array>, symbol_name);

The type of the map would be string to a json primitive that isn't an object or an array.

The use case is that the keys in the map could be used as form field names. PHP and jQuery both are already doing this natively. Wouldn't it be nice if C++ had equal or better footing for web development.

@nlohmann
Copy link
Owner

nlohmann commented May 3, 2015

Hi @jrandall, thanks for the input. I have an idea what you mean, and I have an idea how to realize it. Could you give me some references for PHP and jQuery so I can check?

@nlohmann
Copy link
Owner

nlohmann commented Jun 4, 2015

Without more information, I close this issue for now.

@nlohmann nlohmann closed this as completed Jun 4, 2015
@jrandall
Copy link
Contributor

jrandall commented Jun 5, 2015

@nlohmann it looks like you replied to me instead of @jwaterloo by mistake. @jwaterloo, perhaps you can provide the references for PHP and jQuery that Niels is looks for?

@nlohmann
Copy link
Owner

nlohmann commented Jun 5, 2015

Oops, my bad...

@nlohmann nlohmann reopened this Jun 5, 2015
@nlohmann
Copy link
Owner

Hi @jwaterloo, thanks for the input. I have an idea what you mean, and I have an idea how to realize it. Could you give me some references for PHP and jQuery so I can check?

@jwaterloo
Copy link
Author

On 6/16/2015 4:43 PM, Niels wrote:

Hi @jwaterloo https://github.com/jwaterloo, thanks for the input. I
have an idea what you mean, and I have an idea how to realize it.
Could you give me some references for PHP and jQuery so I can check?


Reply to this email directly or view it on GitHub
#65 (comment).

http://api.jquery.com/jQuery.param/

jQuery.param()

|// >=1.4:|
|$.param({ a: { b: 1, c: 2 }, d: [ 3, 4, { e: 5 } ] });|
|// "a[b]=1&a[c]=2&d[]=3&d[]=4&d[2][e]=5"|

In our case
map<string, ?>
key -> value
a[b] -> 1
a[c] -> 2
d[] -> 3
d[] -> 4
d[2][e] -> 5
or
a.b -> 1
a.c -> 2
d[] -> 3
d[] -> 4
d[2].e -> 5

see also http://api.jquery.com/jQuery.ajax/ which is used throughout
jQuery AJAX calls since 1.4
"Sending Data to the Server

By default, Ajax requests are sent using the GET HTTP method. If the
POST method is required, the method can be specified by setting a value
for the type option. This option affects how the contents of the data
option are sent to the server. POST data will always be transmitted to
the server using UTF-8 charset, per the W3C XMLHTTPRequest standard.

The data option can contain either a query string of the form
key1=value1&key2=value2, or an object of the form {key1: 'value1', key2:
'value2'}. If the latter form is used, the data is converted into a
query string using jQuery.param() before it is sent. This processing can
be circumvented by setting processData to false. The processing might be
undesirable if you wish to send an XML object to the server; in this
case, change the contentType option from
application/x-www-form-urlencoded to a more appropriate MIME type."

In case of PHP, it automatic. Whenever you request anything from the
$GET and other collections
a[b] -> 1
a[c] -> 2
d[] -> 3
d[] -> 4
d[2][e] -> 5
is automatically converted to the PHP map/hash equivalent of JSON's { a:
{ b: 1, c: 2 }, d: [ 3, 4, { e: 5 } ] }
So web developers rarely ever has to do any serialization, knowingly, as
long as the data type complexity is a tree and not an object graph which
JSON can't handle anyway.

Any C++ library should definitely have the general use case for when
they are needed but also the most common convenient functions/objects
for use by the 90%++ of the time. Of course this needs to be reflexive,
ie. going in the opposite direction.

...

More jQuery usage

http://api.jquery.com/serialize/

web developers typically name there input fields "d[2][e]" so when the
form is submitted it is already in the proper format for PHP. So jquery
isn't even needed. However when jquery is needed they'll param() for
code and serialize() when dealing with the form element in the UI. Both
returns the encoded format.

@nlohmann
Copy link
Owner

Thanks. I'll have a look and maybe come back if I have some questions. Until then, I would appreciate more concrete examples.

  • What kind of functions would you expect?
  • What should be the input?
  • What should be the output?

@nlohmann
Copy link
Owner

Hi @jwaterloo, could you be so kind and give me more concrete examples?

@jwaterloo
Copy link
Author

On 6/17/2015 5:55 PM, Niels wrote:

Thanks. I'll have a look and maybe come back if I have some questions.
Until then, I would appreciate more concrete examples.

  • What kind of functions would you expect?
  • What should be the input?
  • What should be the output?


Reply to this email directly or view it on GitHub
#65 (comment).

I am not over set on the names

// flatten
std::map<string, string>&& flatten(const json& object_or_array, const
std::string& name);
std::map<wstring, wstring>&& flatten(const json& object_or_array);
std::map<string, boost|std::any>&& flatten(const json& object_or_array,
const std::string& name);
std::map<wstring, boost|std::any>&& flatten(const json& object_or_array);
std::map<string, boost|std::variant>&& flatten(const json&
object_or_array, const std::string& name);
std::map<wstring, boost|std::variant>&& flatten(const json&
object_or_array);

// boost|std::any means boost::any or std::any depending on which
version of standard you are targeting
// boost|std::variant means boost::variant or std::variant depending on
which version of standard you are targeting
// boost::any, std::any, boost::variant or std::variant could be
replaced with json object that is not an array or embedded object or in
other words a primitive string, number, null, true, false, empty object
or empty array
// json object actual means your json object container class or any C++
class that could be converted to actual json object via copying or more
efficient streaming/reflection

// there should be a symmetric operation
// deflatten (again a better name might be better)
json&& deflatten(const std::map<string, string>& values, const
std::string& name);
json&& deflatten(const std::map<wstring, wstring>& values);
json&& deflatten(const std::map<string, boost|std::any>& values, const
std::string& name);
json&& deflatten(const std::map<wstring, boost|std::any>& values);
json&& deflatten(const std::map<string, boost|std::variant>& values,
const std::string& name);
json&& deflatten(const std::map<wstring, boost|std::variant>& values);

// symmetry guarantees
json object = ...;
json object2 = deflatten(flatten(object, "somename"), "somename");
assert(object == object2);

std::map<wstring, wstring> values = ...;
std::map<wstring, wstring> values2 = flatten(deflatten(values,
"somename"), "somename");
assert(values == values2);

// what does parameters look like
json somename = {"a" : "1", "b" : {"d" : "5", "f" : [6, true, null, 7,
false]}, "co ff ee" : [3, true, 4, false]};

result of flatten(somename, "somename");
key: somename.a, value: 1
key: somename.b.d, value: 5
key: somename.b.f[0], value: 6
key: somename.b.f[1], value: true
key: somename.b.f[2], value: null
key: somename.b.f[3], value: 7
key: somename.b.f[4], value: false
key: somename.["co ff ee"][0], value: 3
key: somename.["co ff ee"][1], value: true
key: somename.["co ff ee"][2], value: 4
key: somename.["co ff ee"][3], value: false

...

std::map<wstring, any|variant|primitive_json> values;
values.push_back("somename2.b.f[0]", "6");// ignored
values.push_back("somename.a", "1");
values.push_back("somename.b.d", "5");
values.push_back("somename.b.f[0]", "6");
values.push_back("somename.b.f[1]", true);
values.push_back("somename.b.f[2]", null);
values.push_back("somename.b.f[3]", "7");
values.push_back("somename.b.f[4]", "false");
values.push_back("somename3.b.f[0]", "6");// ignored
values.push_back("somename.["co ff ee"][0]", "3");
values.push_back("somename.["co ff ee"][1]", "true");
values.push_back("somename.["co ff ee"][2]", "4");
values.push_back("somename.["co ff ee"][3]", "false");
values.push_back("somename4.b.f[0]", "6");// ignored
json object = deflatten(values, "somename");

...

// real world usage

// HTTP GET

write server servlet code to generate following HTML

NAME PRICE

// HTTP POST

// NOTE: usecase, no complicated manual serialization or
deserialization; deflatten reassembles the JSON tree
json object_or_array = deflatten(request_map, "products");
vector products = object_or_array;
for(auto product : products)
{
// insert product in database
}

// Next request: SECURITY
flatten(const json& object_or_array, const std::string& name,
std::function<bool(wstring, any|variant|primitive_json)> filter);
deflatten(const std::map<string, boost|std::any>& values, const
std::string& name, std::function<bool(wstring,
any|variant|primitive_json)> filter);
// std::function<bool(wstring, any|variant|primitive_json)> filter takes
the key and primitive value and return a boolean stating whether the
value gets applied to the map or object in question. function may throw
in case of fail fast security exceptions or if a member function may
aggregate the false attempts for informative debugging

@nlohmann
Copy link
Owner

I think this change is too complicated and does not really cover JSON core functionality.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants