Using JSON Parser Support Functions
===================================

The JSON Parser package provides not only a JSON Parser, a JSON Generator and a
JSON Validator, but also a rich set of JSON Support Functions to assist C developers
is using JSON Data easily with the minimum of coding overhead.

This document presents basic ideas on how to use the JSON Support Functions provided 
with this JSON Parser package and the available D-List functions, to provide support
for typical types of JSON Data usage, in the C programming environment.

Presented are some typical examples of JSON usage from other higher level coding 
environments, and how to easily achieve the same with this package.

The structure of this document is identical to that of JSON-Usage-with-C.txt
found in the same GUIDES directory. The sections are followed in the same order
so it is easy for a reader to both find a section in both documents and compare
coding styles required to achieve a particular goal.

As this is a lower level programming environment data types are not automatically
encoded for the callers, that will always be the responsibility of the C programmer.
As will be the normal concepts such as ensuring data is within bounds, strings are
properly terminated, etc. This is not Python after all...

Background
----------

This JSON Parser package was written to provide not only a fully functional, fast
and accurate JSON Parser for C programmers, but also to provide the JSON data in a
form that is more generally useful to C developers. Most JSON parsers write the
parsed JSON data into arrays etc, and there are numerous issues as C as a language
does not natively support unbounded or variable sized data. However the D-List 
package for C does natively provide such support with a very easy to use, and rich,
set of available functions to access, modify, add to, manipulate, manage and copy 
this variable data. The D-List package is also extremely fast & efficient and a 
great way to manipulate varied data from different sources.

All functions described in this document that start with json_xxx are part of the 
JSON Parser package, and details about there usage and arguments, can be found in
the JSON Parser documentation. All functions that start with list_xxx are part of
the D-List package.

JSON is a data format focused on inter-system and inter-language interoperability. 
If you are unfamiliar with JSON grammar or syntax, please refer to ECMA-404 and 
RFC 8259 or 
	
	http://json.org 

before trying to use the JSON Support Functions.

Throughout this JSON Parser package, all JSON Objects and JSON Arrays are accessed
and manipulated using D-List list_objects, and all JSON value items are elements
within those list_objects. The list_objects are arranged hierarchically allowing
these data structures to represent the JSON syntax exactly.

If you are unfamiliar with D-List, then please consult the reference documentation.
To find that documentation, or to learn more about list_objects, elements, and the
rich set of D-List functions; please refer to the D-List documentation, which is 
available in the D-List distribution Header Files, or a set of Doxy files that are
included in that distribution, or online at 

	http://info.fwsentry.org/dlist/index.html

Examples in this tutorial
-------------------------

All of the code snippets in this document can be found in the function
test_json_function_set() which is in the file json-parser-test.c. These
code snippets have all been tested, but are presented here with some of
the extra clutter removed for clarity. The code in the function flows in
the same order as the tutorial, so you can examine the state of the JSON
data at any point along its path to see the results.


Starting a new JSON Data Block from scratch.
--------------------------------------------

At the root level of a JSON data block there can be only 1 item, either a single
value, a JSON Array or a JSON Object. It you need more than a single value at the
top level, you must enclosed them in a JSON Array, or create a JSON Object.

If you do not have an existing JSON data block to read or modify, you will need to
create one first. If you have a JSON data block in a file, or one that was 
transmitted over the network, you can create the list_object representation of the
entire JSON Data by calling the function json_parse_data_block()

In all cases you will need a D-List list_object to describe whatever is at the top
level. You do this the same way the JSON Parser creates a representation of a JSON
data block. If called, the Parser will return to the caller a list_object, and one
of 3 JSON Value Types that tells the caller what that root list_object represents.
Therefore, the root list_object always has list elements (data values) in it,
they could be either:
	
	•	a single value item as a single element in that list, or
	•	a JSON array of value items, which are now a set of elements in
		that list, or
	•	a JSON Object which are a set of elements in that list that also
		have object_names filled in (as all JSON Object Members must have 
		names that are string values, even if the string is zero length).

So to pass the root list_object to another party expecting a JSON Data Block you
should pass the root list_object and a JSON value type as well, to inform the 
recipient of that JSON Data what to expect from the root list_object. In fact a 
recipient can analyse the list_object and figure out what it is easily enough, but 
passing the JSON value type cuts out needless redundant work. (See Note 1 for more 
information). This is also the format of calling the JSON Generator. 

To create a root list_object for your new JSON data hierarchy simply call
the function 

	list_object *new_root_object;
	new_root_object = json_create_new_list_object(value_type, NULL);		(see Note 2)
	
Where value_type will depend on what type of data is at the root of JSON data
tree you are building. If it is a JSON Object, you use JSON_object as the
value_type, otherwise for either a JSON Array or a single data value, use the
value_type JSON_array.

You now have a new, and empty, list_object to add elements to. The elements you
add must be consistent with the type of list_object you created. It is up to
you, the C programmer, to add the correct type of elements to the list_objects.

You can always call the JSON generator with your root list_object and see if it
will generate a JSON data text for you. If there are grammar or syntax errors
in the way you have assembled the list_objects and elements, it will throw an
error at that location in the list_object hierarchy. If there are minor errors
such as having an object_name in an Array element, a warning is written to 
stderr, and the name is just ignored. If there are structural errors, you will
be notified along with the JSON generation failure.


Adding New Elements to the list_object
--------------------------------------

All elements in every list_object throughout the JSON data hierarchy, be they at
the root level or below, must have a JSON value type recorded in them. This is so
everyone who touches the element will know exactly what the value type is, and 
cannot make a mistake of loading an integer into a pointer, or similar mistakes.

Continuing the previous example above with a new JSON data hierarchy, let's 
assume the new list_object is a JSON Object.

Adding a JSON Object Member <"member name" : value>
---------------------------------------------------

To add a new JSON Object Member to this JSON Object list_object, the only actions
required are to call the relavant JSON Suport Function with the new Member data

There are 2 choices for this, either 

	json_object_name_member_add_xxx() or json_list_object_member_add_xxx()
	
However as this is a new JSON Object with no current Members in it, the function
json_object_name_member_add_xxx() will not work as it adds Members to an Object by 
name. That function is covered later in this tutorial.

For this example let's assume you wish to add a Member:value pair of "Hayao" : 72

	list_object *json_object;
	int ret;
	
	ret = json_list_object_member_add_number(json_object, "Hayao", 72, 0);
	if (ret) { an error occurred }

after this the root_object will have 1 element in it, and if you called the JSON 
Generator with this root list_list at this point, the generated JSON representation
would be

	{ "Hayao": 72 }

Now the above example was overly simple for demonstration purposes. When 
programming in C there is always the real issue of where to store the strings
associated with any list element. However all the JSON Support Functions that 
add or modify members or data values take care of the proper allocation and
disposal of all memory chunks used for strings. The caller does not have to 
deal with this.

Adding another Member to the Object, this time a string value, we use the same
JSON Support Function

	ret -= json_list_object_member_add_string(json_object, "Miyazaki", "Director");

So now the root list_object has 2 elements in it, and if you called the JSON 
Generator with this root list_list at this point, the generated JSON representation
would be

	{ 
	  "Hayao": 72,
	  "Miyazaki": "Director"
	}

When later the list_object is erased, all the strings will be automatically 
deallocated and freed.

In the last example we added a Object Member with a string value. The process is
same for any of the other value types as well, here we will add a fractional number
value.

	ret -= json_list_object_member_add_number(json_object, "IMDB", 0, 9.2);

with the result being the JSON data block

	{
	  "Hayao": 72, 
	  "Miyazaki": "Director", 
	  "IMDB": 9.200000
	}

There are 2 other value types available in JSON, for simplicity of interfaces
these have been implemented in 2 separate functions

	ret -= json_list_object_member_add_boolean(json_object, "IMDB active", TRUE);
	ret -= json_list_object_member_add_null(json_object, "Showing in SF");

