GMS 2 [SOLVED] JSON encoding with nested object inside an array

bacteriaman

Member
I'm trying to produce the following encoded JSON in order to POST scores to a RESTful service:

Code:
{
  "_links": {
    "type": {
      "href": "http://example.com"
    }
  },
  "title": {"value": "Score 100 by John"},
  "field_game_reference": [{"target_id": "2"}],
  "field_player_reference": [{"target_id": "3"}],
  "field_score_points": {"value": "100"}
}
I'm very close using the following DS functions:

Code:
var href = ds_map_create();
ds_map_add(href, "href", "http://example.com");
var type = ds_map_create();
ds_map_add_map(type, "type", href);

var map = ds_map_create();
ds_map_add_map(map, "_links", type);

var item = ds_map_create();
ds_map_add(item, "value", "Score 100 by John");
ds_map_add_map(map, "title", item);

var item = ds_map_create();
ds_map_add(item, "target_id", "2");
ds_map_add_map(map, "field_game_reference", item);

var item = ds_map_create();
ds_map_add(item, "target_id", "3");
ds_map_add_map(map, "field_player_reference", item);

var item = ds_map_create();
ds_map_add(item, "value", "100");
ds_map_add_map(map, "field_score_points", item);

ds_map_destroy(item);
ds_map_destroy(href);
ds_map_destroy(type);
ds_map_destroy(map);
This outputs the following:

Code:
{
  "field_player_reference": { "target_id": "3" },
  "_links": {
    "type": {
      "href": "http:\/\/example.com"
    }
  },
  "title": { "value": "Score 100 by John" },
  "field_game_reference": { "target_id": "2" },
  "field_score_points": { "value": "100" }
}
The only thing different is the array (square brackets) wrapping the object (curly brackets) for the two field references:

Code:
  "field_game_reference": [{"target_id": "2"}],
  "field_player_reference": [{"target_id": "3"}],
This presumably requires another type of nesting, but the syntax eludes me. Any advice is greatly appreciated.

Note the above GML has not been optimized. Perhaps there's a more efficient way to go about it (?)
 

Bart

WiseBart
Those square brackets in the JSON always correspond to a ds_list in GameMaker. To let it know that you added a ds_list as a ds_map_value, you can use ds_map_add_list. To indicate that a map was added to a list, you can use ds_list_mark_as_map.

So, for example, for the field_game_reference, you should first add the ds_map item to a ds_list, then add that ds_list to map:
Code:
var item = ds_map_create();
var list = ds_list_create();
ds_map_add(item, "target_id", "2");
ds_list_add(list, item);
ds_list_mark_as_map(list, ds_list_size(list)-1);
ds_map_add_list(map, "field_game_reference", list);
Unfortunately, there's no more efficient way to do this at the moment, although chained accessors are on the roadmap.

Also note that you don't have to destroy any of the additional ds_lists or ds_maps that you add using ds_list_mark_as_list, ds_list_mark_as_map, ds_map_add_list, ds_map_add_map. Just destroy the root map. In this case, that would be map.
 
Last edited:

FrostyCat

Member
The built-in functionality leaves a lot to be desired for, but I've written utilities making them a bit more bearable.

For building nested JSON structures, see the JsonData, JsonList and JsonMap constructor scripts in my GMSugar library. The wiki there has examples of how to use them.

For accessing nested JSON structures, see the Get and Set scripts from my Universal Accessor library. That's the best I've got until YoYo makes up its mind about chained accessors.
 

bacteriaman

Member
@Bart, indeed, ds_list_mark_as_map did the trick--thank you! I ended up using "0" instead of ds_list_size for the second param. And thanks for the tip about the single ds_map_destroy.

@FrostyCat, your JSON scripts sound super useful--thank you!
 
Top