Cross-platform C SDK logo

Cross-platform C SDK

JSON

❮ Back
Next ❯
This page has been automatically translated using the Google Translate API services. We are working on improving texts. Thank you for your understanding and patience.

Functions

type*json_read (...)
type*json_read_str (...)
voidjson_write (...)
String*json_write_str (...)
voidjson_destroy (...)
voidjson_destopt (...)

JSON JavaScript Object Notation, is a data format in text mode that allows to easily represent basic types, objects and arrays. Although its use has become popular in the Web environment, it can also be used for other purposes, such as configuration files or local exchange. Its syntax is easy to understand for humans and simple to process for machines. In (Listing 1) we reproduce a small fragment of the JSON response of a Web service:

Listing 1: JSON fragment returned by a Web Service.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
    "code":0,
    "size":80,
    "data":[
    {
        "id":0,
        "code":"i7-8700K",
        "description":"Intel BX80684I78700K 8th Gen Core i7-8700K Processor",
        type":0,
        "price":374.89,
        "image":"cpu_00.jpg",
        "image64":"\/9j\/4AAQSkZJRgABAQ...."
    },
    {
        "id":1,
        "code":"G3930",
        "description":"Intel BX80677G3930 7th Gen Celeron Desktop Processors",
        "type":0,
        "price":51.95,
        "image":"cpu_01.jpg",
        "image64":"\/9j\/4AAQSkZJRgABAQAAAQABAAD..."
    },
    ...
    ]
}

In its structure we can find these data types:

  • Booleans: Represented by constants true or false.
  • Numbers: Use the exponential notation of C for floating-point values: 2.3, .76, -0.54 or 5.6e12 they are valid examples of numerical values. JSON does not distinguish between integers, negatives or reals.
  • Strings: Any text in quotes is considered a string. Supports any Unicode character in UTF-8 or through the escape sequence \uXXXXto indicate the codepoint.
  • Arrays: Lists of items delimited by brackets [...] and separated by commas. The values do not have to be the same type as usually happens in some programming languages (Listing 2).
  • Listing 2: JSON array
    1
    2
    3
    
    [
        "Red", "Green", "Blue", "Yellow"
    ]
    
  • Objects: They are delimited by keys and composed of several fields separated by commas. Each field is formed by an identifier (string) followed by a colon and a value that can be any simple type, object or array (Listing 3).
  • Listing 3: JSON object
    1
    2
    3
    4
    5
    6
    7
    
    {
        "field1" : true,
        "field2" : 24.67,
        "field3" : "Hello Pibe",
        "field4" : [1, 2, 4, 8.4],
        "field5" : { "x" : 34.32, "y" : -6.19 }
    }
    
  • null: Indicates the absence of value.
  • Binaries: JSON does not support binary data so opaque objects (images, for example) must be encoded in text and transmitted as a string type value. The most widespread and globally supported format is the Base64 where each character represents 6 bits of information.
NAppGUI's JSON parser automatically transforms Image objects to Base64 and viceversa, allowing images to be embedded as data fields.

1. JSON parsing and conversion to data in C

NAppGUI allows automatic parsing of Json information.

Next we will show different examples with basic types, arrays and objects. In Read/Write Json you have the complete code. The first step is to create a Stream with the content of the Json (Listing 4):

Listing 4: Create a Stream with Json data.
1
2
3
4
5
6
7
8
9
/* Json data from web service */
Stream *stm = http_dget("http://serv.nappgui.com/dproducts.php", NULL, NULL);

/* Json data from disk file */
Stream *stm = hfile_stream("/home/fran/appdata/products.json", NULL);

/* Json data from memory block */
const char_t *data = "[12, 34, 67, 45]";
Stream *stm = stm_from_block((const byte_t*)data, str_len_c(data));
The Stream should be destroyed with stm_close at the end of the analysis.

Later we will use json_read indicating the expected data type of the Json.

Listing 5: Json boolean.
1
2
3
4
5
json: true

bool_t *json = json_read(stm, NULL, bool_t);
bstd_printf("Json boolean: %d\n", *json);
json_destroy(&json, bool_t);
Listing 6: Json number.
1
2
3
4
5
json: 6654

uint16_t *json = json_read(stm, NULL, uint16_t);
bstd_printf("Json unsigned int: %d\n", *json);
json_destroy(&json, uint16_t);
Listing 7: Json string.
1
2
3
4
5
json: "Hello World"

String *json = json_read(stm, NULL, String);
bstd_printf("Json string: %s\n", tc(json));
json_destroy(&json, String);
Listing 8: Json string/b64 image (jpg, png, bmp).
1
2
3
4
5
6
7
json: "/9j/4QB4RXhpZgAASUkqAAgAAA..."