after calling these functions, the JSON data block now looks like:

	{
	  "Hayao": 72, 
	  "Miyazaki": "Director", 
	  "IMDB": 9.200000, 
	  "IMDB active": true, 
	  "Showing in SF": null
	}


Adding a JSON Array value
-------------------------

Building on the previous example if you wish to add an element to a JSON Object
that has an Array value, here is an example. 

	list_object *array_list;
	json_integer_t new_date = 2022;
	json_integer_t dates[] = { 1988, 1992, 1998, 2002, 2008, 2014 };

	array_list = json_create_new_list_object(JSON_array, NULL);
	ret = json_list_object_member_add_list(json_object, "films", array_list, JSON_array);

after calling these functions, the JSON data block now looks like:

	{
	  "Hayao": 72, 
	  "Miyazaki": "Director", 
	  "IMDB": 9.200000, 
	  "IMDB active": true, 
	  "Showing in SF": null, 
	  "films": [ ]
	}

now let's add a value to that new Array

	ret = json_list_object_array_value_add_number(array_list, &new_date, NULL, 1);

	{
	  "Hayao": 72, 
	  "Miyazaki": "Director", 
	  "IMDB": 9.200000, 
	  "IMDB active": true, 
	  "Showing in SF": null, 
	  "films": [ 2022 ]
	}

one value at a time is tedious, so let's add 6 of them at once.

	ret = json_list_object_array_value_add_number(array_list, &dates, NULL, 6);

after calling that functions, the JSON data block now looks like:

	{
	  "Hayao": 72, 
	  "Miyazaki": "Director", 
	  "IMDB": 9.200000, 
	  "IMDB active": true, 
	  "Showing in SF": null, 
	  "films": [ 2022, 1988, 1992, 1998, 2002, 2008, 2014 ]
	}

So now you notice that the list of values in the Array is not ordered, so
let's sort it.

	list_fast_sort(array_list, LIST_ASCENDING, ENTIRE_LIST);

now the JSON data block looks like this:
	{
	  "Hayao": 72, 
	  "Miyazaki": "Director", 
	  "IMDB": 9.200000, 
	  "IMDB active": true, 
	  "Showing in SF": null, 
	  "films": [ 1988, 1992, 1998, 2002, 2008, 2014, 2022 ]
	}

Adding a JSON Object Value
--------------------------

The same applies if you want to add an element which starts a new JSON Object,
the code is basically the same, except the new Elements being Object Members must
have names.

	list_object *films_json_object;

	char new_object_name[] = "museums";
	char museums_to_add[][10] = { "Louvre", "Tate", "MOMA", "Getty", "" };
	char location[][14] = { "Paris", "London", "New York", "Santa Monica","" };
	int i = 0;

	films_json_object = json_create_new_list_object(JSON_object);
	ret = json_list_object_array_value_add_list(array_list, films_json_object, JSON_object);

	{
	  "Hayao": 72, 
	  "Miyazaki": "Director", 
	  "IMDB": 9.200000, 
	  "IMDB active": true, 
	  "Showing in SF": null, 
	  "films": [ 1988, 1992, 1998, 2002, 2008, 2014, 2022, { } ]
	}

Oops, now you notice that the Object is at the end of the Array, you wanted it
at the front, so let's sort it again.

	list_fast_sort(array_list, LIST_ASCENDING, ENTIRE_LIST);

now the JSON data block looks like this:
	{
	  "Hayao": 72, 
	  "Miyazaki": "Director", 
	  "IMDB": 9.200000, 
	  "IMDB active": true, 
	  "Showing in SF": null, 
	  "films": [ { }, 1988, 1992, 1998, 2002, 2008, 2014, 2022 ]
	}

sorting a JSON Array with the default compare function will sort all numbers
and strings within their blocks, but will also arrange other value types in
a predictable order, Objects first, then Arrays, then null and booleans, then
numbers and finally strings.

