Skip to content

Wishlist #65

Closed
Closed

Description

@jwaterloo

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.

Activity

  1. nlohmann commented on May 3, 2015

    @nlohmann
    Owner

    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?

  2. nlohmann commented on Jun 4, 2015

    @nlohmann
    Owner

    Without more information, I close this issue for now.

  3. jrandall commented on Jun 5, 2015

    @jrandall
    Contributor

    @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?

  4. nlohmann commented on Jun 5, 2015

    @nlohmann
    Owner

    Oops, my bad...

  5. nlohmann commented on Jun 16, 2015

    @nlohmann
    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?

  6. jwaterloo commented on Jun 17, 2015

    @jwaterloo
    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.

  7. nlohmann commented on Jun 17, 2015

    @nlohmann
    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?
  8. nlohmann commented on Jun 27, 2015

    @nlohmann
    Owner

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

  9. jwaterloo commented on Jun 30, 2015

    @jwaterloo
    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

  10. nlohmann commented on Dec 14, 2015

    @nlohmann
    Owner

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

  11. added a commit that references this issue on Nov 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions