Extract different set of keys for different nesting level of json - c

I have the following JSON object, from which I need to retrieve values of certain keys.
For example, in outer JSON object, I need only "timestamp" and "type", next from a nested "meta" object I need only "version", and from nested "payload" I want fields "reason", "type" and "condition" from its nested object "data"
{
"timestamp": "1568961295627",
"type": "test",
"namespace": "internal",
"meta": {
"version": "2.0-test",
"id": "123"
},
"payload": {
"data": {
"reason": "user_request",
"type": "asd",
"condition": "bad"
},
"contentType": "application/json"
}
}
I wrote a function to retrieve such data:
void log_values(json_t *data) {
json_t *obj = NULL;
json_t *nested = NULL;
syslog(LOG_INFO, "%s: ", json_string_value(json_object_get(data, "timestamp")));
syslog(LOG_INFO, "%s: ", json_string_value(json_object_get(data, "type")));
obj = json_object_get(data, "meta");
syslog(LOG_INFO, "%s: ", json_string_value(json_object_get(obj, "version")));
obj = json_object_get(data, "payload");
nested = json_object_get(obj, "data");
syslog(LOG_INFO, "%s: ", json_string_value(json_object_get(nested, "reson")));
syslog(LOG_INFO, "%s: ", json_string_value(json_object_get(nested, "type")));
syslog(LOG_INFO, "%s: ", json_string_value(json_object_get(nested, "condition")));
}
However, the code looks repetitive and I'm wondering if there is any way to generalize it?
The first thing which came to mind is to create a jagged array of pointers to keys needed for each stage, and then walk through the array and retrieve only certain keys on certain nesting level, for example:
char *nested0 = {"timestamp", "type"};
char *nested1 = {"anomaly", "version"};
char *nested2 = {"reason", "type", "condition"};
char *(*keys[])[] = { &nested0, &nested1, &nested2 }
But, this solution does not solve problem regarding where to store key names, which point to nested JSONs (e.g "meta, payload, data").
So, the question is: How to generalize the aforementioned code and what data structure should I use to store names of keys holding a json object and keys for which I need to get values.