Now lets add Members to the new JSON we just added and shifted in the Array. It
is the same as for the original root list_object, except you specify the new
list_object instead. It is important to keep track of these list_object pointers
so you know which is which.

	for (i = 0; (museums_to_add[i][0] != '\0'); ++i) {
		ret -= json_list_object_member_add_string(films_json_object, museums_to_add[i], location[i]);
	}

JSON Support functions does not provide a function to add multiple Object Members,
but it is simple enough if you have your data organized.

now the JSON data block looks like this:
	{
	  "Hayao": 72, 
	  "Miyazaki": "Director", 
	  "IMDB": 9.200000, 
	  "IMDB active": true, 
	  "Showing in SF": null, 
	  "films": [
		{
		  "Louvre": "Paris", 
		  "Tate": "London", 
		  "MOMA": "New York", 
		  "Getty": "Santa Monica"
		}, 
		1988, 
		1992, 
		1998, 
		2002, 
		2008, 
		2014, 
		2022
	  ]
	}

It should be noted the the JSON Generator will generate JSON text from any valid 
JSON data hierarchy. So for example to test a piece of data without rendering the
entire block, you can call it with a sample from above:

	char *output_buffer;
	ret = json_generate_data_block(films_json_object, JSON_object, &output_buffer);

and you would get this output instead, although the entire JSON data block is still
intact

	{
		"Louvre": "Paris", 
		"Tate": "London", 
		"MOMA": "New York", 
		"Getty": "Santa Monica"
	}

Moving elements between lists
-----------------------------

Let's say you discovered you put the elements in the wrong place. And they are
supposed to be in a separate Object Member on the root level. You will have 
noticed that the string "Museums" was not used in the above snippet, that was
the mistake that was discovered. We can easily rectify this:

	list_object *museum_json_object;
	list_object *films_json_object;		/* still has the JSON Obj ptr */
	list_object *array_list;			/* still the same */
	list_object *json_object;
	char new_object_name[] = "museums";


	museum_json_object = json_create_new_list_object(JSON_object, NULL);
	ret = json_list_object_member_add_list(json_object, new_object_name, museum_json_object, JSON_object);
	
	list_transfer(films_json_object, museum_json_object);	/* move all the elements from, to */
	list_delete_index(array_list, 0);						/* remove the first Array value (and it cleans up the underlying list_object) */
	free(films_json_object);	
	films_json_object = NULL;								

So now the root list_object still has 7 elements in it, and if you called the JSON 
Generator with this root object_list at this point, the generated JSON representation
would be

{
  "Hayao": 72, 
  "Miyazaki": "Director", 
  "IMDB": 9.200000, 
  "IMDB active": true, 
  "Showing in SF": null, 
  "films": [ 1988, 1992, 1998, 2002, 2008, 2014, 2022 ], 
  "museums": 
  {
    "Louvre": "Paris", 
    "Tate": "London", 
    "MOMA": "New York", 
    "Getty": "Santa Monica"
  }
}


Adding a JSON Array of String Values
------------------------------------

Now we add an Array to the root list_object and populate it with string values

	list_object *cities_json_array;

	cities_json_array = json_create_new_list_object(JSON_array, NULL);
	ret = json_list_object_member_add_list(json_object, "cities", cities_json_array, JSON_array);
	for (i = 0; (location[i][0] != '\0'); ++i) {
		ret = json_list_object_array_value_add_string(cities_json_array, location[i]);
	}

	to simplify the interface and general usage, the function
	json_list_object_member_add_list() takes one string value at a time.

{
  "Hayao": 72, 
  "Miyazaki": "Director", 
  "IMDB": 9.200000, 
  "IMDB active": true, 
  "Showing in SF": null, 
  "films": [ 1988, 1992, 1998, 2002, 2008, 2014, 2022 ], 
  "museums": 
  {
    "Louvre": "Paris", 
    "Tate": "London", 
    "MOMA": "New York", 
    "Getty": "Santa Monica"
  }
  "cities": [
    "Paris", 
    "London", 
    "New York", 
    "Santa Monica"
  ]
}


