ibireme / yyjson

The fastest JSON library in C
https://ibireme.github.io/yyjson/doc/doxygen/html/
MIT License
3.07k stars 267 forks source link

How to edit sub-object #125

Closed slidertom closed 1 year ago

slidertom commented 1 year ago

Hi, const char *json = "{\"name\":\"Mash\",\"star\":4,\"hits\":[2,2,1,3], \"color\":{ \"m_nID\": 64, \"m_nRGB\": 16316664}}"; I want to extend color object. It seems that "color" requires a document not value to be edited.

yyjson_doc doc = yyjson_read(json, strlen(json), 0); yyjson_val root = yyjson_doc_get_root(doc);

yyjson_mut_doc mut_doc = yyjson_doc_mut_copy(doc, NULL); yyjson_mut_val mut_root = yyjson_mut_doc_get_root(mut_doc);

yyjson_val color = yyjson_obj_get(root, "color"); yyjson_val id = yyjson_obj_get(color, "m_nID"); unsafe_yyjson_set_sint(id, 50); // this is works and OK

int hits_arr[] = {2, 2, 1, 3}; yyjson_mut_val hits2 = yyjson_mut_arr_with_sint32(mut_doc, hits_arr, 4); yyjson_mut_val mut_color = ::yyjson_val_mut_copy(mut_doc, color); yyjson_mut_obj_add_val(mut_doc, mut_color, "hits2", hits2); // here I get fail ! "hits2" is not added const char json2 = yyjson_mut_write(mut_doc, 0, NULL); if (json2) { printf("json: %s\n", json2); free((void )json2); }

yyjson_doc_free(doc);
yyjson_mut_doc_free(mut_doc);

I'm missing something... Can anybody provide any hint?

slidertom commented 1 year ago

Hi, I've found a way with additional temporal document - looks like quite logical solution.

yyjson_mut_val mut_color = ::yyjson_val_mut_copy(mut_doc, color); yyjson_mut_doc color_doc = yyjson_mut_doc_new(NULL); yyjson_mut_doc_set_root(color_doc, mut_color);

int hits_arr[] = {2, 2, 1, 3}; yyjson_mut_val *hits2 = yyjson_mut_arr_with_sint32(mut_doc, hits_arr, 4); // it's not mut_color doc! is it OK? yyjson_mut_obj_add_val(color_doc, mut_color, "hits2", hits2);

yyjson_mut_obj_remove_key(mut_root, "color"); // Failed to find better solution currently to update document object yyjson_mut_obj_add_val(mut_doc, mut_root, "color", mut_color); // do set object again

const char json2 = yyjson_mut_write(mut_doc, 0, NULL); if (json2) { printf("json: %s\n", json2); free((void )json2); }

// Free the doc
yyjson_mut_doc_set_root(color_doc, NULL);
yyjson_mut_doc_free(color_doc);

yyjson_doc_free(doc);
yyjson_mut_doc_free(mut_doc);

Here is multiple actions are done which could be avoided: yyjson_mut_obj_remove_key, yyjson_mut_obj_add_val Is it any other better approach to achieve sub object modifications?

ibireme commented 1 year ago

You just need to use mutable copy to convert doc to mut_doc, and then all operations will use this mut_doc:

const char *json = "{\"name\":\"Mash\",\"star\":4,\"hits\":[2,2,1,3],\"color\":{\"m_nID\":64,\"m_nRGB\": 16316664}}";
yyjson_doc *doc = yyjson_read(json, strlen(json), 0);

// make a mutable copy, free the immutable doc
yyjson_mut_doc *mut_doc = yyjson_doc_mut_copy(doc, NULL);
yyjson_doc_free(doc);

// create new value
int hits_arr[] = {2, 2, 1, 3};
yyjson_mut_val *hits2 = yyjson_mut_arr_with_sint32(mut_doc, hits_arr, 4);

// get the target object, add new value
yyjson_mut_val *root = yyjson_mut_doc_get_root(mut_doc);
yyjson_mut_val *color = yyjson_mut_obj_get(root, "color");
yyjson_mut_obj_add_val(mut_doc, color, "hits2", hits2);

// print
const char *json2 = yyjson_mut_write(mut_doc, 0, NULL);
if (json2) {
    printf("json: %s\n", json2);
    free((void *)json2);
}

// free mut_doc
yyjson_mut_doc_free(mut_doc);
slidertom commented 1 year ago

Thank you! It works!