armink / struct2json

A fast convert library between the JSON and C structure. Implement structure serialization and deserialization for C. | C 结构体与 JSON 快速互转库,快速实现 C 结构体的序列化及反序列化
MIT License
680 stars 293 forks source link

结构体数组如何序列化? #8

Open zlr3538 opened 6 years ago

zlr3538 commented 6 years ago

如题,目前数组序列化只能是基本类型吗?如果数组里面是结构体这样的嵌套有没有解决办法

armink commented 6 years ago

这个功能现在确实还不支持。你有没有比较好的办法呢?

zlr3538 commented 6 years ago

我这几天绞尽脑汁,勉励改出了一个可以支持的样子,但是却完全失去了原有的样子,不仅有了start和end,而且参数的数量和位置也不再统一。 我觉得你这个封装的设计目的应该是,希望用简洁的格式,描述struct和json之间的转换关系。这也是为什么你的封装看起来不像是过程而像是一种声明。 我想到的一个办法,就是用一些声明语句,构造一个树来描述struct,那么这个如果这树和json解析的树相同,就可以用遍历的方法将他们两者进行转化。这样应该能保持简洁的描述,也可以处理json中各种情况,一次描述应该就可以实现两个方向的互转。毕竟C没有元信息,结构体和其中变量的描述,肯定要通过额外的方法再声明一遍。你看这个思路是不是可行?

armink commented 6 years ago

树的方案是可行的,就是工作量会非常大。

start 和 end 的那个方案改完是什么样子?

zlr3538 commented 6 years ago

大概是这样,可以说非常丑陋了,而且弄得很复杂,感觉也不是很靠谱

typedef struct {
    char name[16];
} Hometown;

typedef struct {
    int ranking;
    int score;
} Results;

typedef struct {
    int id;
    double weight;
    char name[10];
    int attendance [10];
    Hometown hometown;
    Results results[5];
} Student;

/**
 * Student JSON object to structure object
 *
 * @param json_obj JSON object
 *
 * @return structure object
 */
static void *json_to_struct(json_object* json_obj) {
    /* create Student structure object */
    s2j_create_struct_obj(struct_student, Student);

    /* deserialize data to Student structure object. */
    s2j_struct_get_basic_element(struct_student, json_obj, int, id);
    s2j_struct_get_basic_element(struct_student, json_obj, double, weight);
    s2j_struct_get_basic_element(struct_student, json_obj, string, name);

    {
        s2j_struct_get_struct_element_start(struct_student, json_obj, int, attendance);
        s2j_struct_get_array_element_start(CHILD_STRUCT,CHILD_ELEMENT,int);
        s2j_struct_get_array_basic_element(ARRAY_STRUCT, ARRAY_ELEMENT, int, attendance);
        s2j_struct_get_array_element_end();
        s2j_struct_get_struct_element_end();
    }

    {
    /* deserialize data to Student.Hometown structure object. */
        s2j_struct_get_struct_element_start(struct_student, json_obj, Hometown, hometown);
        s2j_struct_get_basic_element(CHILD_STRUCT, CHILD_ELEMENT, string, name);
        s2j_struct_get_struct_element_end();
    }

    {
        s2j_struct_get_struct_element_start(struct_student, json_obj, Results, results);
        s2j_struct_get_array_element_start(CHILD_STRUCT,CHILD_ELEMENT,Results);        
        s2j_struct_get_basic_element(ARRAY_STRUCT, ARRAY_ELEMENT, int ,ranking);
        s2j_struct_get_basic_element(ARRAY_STRUCT, ARRAY_ELEMENT, int ,score);
        s2j_struct_get_array_element_end();
        s2j_struct_get_struct_element_end();
    }

    /* return Student structure object pointer */
    return struct_student;
}

/**
 * Student structure object to JSON object
 *
 * @param struct_obj structure object
 *
 * @param JSON object
 */
static json_object *struct_to_json(void* struct_obj) {
    Student *struct_student = (Student *)struct_obj;

    /* create Student JSON object */
    s2j_create_json_obj(json_student);

    /* serialize data to Student JSON object. */
    s2j_json_set_basic_element(json_student, struct_student, int, id);
    s2j_json_set_basic_element(json_student, struct_student, double, weight);
    s2j_json_set_basic_element(json_student, struct_student, string, name);

    {
        s2j_json_set_array_element_start(json_student, int, 10);
        s2j_json_set_array_basic_element(ARRAY_ELEMENT, struct_student, int, attendance);
        s2j_json_set_array_element_end(json_student, attendance);
    }

    {
        /* serialize data to Student.Hometown JSON object. */
        s2j_json_set_struct_element_start(struct_student, Hometown, hometown);
        s2j_json_set_basic_element(CHILD_ELEMENT, CHILD_STRUCT, string, name);
        s2j_json_set_struct_element_end(json_student, hometown);
    }

    {
        s2j_json_set_array_element_start(json_student, Results, 5);
        s2j_json_set_array_struct_element_start(struct_student, Results, results);
        s2j_json_set_basic_element(CHILD_ELEMENT, CHILD_STRUCT, int, ranking);
        s2j_json_set_basic_element(CHILD_ELEMENT, CHILD_STRUCT, int, score);
        s2j_json_set_struct_element_end(ARRAY_ELEMENT, results);
        s2j_json_set_array_element_end(json_student, results);
    }
    /* return Student JSON object pointer */
    return json_student;
}
armink commented 6 years ago

可以把 s2j_struct_get_struct_element_start 与 s2j_struct_get_array_element_start ,以及对应的 end 合并为一个吗?

例如:s2j_struct_get_struct_array_element_start

zlr3538 commented 6 years ago