Finding JSON Object Members
---------------------------

Finding Members is a large part of using JSON data blocks, this JSON package
provides extensive support for this, allowing things to be located by member name,
value, and even array values. So let's start with something simpler.

In the example we have built so far, we want to find the IMDB score. There are
2 different ways to go about this, you can use D-List functions directly or use
the JSON Package Support Functions. If you have the pointer to the correct
list_object using the D-List functions is fast and simple, if you want to only 
use the JSON Support Functions that is fine as well, but adds a layer of code to
perform the same things. If you do not already have the list_object for where 
you are searching, or you want to search the hierarchy for something in an unknown
location, then the JSON Support Functions are what you need, they will cut out a
lot of extra code you would otherwise have to write.

So with the list_object already known, we can do the following with the D-List
function list_simple_search()

	array_element = list_simple_search(json_object, "IMDB");
	if ((array_element) && (array_element->value_type == JSON_double)) { 
		fprintf(stdout, "Search #1 for IMDB found %Lf.\n", array_element->value.double_number);
	} else {
		fprintf(stdout, "Search for IMDB failed, or found the wrong thing !!!\n");
	}

which will produce this output
	Search #1 for IMDB found 9.200000.


that D-List function will only search the list_object that was presented to it.
However the following JSON Support Function will search the entire tree underneath
the starting point, which is defined by the list_object presented.

	json_member_list_t *search_result;

	ret = json_find_member_value(&search_result, json_object, "IMDB", FALSE, NULL, FALSE);
	if (ret < 0) {
		fprintf(stdout, "Search for IMDB failed !!!\n");
	} else {
		if ((ret > 0) && (search_result.value_type == JSON_double)) {
			fprintf(stdout, "Search #2 for IMDB found %Lf.\n", search_result.json_member->value.double_number);
		} else {
			fprintf(stdout, "Search for IMDB found the wrong thing !!!\n");
		}
	}

which will produce this output
	Search #2 for IMDB found 9.200000.

That example had the same effect as using D-List, however the following example would
have required much more D-List code to perform, as the Member name being searched for
is inside a JSON Object below the top level.
	
	ret = json_find_member_value(&search_result, json_object, "Tate", FALSE, NULL, FALSE);
	if (ret < 0) {
		fprintf(stdout, "Search for Tate failed !!!\n");
	} else {
		if ((ret > 0) && (search_result.value_type == JSON_string)) {
			fprintf(stdout, "Search for Tate found %d matches, first one is -> %s: %s\n", 
					ret, search_result.json_member->member_name, search_result.json_member->value.string);
		} else {
			fprintf(stdout, "Search for Tate found the wrong thing !!!\n");
		}
	}

which will produce this output
	Search for Tate found 1 matches, first one is -> "Tate": "London"

not only did you find the Object Member, but you now have the list_object you need
to examine the other elements within this lower level JSON Object. This code will
perform the display of all those Object Members

	list_iteration_start(search_result.json_owner_object, TAIL_OF_LIST);
	fprintf(stdout, "The contents of the JSON Object are :\n{\n");
	while (list_iteration_has_more(search_result.json_owner_object)) {
		array_element = list_iteration_get_next(search_result.json_owner_object, NULL);
		fprintf(stdout, "\t\"%s\": \"%s\"%s\n", 
				array_element->member_name, 
				array_element->value.string, 
				(list_iteration_has_more(search_result.json_owner_object)) ? "," : "");
	}
	list_iteration_stop(search_result.json_owner_object);
	fprintf(stdout, "}\n"); 

which will produce this output
	The contents of the JSON Object are :
	{
		"Louvre": "Paris",
		"Tate": "London",
		"MOMA": "New York",
		"Getty": "Santa Monica"
	}

Finding the path of a JSON Object
---------------------------------