Image *json = json_read(stm, NULL, Image);
uint32_t width = image_width(json);
uint32_t height = image_height(json);
bstd_printf("Json image: width: %d height: %d\n", width, height);
json_destroy(&json, Image);
Listing 9: Json integer array
1
2
3
4
5
6
7
8
9
json: [ -321, 12, -8943, 228, -220, 347 ]

ArrSt(int16_t) *json = json_read(stm, NULL, ArrSt(int16_t));
bstd_printf("Json array: ");
arrst_foreach(id, json, int16_t)
    bstd_printf("%d ", *id);
arrst_end()
bstd_printf("\n");
json_destroy(&json, ArrSt(int16_t));
Listing 10: Json string array
1
2
3
4
5
6
7
8
9
json: [ "Red", "Green", "Blue", "Yellow", "Orange" ]

ArrPt(String) *json = json_read(stm, NULL, ArrPt(String));
bstd_printf("Json array: ");
arrpt_foreach(str, json, String)
    bstd_printf("%s ", tc(str));
arrpt_end()
bstd_printf("\n");
json_destroy(&json, ArrPt(String));

For the analysis of objects it is necessary that we register with Data binding their structure, in such a way that the types and names of the fields of the Json object coincide with the struct from C. Given this Json:

Listing 11: Json object
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
    "size" : 3,
    "data" : [
        {
            "description" : "Intel i7-7700K",
            "price" : 329.99
        },
        {
            "description" : "Ryzen-5-1600",
            "price" : 194.99
        },
        {
            "description" : "GTX-1060",
            "price" : 449.99
        }
    ]
}

We define these structs and register them:

Listing 12: Structures that will hold the data of the Json object.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
typedef struct _product_t Product;
typedef struct _products_t Products;

struct _product_t
{
    String *description;
    real32_t price;
};

struct _products_t
{
    uint32_t size;
    ArrSt(Product) *data;
};

DeclSt(Product);

dbind(Product, String*, description);
dbind(Product, real32_t, price);
dbind(Products, uint32_t, size);
dbind(Products, ArrSt(Product)*, data);

This way we can now call json_read:

Listing 13: Reading the Json object.
1
2
3
4
5
6
7
Products *json = json_read(stm, NULL, Products);
bstd_printf("Json object: Size %d\n", json->size);
arrst_foreach(elem, json->data, Product)
    bstd_printf("Product: %s Price %.2f\n", tc(elem->description), elem->price);
arrst_end()
bstd_printf("\n");
json_destroy(&json, Products);
json_read() ignores (skips) those fields of Json objects that are not registered with dbind. In no case will they generate caches or dynamic memory.

2. Mapping between Json and C

json_read recognizes the basic NAppGUI types, as well as String, Image, ArrSt, and ArrPt. Will not work with other data types such as int or float. It will also not recognize the STL structures vector, map, etc. In (Table 1) we show the equivalence between the fields of a Json and the C types that we need to map it correctly.