我把他们拆成两个纯粹无奈之举,展开来其实是一个循环,在循环里面遍历struct 展开是下面这个样子,我这个因为需要把cjson换成json-c,其他一样的

#define S2J_STRUCT_GET_ARRAY_ELEMENT_START(to_struct, from_json, type) \
    { \
        struct json_object *array, *array_element; \
        size_t index = 0, size = 0; \
        array = from_json; \
        if (array) { \
            size = json_object_array_length(array); \
            while (index < size) { \
                array_element = json_object_array_get_idx(array, index); \
                if (array_element) { \
                    type *array_struct = &(((type*)(to_struct))[index]);

#define S2J_STRUCT_GET_ARRAY_ELEMENT_END() \
                index++; } \
            } \
        } \
     }

#define S2J_STRUCT_GET_STRUCT_ELEMENT_START(to_struct, from_json, type, _element) \
    { \
        type *child_struct = &((to_struct)->_element); \
        struct json_object *child_element = json_object_object_get(from_json, #_element); \
        if(child_element) {

#define S2J_STRUCT_GET_STRUCT_ELEMENT_END() \
        } \
    }
EveryDayNew commented 5 years ago

以下的这个结构体数组,能否转化为json,如果能那种方法比较合适 typedef struct KR { char name[50]; char evaluation[400]; float weight; char completion[20]; float score; } kr;

typedef struct objective { char name[50]; kr KRs[3]; float score; } obj;

typedef struct OKR { char name[50]; float totalPoints; float weight[2]; obj objs[2]; } okr;

okr okrs[12];

yuxuebao commented 3 years ago

参考下面的分支,已经实现结构体和数组的转换,并提供自动生成转换代码的脚本:) https://github.com/yuxuebao/struct2json

yuxuebao commented 3 years ago

已经实现,自动生成的转换代码示例:

if 0

typedef struct McBaseOrdrS { int64 ordrNo; int64 intrlOrdrNo; int64 exePrc; int64 elstcPrc; int64 ordrQty; int64 effectTime; int32 ordSide; int32 ordrType; int32 usrSqno; int32 prdctSqno; int32 orgSqno; int32 extOrdType; int32 ordrRestr; } McBaseOrdrT, *pMcBaseOrdrT;

endif

cJSON struct_to_json_McBaseOrdrT(void struct_obj) { s2j_create_json_obj(jsonobj); McBaseOrdrT structobj = (McBaseOrdrT )struct_obj; s2j_json_set_basic_element(jsonobj, structobj, int, ordrNo); s2j_json_set_basic_element(jsonobj, structobj, int, intrlOrdrNo); s2j_json_set_basic_element(jsonobj, structobj, int, exePrc); s2j_json_set_basic_element(jsonobj, structobj, int, elstcPrc); s2j_json_set_basic_element(jsonobj, structobj, int, ordrQty); s2j_json_set_basic_element(jsonobj, structobj, int, effectTime); s2j_json_set_basic_element(jsonobj, structobj, int, ordSide); s2j_json_set_basic_element(jsonobj, structobj, int, ordrType); s2j_json_set_basic_element(jsonobj, structobj, int, usrSqno); s2j_json_set_basic_element(jsonobj, structobj, int, prdctSqno); s2j_json_set_basic_element(jsonobj, structobj, int, orgSqno); s2j_json_set_basic_element(jsonobj, structobj, int, extOrdType); s2j_json_set_basic_element(jsonobj, structobj, int, ordrRestr); return jsonobj; }

void json_to_struct_McBaseOrdrT(cJSON json_obj) { s2j_create_struct_obj(structobj, McBaseOrdrT); s2j_struct_get_basic_element(structobj,json_obj, int, ordrNo); s2j_struct_get_basic_element(structobj,json_obj, int, intrlOrdrNo); s2j_struct_get_basic_element(structobj,json_obj, int, exePrc); s2j_struct_get_basic_element(structobj,json_obj, int, elstcPrc); s2j_struct_get_basic_element(structobj,json_obj, int, ordrQty); s2j_struct_get_basic_element(structobj,json_obj, int, effectTime); s2j_struct_get_basic_element(structobj,json_obj, int, ordSide); s2j_struct_get_basic_element(structobj,json_obj, int, ordrType); s2j_struct_get_basic_element(structobj,json_obj, int, usrSqno); s2j_struct_get_basic_element(structobj,json_obj, int, prdctSqno); s2j_struct_get_basic_element(structobj,json_obj, int, orgSqno); s2j_struct_get_basic_element(structobj,json_obj, int, extOrdType); s2j_struct_get_basic_element(structobj,json_obj, int, ordrRestr); return structobj; }

if 0

typedef struct McBaseOrdrArray { McBaseOrdrT mcBaseOrdrArray[2] ; } McBaseOrdrArrayT;

endif

cJSON struct_to_json_McBaseOrdrArrayT(void struct_obj) { s2j_create_json_obj(jsonobj); McBaseOrdrArrayT structobj = (McBaseOrdrArrayT )struct_obj; s2j_json_set_struct_array_element_by_func(jsonobj, structobj, McBaseOrdrT,mcBaseOrdrArray,2); return jsonobj; }

void json_to_struct_McBaseOrdrArrayT(cJSON json_obj) { s2j_create_struct_obj(structobj, McBaseOrdrArrayT); s2j_struct_get_struct_array_element_by_func(structobj, json_obj, McBaseOrdrT,mcBaseOrdrArray); return structobj; }

armink commented 3 years ago

参考下面的分支,已经实现结构体和数组的转换,并提供自动生成转换代码的脚本:) https://github.com/yuxuebao/struct2json

Cool