The last json_find_ function we used only returns 1 match, although it does tell you
how many matches it did find. The following function json_find_members_value_string()
is the more normal version as it returns all the matches from the search, but it takes
a little more work to get the results. Instead of a single record, you get a list of
records that you can do with as you want. And this time we will print the path to the
Object Member we searched for.

	list_object *search_result_list;
	json_member_list_t *search_match;

	/* This time use the normal JSON Member search that returns all results in a list */
	search_result_list = json_find_members_value_string(json_object, "Tate", FALSE, NULL, FALSE);
	if (! list_is_empty(search_result_list)) {
		/* get the first match */
		search_match = list_get_index(search_result_list, 0);
		/* display the JSON path to the found Member */
		json_object_buffer = json_generate_path_from_links(search_match->path, search_match->path_segments);
		fprintf(stdout, "Search for Tate found it with the JSON Path -> %s\n", json_object_buffer);
		list_erase(search_result_list);
	}

which will produce this output
	Search for Tate found it with the JSON Path -> museums.Tate

Find a value in a JSON Array
----------------------------

To search a JSON Array of values, you must first access the Array and then search it.
So for example, you want to see if 1998 and 2000 are present in the Array "films".
When the Array list_object was created, a general purpose search function was attached
to it. We will not make use of that with a D-List function

	json_element_t search_criteria;

	array_element = list_simple_search(json_object, "films");
	if ((array_element) && (array_element->value_type == JSON_array)) {
		/* tell the search what you are looking for */
		search_criteria.value_type = JSON_integer;
		search_criteria.value.integer = 1998;
		if (list_simple_search(array_element->value.object, &search_criteria)) 
			fprintf(stdout, "1998 was found in the Array.\n");
		search_criteria.value.integer = 2000;
		if (list_simple_search(array_element->value.object, &search_criteria) == NULL) 
			fprintf(stdout, "2000 was NOT found in the Array, which is correct.\n");
	} else {
		fprintf(stdout, "Search for films failed, or found the wrong thing !!!\n");
	}

which will produce this output
	1998 was found in the Array.
	2000 was NOT found in the Array, which is correct.

You can scroll through an array in the same way we went through a JSON Object earlier,
using a list_iteration sequence. So, continuing from the example above:

	json_element_t *temp_element;

	list_iteration_start(array_element->value.object, TAIL_OF_LIST);
	fprintf(stdout, "The contents of the JSON Array are -> films: [ ");
	while (list_iteration_has_more(array_element->value.object)) {
		temp_element = list_iteration_get_next(array_element->value.object, NULL);
		fprintf(stdout, "%Ld%s", 
				temp_element->value.integer, 
				(list_iteration_has_more(array_element->value.object)) ? ", " : " ");
	}
	list_iteration_stop(array_element->value.object);
	fprintf(stdout, "]\n"); 

which will produce this output
	The contents of the JSON Array are -> films: [ 1988, 1992, 1998, 2002, 2008, 2014, 2022 ]

There are other methods available in D-List to go through list elements, but
list iteration is the simplest to illustrate here.

Find JSON Object Member using a JSON dotted path notation
---------------------------------------------------------

Perhaps you are getting requests from a JavaScript module, or a user input, and 
need to locate a Member from a dotted path. Here is an example of how to do that.

	json_member_list_t *parsed_result;
	parsed_result = json_parse_dotted_path("museums.Getty");
	if (! parsed_result) {
		fprintf(stdout, "%s() error Path parsing failed.\n", __func__);
	} else {
		if (json_path_locate(json_object, parsed_result, TRUE, FALSE) == NULL) {
			fprintf(stdout, "%s() error could not find Path (museums.Getty).\n", __func__);
		} else {
			fprintf(stdout, "Found (museums.Getty) %s: %s.\n", parsed_result->json_member->member_name,  parsed_result->json_member->value.string);
		}
		if (parsed_result) free(parsed_result);
	}

which will produce this output
	Found (museums.Getty) Getty: Santa Monica.