Table 1: Equivalence between Json and NAppGUI types.
Json C
boolean bool_t true, false
number int8_t, int16_t, int32_t, int64_t -6785, 45, 0
number uint8_t, uint16_t, uint32_t, uint64_t 1, 36734, 255, 0, 14
number real32_t, real64_t 67.554, -3.456, 1.5e7
string String "Intel Celeron", "Red"
string Image "/9j/4QB4RXhpZgAASUkqAAgAAA..."
array ArrSt(uint16_t) [ 12, 111, 865 ]
array ArrSt(real32_t) [ -34.89, 0.0001, 567.45, 1e6 ]
array ArrPt(String) [ "red", "green", "blue" ]
array ArrPt(Image) [ "/9j/4QB4RXh...", "/9j/4QB4RXh...", ... ]
object struct Product (Data binding) { "description" : "i7-8700K", " "price" : 234.54 }
array ArrSt(Product) [ { "description" : "i7-8700K", " "price" : 234.54 }, ... ]
array ArrPt(Product) [ { "description" : "i7-8700K", " "price" : 234.54 }, ... ]

3. Convert from C to JSON

  • Use json_write to write data/objects from C to Json.

Based again on (Table 1), let's do the reverse process and generate Json data from C types and objects. First, create a write stream to hold the result (Listing 14):

Listing 14: Create a write Stream.
1
2
3
4
5
/* Write stream in memory */
Stream *stm = stm_memory(2048);

/* Write stream in disk */
Stream *stm = stm_to_file("/home/fran/appdata/products.json", NULL);
The Stream should be destroyed with stm_close when it is no longer needed.

Later we will use json_write indicating the expected data type of the Json.

Listing 15: Write boolean to Json.
1
2
3
4
5
bool_t data_bool = TRUE;
stm_writef(stm, "Json from bool_t: ");
json_write(stm, &data_bool, NULL, bool_t);

// Json from bool_t: true
Listing 16: Write integer to Json.
1
2
3
4
5
uint16_t data_uint = 6654;
stm_writef(stm, "Json from uint16_t: ");
json_write(stm, &data_uint, NULL, uint16_t);

// Json from uint16_t: 6654
Listing 17: Write String to Json.
1
2
3
4
5
6
String *data_str = str_c("Hello World");
stm_writef(stm, "Json from String: ");
json_write(stm, data_str, NULL, String);
str_destroy(&data_str);

// Json from String: "Hello World"
Listing 18: Write Image to Json.
1
2
3
4
5
6
Image *data_image = load_image();
stm_writef(stm, "Json from Image: ");
json_write(stm, data_image, NULL, Image);
image_destroy(&data_image);

// Json from Image: "iVBORw0KGgoAAAANSUhEUgAAAAIA..."
Listing 19: Write ArrSt(int16_t) to Json.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
ArrSt(int16_t) *array = arrst_create(int16_t);
arrst_append(array, -321, int16_t);
arrst_append(array, 12, int16_t);
arrst_append(array, -8943, int16_t);
arrst_append(array, 228, int16_t);
arrst_append(array, -220, int16_t);
arrst_append(array, 347, int16_t);
stm_writef(stm, "Json from int array: ");
json_write(stm, array, NULL, ArrSt(int16_t));
arrst_destroy(&array, NULL, int16_t);

// Json from int array: [ -321, 12, -8943, 228, -220, 347 ]
Listing 20: Write ArrPt(String) to Json.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
ArrPt(String) *array = arrpt_create(String);
arrpt_append(array, str_c("Red"), String);
arrpt_append(array, str_c("Green"), String);
arrpt_append(array, str_c("Blue"), String);
arrpt_append(array, str_c("Yellow"), String);
arrpt_append(array, str_c("Orange"), String);
stm_writef(stm, "Json from string array: ");
json_write(stm, array, NULL, ArrPt(String));
arrpt_destroy(&array, str_destroy, String);

// Json from string array: [ "Red", "Green", "Blue", "Yellow", "Orange" ]
Listing 21: Write Products object to Json.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Products *products = heap_new(Products);
products->size = 3;
products->data = arrst_create(Product);

{
    Product *product = arrst_new(products->data, Product);
    product->description = str_c("Intel i7-7700K");
    product->price = 329.99f;
}

{
    Product *product = arrst_new(products->data, Product);
    product->description = str_c("Ryzen-5-1600");
    product->price = 194.99f;
}

{
    Product *product = arrst_new(products->data, Product);
    product->description = str_c("GTX-1060");
    product->price = 449.99f;
}

stm_writef(stm, "Json from object: ");
json_write(stm, products, NULL, Products);
dbind_destroy(&products, Products);

// Json from object: {"size" : 3, "data" : [ {"description" : "Intel i7-7700K", "price" : 329.989990 }, {"description" : "Ryzen-5-1600", "price" : 194.990005 }, {"description" : "GTX-1060", "price" : 449.989990 } ] }
❮ Back
Next ❯

json_read ()

Parse a JSON script. It will transform JSON text into a type or object in C.

type*
json_read(Stream *stm,
          const JsonOpts *opts,
          type);
stm

Data entry in JSON format.

opts

Options.

type

Type of data.

Return

Result object.

Remarks

See JSON parsing and conversion to data in C.


json_read_str ()

Same as json_read, but accepting JSON code from a character string.

type*
json_read_str(const char_t *str,
              const JsonOpts *opts,
              type);
str

Text string in JSON format, terminated with a null character '\0'.

opts

Options.

type

Type of data.

Return

Result object.

Remarks

See JSON parsing and conversion to data in C.


json_write ()

Write data in C to JSON format.

void
json_write(Stream *stm,
           type *data,
           const JsonOpts *opts,
           type);
stm

Data output in JSON format.

data

Object.

opts

Options.

type

Type of data.

Remarks

See Convert from C to JSON.


json_write_str ()

Same as json_write, but returning the result in a String.

String*
json_write_str(type *data,
               const JsonOpts *opts,
               type);
data

Object.

opts

Options.

type

Type of data.

Return

Text string in JSON format.

Remarks

See Convert from C to JSON.


json_destroy ()

Destroys a JSON object, previously created with json_read .

void
json_destroy(type **data,
             type);
data

Object.

type

Type of data.


json_destopt ()

Destroys a JSON object, previously created with json_read, if it is not NULL.

void
json_destopt(type **data,
             type);
data

Object.

type

Type of data.

❮ Back
Next ❯