Take a look at jsmn, it should fit your needs : https://github.com/zserge/jsmn
exemple of what you could do with jsmn :
[user#machine ~]$ ./json_parser_with_keys test.json timestamp type meta/version
timestamp=1568961295627
type=test
meta/version=2.0-test
[user#machine ~]$ ./json_parser_full test.json
/timestamp=1568961295627
/type=test
/namespace=internal
/meta/version=2.0-test
/meta/id=123
/payload/data/reason=user_request
/payload/data/type=asd
/payload/data/condition=bad
/payload/contentType=application/json
[user#machine ~]$

Related

flutter get json array

Hi I have this JSON as a string as a response for an API call
{
"friends": {
"data": [],
"summary": {
"total_count": 42
}
},
"id": "111111111111111"
}
I want to get friends.data and friends.summary.total_count.
Something like :
for (int i = 0 ; i < friends.summary.total_count ; i++)
{
myAmazingArray.pushback(friends.data[i]);
}
I think that total_count is the number of contents in the array.
I also know that in order to get the "id" I have to do : json['name']
You need to use jsonDecode from dart:convert. Actually you don't even need to use the total_count value at all, if the length in data is the same. You can simply use:
import 'dart:convert';
final Map<String, dynamic> dataMap = jsonDecode(json);
final List<dynamic> friendsData = dataMap['friends']['data'];
for(dynamic friend in friendsData) myAmazingArray.pushback(friend);
I don't know what kind of content is contained in data, so I suggest you to find out the runtime type (e.g. String, Map etc.) and exchange the word 'dynamic' in my code above to improve the code quality.
If you wanted to do it with total_count:
final int total_count = dataMap['friends']['summary']['total_count'];
for(int i=0; i<total_count; i++)
myAmazingArray.pushback(friendsData[i]);

Unmarshal JSON Array in Go

I've read a few answers here and none seem to help. I keep getting the same error:
json: cannot unmarshal array into Go value of type A
type A struct {
Arr []string
}
type MA []A
func UnmarshalJSON() (ma MA, err error) {
jsonFile, err := os.Open(aJsonFile)
// error handling
defer jsonFile.Close()
byteValue, _ := ioutil.ReadAll(jsonFile)
err = json.Unmarshal(byteValue, &ma)
if err != nil {
return ma, err
}
return ma, nil
}
The json looks like this:
[
["Name", "Another Name", "Another"],
["A", "B"],
["W", "X", "Y", "Z"],
["Foo", "Bar"]
]
I've tried various different things from top answers when searching and as previously stated, nothing has worked.
I'm still decently new to Go and having to unmarshall stuff (I'm currently unmarshalling to [][]string but I want to use structs). What am I doing wrong?
A struct has fields; fields have names; the name of the field in your struct is Arr. So the json input would need to be [{ "arr": ["list", "of", "names"]}, {"arr": ["more", "names"]}] for instance, given the example you have above.
You can, however, define an UnmarshalJSON on your type named A, like this:
func (p *A) UnmarshalJSON(data []byte) error {
var s []string
err := json.Unmarshal(data, &s)
if err != nil {
return err
}
p.Arr = s
return nil
}
This receiver function named UnmarshalJSON takes a pointer to an A object, plus some sort of valid json input. Its job is to unmarshal that json. In this case we attempt to unmarshal into an ordinary slice-of-string—the variable s—which works as long as the json itself is a valid initializer for slice-of-strings.
If the unmarshal succeeds we then set p.Arr, knowing that the array is meant just for the thing named Arr (which is in fact the only member of the structure type) and return nil (no error).
Note that the last few lines could be written as:
if err == nil {
p.Arr = s
}
return err
which is shorter, but Go conventions generally handle the error case first, rather than letting it flow through. (I actually prefer the shorter code myself, slightly, but use whatever your group likes.)
(Given an UnmarshalJSON receiver on the type, there probably should be a json marshaler on the type, too, but my minimal test-and-example on the Go playground does not have one.)
your json content should like this
[
{
"Arr": [
"a0",
"a1"
]
},
{
"Arr": [
"b0",
"b1"
]
},
{
"Arr": [
"c0",
"c1"
]
}
]

Correct structure for json unmarshal

I can't figure out how to build a structure for this json object in golang:
{
"response": [1702487, {
"uid": 150261846,
"first_name": "Олег",
"last_name": "Брейн"
}, {
"uid": 53260546,
"first_name": "Олег",
"last_name": "Лобацевич"
}
]
}
As you can see there is no keys names for array and for count too.
Would be glad if you can help
In this situation you'll have to punt and use interface{} somewhere, for example:
package main
import (
"fmt"
"encoding/json"
)
type JsObject struct {
Response []interface{}
}
func main() {
bs := []byte(`{"response":[1702487,{"uid":150261846,"first_name":"Олег","last_name":"Брейн"},{"uid":53260546,"first_name":"Олег","last_name":"Лобацевич"}]}`)
var jso JsObject
json.Unmarshal(bs, &jso)
fmt.Printf("%+v\n", jso)
}
Json to go is quite handy for this sort of thing:
https://mholt.github.io/json-to-go/
If you can remove the spurious 1702487 which makes this a heterogenous list, you should be able to parse it easily into a proper structure, otherwise you might be stuck using interface:
https://play.golang.org/p/w7ebLTuOj9
Presumably you want an array of structs like this:
type Person struct {
UID int `json:"uid"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
}
not sure what 1702487 is but if uid of request, it doesn't really belong in the array.
type AutoGenerated struct {
Response []interface{} `json:"response"`
}

Adding Unique Elements to a Json Object using C

Using (learning) c to create a mini packet sniffer which adds the src IPs to a json object and adds them to a json array.
The pcap filter works without issue, and now I'm trying to create a json object of the src ips and a counter of packets sent to this IP.
{
"ips": [
{
"ip": "1.2.3.4",
"count": 10
},
{
"ip": "4.3.2.1",
"count": 103
}
]
}
Excluding all the pcap code, I have a loop as so:
pcap_loop(pcap, 1000, ethernet_packet, NULL);
Within the ethernet_packet function, I created an array for the IPs so I could check if one had already been added.
if (!array_contains(buf, src_ip)) {
// Do things
}
int array_contains(char *array, char *ip ) {
if ( strchr(array, *ip) )
return 1;
}
Here's what I have so far which was supposed to get the IP and add to the array:
void ethernet_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
static int count = 1;
printf("\nPacket number %d:\n", count); */
count++;
struct json_object *obj1, *obj2, *array;
array = json_object_new_array();
obj1 = json_object_new_object();
char buf[MESSAGE_BUFF_LEN];
/* Some Pcap stuff to get the ips etc. */
src_ip = inet_ntoa(ip->ip_src);
if (!array_contains(buf, src_ip)) {
/* Add IP to array */
sprintf(buf, src_ip);
/* Create a new object */
obj2 = json_object_new_object();
json_object *jstring = json_object_new_string(src_ip);
json_object_object_add(obj2,"ip", jstring);
/* Add to array */
json_object_array_add(array,obj2);
}
}
The problem I have is that the object isn't added to an existing array, it creates a new one each time.
The json object created: [ { "ip": "79.65.10.0" } ]
The json object created: [ { "ip": "80.152.10.0" } ]
The json object created: [ { "ip": "99.211.10.0" } ]
I even tried checking the type of object at the start of the loop and only initialising when it was not an array but that threw an error when trying to add.
It's probably obvious to someone who's spent more than 2 days with c but I don't understand how to fix this.
What's the best / most efficient way to solve this?
--- EDIT ---
Have it working by checking the type and initialising if it's not an array. Just not sure this is the best way to do so.
Full code for the fn is here:
https://gist.github.com/simonmorley/9850f2a42453e4f54b75
This is wrong
char buf[MESSAGE_BUFF_LEN];
/* Some Pcap stuff to get the ips etc. */
src_ip = inet_ntoa(ip->ip_src);
if (!array_contains(buf, src_ip)) {
because buf is initialized with garbages, as it is local variable, so doing strchr on its content is not what you want.
Additionally, it seems like you are not adding the object to correct array:
/* Add to array */
json_object_array_add(res,obj2);
// ^^^

parse json arrays using cJSON library

First off, this is a very broad question, and it might come across as me asking for the community to write my code for me. That is not my intent, but I am so lost, I don't know how to give enough information.
I am attempting to use the cJSON library, written by Dave Gamble,
I found this is very useful to use for my embedded device for JSON parse and composing.
to read in the following JSON array
{
"name": "Jack",
"types":[23,56,78],
"format": {
"type": "rect",
"width": 1920, }
}
.. and parsing the getting the object worked with this method
cJSON *format = cJSON_GetObjectItem(json,"format");
int framerate = cJSON_GetObjectItem(format,"width")->valueint;
but I am not able to parse the key "name" and object simple key value ,
I tried this
cJSON *array = cJSON_GetArrayItem(json,"types");
int value = cJSON_GetArrayItem(format1,1)->valueint;
but did not work, how to parse the array object and simple key value..
Your json is just fine. You can iterate through array of values in cJSON:
cJSON * array = cJSON_GetObjectItem(json, "types");
for (i = 0 ; i < cJSON_GetArraySize(array) ; i++)
{
printf("%d ",cJSON_GetArrayItem(array, i)->valueint);
}
will print
23 56 78
I think JSON element should respect key:value format.
{
"name": "Jack",
"types":[{"type" : 23}, {"type" : 56}, {"type":78}],
"format": {
"type": "rect",
"width": 1920, }
}

Resources