and locating a value in an array using the same code.

	parsed_result = json_parse_dotted_path("cities[2]");
	if (! parsed_result) {
		fprintf(stdout, "%s() error Path parsing failed.\n", __func__);
	} else {
		if (json_path_locate(json_object, parsed_result, TRUE, FALSE) == NULL) {
			fprintf(stdout, "%s() error could not find Path (museums.Getty).\n", __func__);
		} else {
			fprintf(stdout, "Found (cities[2]) [ %s ].\n",  parsed_result->json_member->value.string);

			/* Now display the entire contents of the array we found */
			list_iteration_start(parsed_result->json_owner_object, TAIL_OF_LIST);
			fprintf(stdout, "The contents of the JSON Array are -> cities: [ ");
			while (list_iteration_has_more(parsed_result->json_owner_object)) {
				temp_element = list_iteration_get_next(parsed_result->json_owner_object, NULL);
				fprintf(stdout, "\"%s\"%s", 
						temp_element->value.string, 
						(list_iteration_has_more(parsed_result->json_owner_object)) ? ", " : " ");
			}
			list_iteration_stop(parsed_result->json_owner_object);
			fprintf(stdout, "]\n"); 
(a)-->
		}
		if (parsed_result) free(parsed_result);
	}

which will produce this output
	Found (cities[2]) [ New York ].

and the list iteration of the parsed result will produce this output
	The contents of the JSON Array are -> cities: [ "Paris", "London", "New York", "Santa Monica" ]

once you have found a JSON Object, an Object Member or an Array value, you are 
provided with everything you need to continue to process the JSON data from that
point in the data hierarchy. This includes an element_reference to the JSON element
found. element references are an opaque identifier used by D-List to allow users
to easily access a known element, regardless of the change in state of the list it
belongs to, for example if elements are added in random places the indexes of the
elements would change, and therefore keeping an index number would be pointless. 
The same would hold true if the list was sorted or rearranged in some way. However
an element reference follows the elements no matter what, until the element is 
removed from the list.

So for example, you can insert the following code into (a) above

			/* you can also manipulate the found element using its element_reference 
				that was returned by json_path_locate() */
			temp_element = list_get_ref(parsed_result->json_owner_object, parsed_result->reference);
			fprintf(stdout, "Found by reference (cities[2]) [ %s ].\n",  temp_element->value.string);
			/* you can use the reference for many uses, without 
				having to search first the get the element */
			list_delete_ref(parsed_result->json_owner_object, &parsed_result->reference);
			/* the data in parsed_result is now useless as the element has been deleted */

			/* Now display the contents of the array we found, minus that element */
			list_iteration_start(parsed_result->json_owner_object, TAIL_OF_LIST);
			fprintf(stdout, "The contents of the JSON Array are -> cities: [ ");
			while (list_iteration_has_more(parsed_result->json_owner_object)) {
				temp_element = list_iteration_get_next(parsed_result->json_owner_object, NULL);
				fprintf(stdout, "\"%s\"%s", 
						temp_element->value.string, 
						(list_iteration_has_more(parsed_result->json_owner_object)) ? ", " : " ");
			}
			list_iteration_stop(parsed_result->json_owner_object);
			fprintf(stdout, "]\n");

which will produce this output
	Found by reference (cities[2]) [ New York ].
	The contents of the JSON Array are -> cities: [ "Paris", "London", "Santa Monica" ]

and the root JSON data structure looks like:
{
  "Hayao": 72, 
  "Miyazaki": "Director", 
  "IMDB": 9.200000, 
  "IMDB active": true, 
  "Showing in SF": null, 
  "films": [ 1988, 1992, 1998, 2002, 2008, 2014, 2022
  ], 
  "museums": 
  {
    "Louvre": "Paris", 
    "Tate": "London", 
    "MOMA": "New York", 
    "Getty": "Santa Monica"
  }, 
  "cities": [ "Paris", "London", "Santa Monica" ]
}

Element references are very useful, and have a number of D-List functions that
operate with them. Please refer to the D-List documentation for more information.

Adding an Object Member using JSON Dotted Path instead of list_object
---------------------------------------------------------------------

Although from a strictly programatic point of view it is far quicker and faster
to use the list_object interfaces to navigate a JSON data block, and find or 
manipulate their contents, there are times when you will have to deal with JSON
dotted paths instead, particularly if you are writing users interface code, or
a module to interface with JavaScript or a web server. 

Below are 2 methods for adding a JSON Object Member to an Object, first using 
the functions already covered above, and then with a simpler interface, that is
useful to reduce your code, or deal with ad-hoc needs.

First this sequence of code will add a new Object Member to museums, using the 
functions described in the examples above. It is a simple flow, but can get
tedious if repeated a lot.

	parsed_result = json_parse_dotted_path("museums");
	if (! parsed_result) {
		fprintf(stdout, "%s() error Path parsing failed.\n", __func__);
	} else {
		if (json_path_locate(json_object, parsed_result, TRUE, FALSE) == NULL) {
			fprintf(stdout, "%s() error could not find Path (museums.Getty).\n", __func__);
		}
		if ((parsed_result->json_member) && (parsed_result->value_type == JSON_object)) {
			museum_json_object = parsed_result->json_member->value.object;		/* if the path_locate failed, this is NULL */
		} else {
			museum_json_object = NULL;
		}
		if (parsed_result) free(parsed_result);								/* we don't need this any longer */
	}
	if (museum_json_object) {
		ret -= json_list_object_member_add_string(museum_json_object, "Musée d'Orsay", "Paris");
	}

Second is this more streamlined approach, however you will not get a pointer to the
list_object for "museums" and if you have to perform more updates to it, the first 
code method is more useful.

	/* now doing the same thing, but an easier way, however you would need to keep 
		the list_object if you wanted to do more work on that JSON Object Museums		*/
	ret -= json_list_object_member_add_string(json_path_to_list_object(json_object, "museums"), "SF MOMA", "San Francisco");
	ret -= json_list_object_array_value_add_string(json_path_to_list_object(json_object, "cities"), "San Francisco");

Unlike the more usual code sequences above there is no real error checking here,
but there is also no recovered list_object or element pointers either. Also any
errors are written to stderr, and the return value will be <0.

After running these 2 sequences of code, the example JSON data block will now
look like:

	{
	  "Hayao": 72, 
	  "Miyazaki": "Director", 
	  "IMDB": 9.200000, 
	  "IMDB active": true, 
	  "Showing in SF": null, 
	  "films": [ 1988, 1992, 1998, 2002, 2008, 2014, 2022 ], 
	  "museums": 
	  {
		"Louvre": "Paris", 
		"Tate": "London", 
		"MOMA": "New York", 
		"Getty": "Santa Monica", 
		"Musée d'Orsay": "Paris", 
		"SF MOMA": "San Francisco"
	  }, 
	  "cities": [
		"Paris", 
		"London", 
		"Santa Monica", 
		"San Francisco"
	  ]
	}

This tutorial has covered a lot of functions and most of how a developer will
most likely use or build a JSON data block. Careful reading of the rest of the
documentation, and the json-parser.h header file will help in solving other
JSON usage details. Becoming familar with D-List and how to use its extensive
list of features will also help in accessing and managing the JSON data more
easily and efficiently.

dbw.





NOTES
=====

(1)		As an aside, the JSON Support Function to call to discover what a root 
		list_object is if it passed to you with no JSON value type attached, is:
		json_report_list_object_type() which returns a JSON_value_type after 
		analyzing the list_object.

(2)		JSON Object Members are also known as a key:value pair in various other 
		environments, such as JavaScript land. Throughout this JSON Package and 
		this document in particular, we try and keep the terminology consistent 
		with the terminology used in RFC 8529 and ECMA-404 to avoid confusion.

(3)		These code snippets are not real-world, for example to add a character
		array to an element, you must also leave the character array in a memory
		location will not be deallocated while the list_object is still being used
		(i.e. prior to calling list_erase() ) this code snipper would fail as soon
		as the pretend function called return, the character array in this example
		is on the stack.
		