In my Go code, I have multidimensional slices of string
input := [][]string{
{"foods", "food by cooking technique", "baked food"},
{"foods", "food by cooking technique", "baked beans"},
{"foods", "food by type", "dried food"},
{"drinks", "hot drinks", "tea"},
{"drinks", "hot drinks", "herbal tea"},
{"drinks", "cold drinks", "ice cream drinks"},
}
how to convert to json so that the resulting print output is as expected. maybe with recursive
{
"data": [
{
"name": "foods",
"data": [
{
"name": "food by cooking technique",
"data": [
{ "name": "baked food" },
{ "name": "baked beans" }
]
},
{
"name": "food by type",
"data": [
{ "name": "dried food" }
]
}
]
},
{
"name": "drinks",
"data": [
{
"name": "hot drinks",
"data": [
{ "name": "tea" },
{ "name": "herbal tea" }
]
},
{
"name": "cold drinks",
"data": [
{ "name": "ice cream drinks" }
]
}
]
}
]
}
still haven't come up with an idea regarding this, thanks for your help
Not fast, but an understandable approach:
package main
import (
"encoding/json"
"log"
)
type mapStruct struct {
Data map[string]*mapStruct
}
type dataStruct struct {
Name string `json:"name,omitempty"`
Data []*dataStruct `json:"data,omitempty"`
}
func main() {
input := [][]string{
{"foods", "food by cooking technique", "baked food"},
{"foods", "food by cooking technique", "baked beans"},
{"foods", "food by type", "dried food"},
{"drinks", "hot drinks", "tea"},
{"drinks", "hot drinks", "herbal tea"},
{"drinks", "cold drinks", "ice cream drinks"},
}
data := &mapStruct{}
for _, v := range input {
temp := data
for _, vv := range v {
if temp.Data == nil {
temp.Data = map[string]*mapStruct{}
}
if _, ok := temp.Data[vv]; !ok {
temp.Data[vv] = &mapStruct{}
}
temp = temp.Data[vv]
}
}
output := &dataStruct{}
fun(output, data)
bts, err := json.MarshalIndent(output, "", "\t")
if err != nil {
log.Println(err)
return
}
log.Println(string(bts))
}
func fun(d *dataStruct, m *mapStruct) {
for k, v := range m.Data {
d.Data = append(d.Data, &dataStruct{})
d.Data[len(d.Data)-1].Name = k
fun(d.Data[len(d.Data)-1], v)
}
}
Related
I'm doing a http.PostForm against an API and the result is a json.
The Json structure is like this:
{
"sites": [
{
"site_id": 456,
"status": "pending-dns-changes",
"domain": "blabla",
"account_id": 123,
"acceleration_level": "advanced",
"site_creation_date": 1515455285000,
"ips": [
"1.2.3.4"
],
"dns": [
{
"dns_record_name": "something.bla.com",
"set_type_to": "CNAME",
"set_data_to": [
"something.x.incapdns.net"
]
}
],
"original_dns": [
{
"dns_record_name": "blabla2.com",
"set_type_to": "A",
"set_data_to": [
""
]
},
{
"dns_record_name": "blabla3.something.com",
"set_type_to": "A",
"set_data_to": [
"1.2.4.5"
]
},
],
"warnings": [],
"active": "bypass",
"support_all_tls_versions": false,
"use_wildcard_san_instead_of_full_domain_san": true,
"add_naked_domain_san": true,
"additionalErrors": [],
"display_name": "something.blablabla2.com",
"security": {
"waf": {
"rules": [
{
"action": "api.threats.action.alert",
"action_text": "Alert Only",
"id": "api.threats.sql_injection",
"name": "SQL Injection"
},
{
"action": "api.threats.action.alert",
"action_text": "Alert Only",
"id": "api.threats.cross_site_scripting",
"name": "Cross Site Scripting"
},
{
"action": "api.threats.action.alert",
"action_text": "Alert Only",
"id": "api.threats.illegal_resource_access",
"name": "Illegal Resource Access"
},
{
"block_bad_bots": true,
"challenge_suspected_bots": false,
"id": "api.threats.bot_access_control",
"name": "Bot Access Control"
},
{
"activation_mode": "api.threats.ddos.activation_mode.auto",
"activation_mode_text": "Auto",
"ddos_traffic_threshold": 1000,
"id": "api.threats.ddos",
"name": "DDoS"
},
{
"action": "api.threats.action.quarantine_url",
"action_text": "Auto-Quarantine",
"exceptions": [
{
"values": [
{
"urls": [
{
"value": "/neverbogus.pvr",
"pattern": "EQUALS"
}
],
"id": "api.rule_exception_type.url",
"name": "URL"
}
],
"id": 1618746719
},
{
"values": [
{
"urls": [
{
"value": "/doubleneverbogus.pvr",
"pattern": "EQUALS"
},
{
"value": "/ddoubleneverbogus.pvr",
"pattern": "EQUALS"
}
],
"id": "api.rule_exception_type.url",
"name": "URL"
}
],
"id": 856301271
},
{
"values": [
{
"client_apps": [
"537"
],
"id": "api.rule_exception_type.client_app_id",
"name": "Client app ID"
}
],
"id": 58318563
},
{
"values": [
{
"ips": [
"192.168.66.66"
],
"id": "api.rule_exception_type.client_ip",
"name": "IP"
}
],
"id": 707083378
},
{
"values": [
{
"geo": {
"countries": [
"BF"
]
},
"id": "api.rule_exception_type.country",
"name": "Country"
}
],
"id": 1432086237
},
{
"values": [
{
"user_agents": [
"gasdfafafdfasdfadsfadsffads"
],
"id": "api.rule_exception_type.user_agent",
"name": "User agent"
}
],
"id": 1876871261
},
{
"values": [
{
"parameters": [
"bogusparamnamehere234"
],
"id": "api.rule_exception_type.http_parameter",
"name": "Http parameter"
}
],
"id": 1338747790
}
],
"id": "api.threats.backdoor",
"name": "Backdoor Protect"
},
{
"action": "api.threats.action.alert",
"action_text": "Alert Only",
"id": "api.threats.remote_file_inclusion",
"name": "Remote File Inclusion"
},
{
"action": "api.threats.action.disabled",
"action_text": "Ignore",
"id": "api.threats.customRule",
"name": "IncapRules"
}
]
}
},
"sealLocation": {
"id": "api.seal_location.none",
"name": "No seal "
},
"ssl": {
"origin_server": {
"detected": true,
"detectionStatus": "ok"
},
"custom_certificate": {
"active": false
},
"generated_certificate": {
"ca": "GS",
"validation_method": "dns",
"validation_data": [
{
"dns_record_name": "blablablasomething2",
"set_type_to": "TXT",
"set_data_to": [
"somethingtexty"
]
}
],
"san": [
"*.blabla2.com"
],
"validation_status": "done"
}
},
"siteDualFactorSettings": {
"enabled": false,
"customAreas": [],
"customAreasExceptions": [],
"allowAllUsers": true,
"shouldSuggestApplicatons": true,
"allowedMedia": [
"ga",
"sms"
],
"shouldSendLoginNotifications": true,
"version": 0
},
"login_protect": {
"enabled": false,
"specific_users_list": [],
"send_lp_notifications": true,
"allow_all_users": true,
"authentication_methods": [
"ga",
"sms"
],
"urls": [],
"url_patterns": []
},
"performance_configuration": {
"advanced_caching_rules": {
"never_cache_resources": [],
"always_cache_resources": []
},
"acceleration_level": "advanced",
"async_validation": true,
"minify_javascript": true,
"minify_css": true,
"minify_static_html": true,
"compress_jpeg": true,
"compress_jepg": true,
"progressive_image_rendering": false,
"aggressive_compression": false,
"compress_png": true,
"on_the_fly_compression": true,
"tcp_pre_pooling": true,
"comply_no_cache": false,
"comply_vary": false,
"use_shortest_caching": false,
"perfer_last_modified": false,
"prefer_last_modified": false,
"disable_client_side_caching": false,
"cache300x": false,
"cache_headers": []
},
"extended_ddos": 1000000,
"log_level": "security",
"incap_rules": [
{
"id": 51589,
"name": "Wordpress",
"action": "api.rule_action_type.rule_action_alert",
"rule": "(URL contains \"/xmlrpc.php$\" | URL contains \"/wp-login.php$\") & (User-Agent == \"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36\" | User-Agent == \"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1\")",
"creation_date": 1518810206000
},
{
"id": 52179,
"name": "No Browser",
"action": "api.rule_action_type.rule_action_alert",
"rule": "(ClientType != Browser & ClientType != SpamBot & ClientType != DDoSBot & ClientType != SiteHelper) & (User-Agent != \"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534+ (KHTML, like Gecko) BingPreview/1.0b\" & User-Agent != \"Pingdom.com_bot_version_1.4_(http://www.pingdom.com/)\")",
"creation_date": 1519432068000
}
],
"res": 0,
"res_message": "OK",
"debug_info": {
"id-info": "13019"
}
},
API Docs: https://docs.imperva.com/bundle/cloud-application-security/page/api/sites-api.htm#List
This seems to be very painful for me to understand in go as I'm just starting..
From what I've been reading I should just define an object of type struct with my expected format.
Any way I can tackle this a lot easier? I'm interested in extracted for each individual site a few items like site_id / ips / domain.
Unsure how I should tackle this. I've been trying to get my head around https://github.com/buger/jsonparser but I'm failing to actually understand how to use it.
So far what I've been doing is:
func main() {
fmt.Println("Starting this..")
formData := url.Values{
"api_id": {keyid},
"api_key": {apikey},
"page_size": {"100"},
"page_num": {"0"},
}
response, err := http.PostForm("https://my.imperva.com/api/prov/v1/sites/list", formData)
if nil != err {
fmt.Println("Ooops..", err)
}
log.Println(response.Status)
bodyBytes, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Fatal(err)
}
var results map[string]interface{}
fmt.Println(string(bodyBytes))
json.Unmarshal([]byte(bodyBytes), &results)
defer response.Body.Close()
}
If you only need to extract a couple of fields, you don't really need to define an elaborate struct type to describe the whole structure. You can use the stdlib to unmarshal the JSON into a map[string]interface{} and then use something like this function to look for interesting keys:
// findNested looks for a key named s in map m. If values in m map to other
// maps, findNested looks into them recursively. Returns true if found, and
// the value found.
func findNested(m map[string]interface{}, s string) (bool, interface{}) {
// Try to find key s at this level
for k, v := range m {
if k == s {
return true, v
}
}
// Not found on this level, so try to find it nested
for _, v := range m {
nm, ok := v.(map[string]interface{})
if ok {
found, val := findNested(nm, s)
if found {
return found, val
}
}
}
// Not found recursively
return false, nil
}
This code deals only with nested maps. You can adjust it slightly to see through slices, etc.
You can define a single, complex go struct that reflects the entire json object structure, and annotate all of the elements with the json object/element names.
You can define simple structs for each of the nested objects, and annotate these structs with the json object/element names; and then build the complex struct by composing these structs.
Either of these are a ton of effort. You do not need the entire struct, you only need a few elements.
You can either define only the parts of the struct that you need to extract, and annotate those, or you can use the map[string]interface approach you have used. Both approaches work well.
package main
import (
"encoding/json"
"fmt"
)
func main() {
// your http query/response here
// Declare an empty interface
var results map[string]interface{}
body, err := ioutil.ReadAll(response.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(body))
// Unmarshal or Decode the JSON to the interface.
json.Unmarshal([]byte(body), &results)
defer response.Body.Close()
json.Unmarshal([]byte(empJson), &result)
//Reading each value by its key
fmt.Println("site_id:", result["site_id"],
"\ndomain:", result["domain"],
"\nip:", result["ips"][0],
// etc
)
}
See also:
How to unmarshal JSON in to array of interface and use
I have the following structs:
type A1 struct {
IdA1 string
NameA1 string
key string
}
type B1 struct {
IdB1 string
NameB1 string
Size string
key string
}
type C1 struct {
IdA1 string
Name string
B1Set B1
}
and I need to create a []struct of type C1, that holds a B1Set of B1, B1 is huge more than 2K entries and A1 is just 10 entries, a really slow and inefficient implementation would be to loop over A1, and ask if B1-key is equal to A1-key and store in a map the result, but.. is there any better way to implement this?
thanks in advance,
Add more info:
They are two different JSON files:
Json1:
[
{
"id": "device1",
"name": "dev1",
"pool": "pool1"
},
{
"id": "device2",
"name": "dev2",
"pool": "pool2"
}
...
]
And the other Json:
[
{
"name": "port1",
"size": 10,
"pool": "pool1",
"status": "active"
},
{
"name": "port2",
"size": 60,
"pool": "pool1",
"status": "active"
},
{
"name": "port3",
"size": 20,
"pool": "pool2",
"status": "down"
},
{
"name": "port8",
"size": 100,
"pool": "pool2",
"status": "active"
},
{
"name": "port10",
"size": 8000,
"pool": "pool1",
"status": "active"
},
...
]
So I need to create a new JSON file from those two with the following:
[
{
"id": "device1",
"name": "dev1",
"pool": "pool1",
"ports": [
{
"name": "port1",
"size": 10,
"pool": "pool1",
"status": "active"
},
{
"name": "port2",
"size": 60,
"pool": "pool1",
"status": "active"
},
{
"name": "port10",
"size": 8000,
"pool": "pool1",
"status": "active"
}
]
},
{
"id": "device2",
"name": "dev2",
"pool": "pool2",
"ports": [
{
"name": "port3",
"size": 20,
"pool": "pool2",
"status": "active"
},
{
"name": "port8",
"size": 100,
"pool": "pool2",
"status": "active"
}
]
}
]
taking into account that Json1 is not more than 10-12 entries and Json2 has more than 800-1000 entries.
So far:
read Json1 (devices), and Json2 (ports) and pass them into two []structs. Then:
results := make(map[string]*models.PortDevices}
portDevs := []models.PortDevices{}
for i := range devices {
results[devices[i].Pool] = &models.PortDevices{}
m := results[devices[i].Pool]
m.Id = devices[i].Id
m.Name = devices[i].Name
m.Pool = devices[i].Pool
m.Status = devices[i].Status
for p := range ports {
if val, ok := results[ports[p].Pool]; ok {
m := val
m.Ports = ports
}
}
portDevs = append(portDevs, *m)
}
devports := []models.PortDevices{}
for _, value := range results {
devports = append(devports, *value)
}
Is this what you are looking to do? https://play.golang.org/p/AZNzQAwRhN0
What this does is build a map grouping all of the ports by pool. Then it loops through what I labeled clusters and assigns the slice of Port to the matching Cluster by grabbing the matching slice by Pool value.
package main
import (
"encoding/json"
"fmt"
)
type Cluster struct {
ID string `json:"id"`
Name string `json:"name"`
Pool string `json:"pool"`
Ports []Port `json:"ports"`
}
type Port struct {
Name string `json:"name"`
Size int `json:"size"`
Pool string `json:"pool"`
Status string `json:"status"`
}
func main() {
var resources []Port
err := json.Unmarshal([]byte(resourceJSON), &resources)
if err != nil {
panic(err)
}
resourcesByPool := make(map[string][]Port)
for _, resource := range resources {
if _, ok := resourcesByPool[resource.Pool]; !ok {
resourcesByPool[resource.Pool] = []Port{}
}
resourcesByPool[resource.Pool] = append(resourcesByPool[resource.Pool], resource)
}
var clusters []Cluster
err = json.Unmarshal([]byte(clusterJSON), &clusters)
if err != nil {
panic(err)
}
for i := 0; i < len(clusters); i++ {
clusters[i].Ports = resourcesByPool[clusters[i].Pool]
}
out, err := json.MarshalIndent(clusters, "", " ")
if err != nil {
panic(err)
}
fmt.Println(string(out))
}
var (
clusterJSON = `[
{
"id": "device1",
"name": "dev1",
"pool": "pool1"
},
{
"id": "device2",
"name": "dev2",
"pool": "pool2"
}
]`
resourceJSON = `[
{
"name": "port1",
"size": 10,
"pool": "pool1",
"status": "active"
},
{
"name": "port2",
"size": 60,
"pool": "pool1",
"status": "active"
},
{
"name": "port3",
"size": 20,
"pool": "pool2",
"status": "down"
},
{
"name": "port8",
"size": 100,
"pool": "pool2",
"status": "active"
},
{
"name": "port10",
"size": 8000,
"pool": "pool1",
"status": "active"
}]`
)
When I got a new data json ORDER_TRX_H_ID the result must looping with new ORDER_TRX_H_ID, but my result always show last data.
My code is
package main
import (
"encoding/json"
"fmt"
)
func main() {
dataJSON := `[
{
"QUICK_DATA_H_ID": "1",
"ORDER_TRX_H_ID": "1",
"FIELD_QUESTION": "FULLNAME",
"FIELD_ANSWER": "RUBEN",
"DTM_CRT": "2019-08-28T16:25:15.757Z"
},
{
"QUICK_DATA_H_ID": "2",
"ORDER_TRX_H_ID": "1",
"FIELD_QUESTION": "ALAMAT_KTP",
"FIELD_ANSWER": "jalandisana",
"DTM_CRT": "2019-08-28T16:25:15.757Z"
},
{
"QUICK_DATA_H_ID": "3",
"ORDER_TRX_H_ID": "2",
"FIELD_QUESTION": "FULLNAME",
"FIELD_ANSWER": "Fariz",
"DTM_CRT": "2019-08-28T16:25:15.757Z"
},
{
"QUICK_DATA_H_ID": "4",
"ORDER_TRX_H_ID": "2",
"FIELD_QUESTION": "ALAMAT_KTP",
"FIELD_ANSWER": "Bogor",
"DTM_CRT": "2019-08-28T16:25:15.757Z"
}
]`
var data []map[string]interface{}
json.Unmarshal([]byte(dataJSON), &data)
qa := map[string]interface{}{}
for _, v := range data {
qa[v["FIELD_QUESTION"].(string)] = v["FIELD_ANSWER"]
}
hasil := data[0]
hasil["QUESTION"] = qa
delete(hasil, "FIELD_QUESTION")
delete(hasil, "FIELD_ANSWER")
hasilJSON, _ := json.MarshalIndent(hasil, "", " ")
fmt.Println(string(hasilJSON))
}
You can run my code
https://play.golang.org/p/aHUoYZlEQs4
My result always show last data
{
"DTM_CRT": "2019-08-28T16:25:15.757Z",
"ORDER_TRX_H_ID": "1",
"QUESTION": {
"ALAMAT_KTP": "Bogor",
"FULLNAME": "Fariz"
},
"QUICK_DATA_H_ID": "1"
}
my expected result
{
"DTM_CRT": "2019-08-28T16:25:15.757Z",
"ORDER_TRX_H_ID": "1",
"QUESTION": {
"ALAMAT_KTP": "jalandisana",
"FULLNAME": "RUBEN"
},
"QUICK_DATA_H_ID": "1"
},
{
"DTM_CRT": "2019-08-28T16:25:15.757Z",
"ORDER_TRX_H_ID": "2",
"QUESTION": {
"ALAMAT_KTP": "Bogor",
"FULLNAME": "Fariz"
},
"QUICK_DATA_H_ID": "2"
}
Why your result only showing 1 data? it because of this line of code:
hasil := data[0]
hasil will always have just one element
also qa will only contains value like this:
{
"ALAMAT_KTP": "BOGOR",
"FULLNAME": "Fariz"
}
it because every data iteration, qa[v["FIELD_QUESTION"].(string)] will keep replaced due to v["FIELD_QUESTION"].(string) is no unique, so in the 3rd iteration of data, the qa["ALAMAT_KTP] that already have value "jalandisana" is replaced with qa["ALAMAT_KTP] = "Bogor"
I modified your code here: https://play.golang.org/p/Ca4aGPGJwT7
I use 2 map[string]map[string]interface{} to hold qa and modified data
and then I combine them into one
package main
import (
"encoding/json"
"fmt"
)
func main() {
dataJSON := `[
{
"QUICK_DATA_H_ID": "1",
"ORDER_TRX_H_ID": "1",
"FIELD_QUESTION": "FULLNAME",
"FIELD_ANSWER": "RUBEN",
"DTM_CRT": "2019-08-28T16:25:15.757Z"
},
{
"QUICK_DATA_H_ID": "2",
"ORDER_TRX_H_ID": "1",
"FIELD_QUESTION": "ALAMAT_KTP",
"FIELD_ANSWER": "jalandisana",
"DTM_CRT": "2019-08-28T16:25:15.757Z"
},
{
"QUICK_DATA_H_ID": "3",
"ORDER_TRX_H_ID": "2",
"FIELD_QUESTION": "FULLNAME",
"FIELD_ANSWER": "Fariz",
"DTM_CRT": "2019-08-28T16:25:15.757Z"
},
{
"QUICK_DATA_H_ID": "4",
"ORDER_TRX_H_ID": "2",
"FIELD_QUESTION": "ALAMAT_KTP",
"FIELD_ANSWER": "Bogor",
"DTM_CRT": "2019-08-28T16:25:15.757Z"
}
]`
var data, finalResult []map[string]interface{}
json.Unmarshal([]byte(dataJSON), &data)
qa := map[string]map[string]interface{}{}
res := map[string]map[string]interface{}{}
for _, v := range data {
if qa[v["ORDER_TRX_H_ID"].(string)] == nil {
// initialize the map first if map is nil
qa[v["ORDER_TRX_H_ID"].(string)] = make(map[string]interface{})
}
qa[v["ORDER_TRX_H_ID"].(string)][v["FIELD_QUESTION"].(string)] = v["FIELD_ANSWER"]
delete(v, "FIELD_QUESTION")
delete(v, "FIELD_ANSWER")
// only assign res if res[key] is nil to prevent doubled data
if res[v["ORDER_TRX_H_ID"].(string)] == nil {
res[v["ORDER_TRX_H_ID"].(string)] = v
}
}
// combine qa and res in finalResult
for k, v := range res {
v["QUESTION"] = qa[k]
finalResult = append(finalResult, v)
}
hasilJSON, _ := json.MarshalIndent(finalResult, "", " ")
fmt.Println(string(hasilJSON))
}
Output:
[
{
"DTM_CRT": "2019-08-28T16:25:15.757Z",
"ORDER_TRX_H_ID": "1",
"QUESTION": {
"ALAMAT_KTP": "jalandisana",
"FULLNAME": "RUBEN"
},
"QUICK_DATA_H_ID": "1"
},
{
"DTM_CRT": "2019-08-28T16:25:15.757Z",
"ORDER_TRX_H_ID": "2",
"QUESTION": {
"ALAMAT_KTP": "Bogor",
"FULLNAME": "Fariz"
},
"QUICK_DATA_H_ID": "3"
}
]
I have what I would consider a very messy block of JSON, and I want to read and
modify two values that are deeply nested within (denoted: I want this!) using Go.
Due to the server that I am sending it to,
I cannot change the label names. What makes it especially difficult
for me is that parents have multiple children which are also nested, and since there are so many "value" labels I don't know how to specify which "value" child thatI want to enter.
I got the values in Bash very quickly using this
jq ' .value[0].value[1].value[0].value[1].value[0].value="'"$one"'" | '\ '
.value[0].value[1].value[0].value[1].value[1].value="'"$two"'"'
I tried a format like this in Go initially, but could not get it working because of the issue where children are all named "value" and I want to go into one other than the first. Unfortunately none of those magic JSON to Go struct were able to handle all of the nesting either.
type Bar struct {
Value struct { // Value[0]
Value struct { // Value[1]
Value struct { // Value[0]
Value struct { // Value[1]
Value struct { // Value[1] or Value[2]
}}}}}}
This code converts the JSON into a more struct/map friendly form, and prints the whole thing.
var foo interface{}
err := json.Unmarshal(blob, &foo)
if err != nil {
fmt.Println("error:", err)
}
m := foo.(map[string]interface{})
// print all
fmt.Println("Loop: ", m)
for k, v := range m {
fmt.Printf("%v : %v", k, v)
}
Here is the JSON that I am storing as a variable
var blob = []byte(`{
"tag": "1",
"value": [{
"tag": "2",
"value": [{
"tag": "3",
"value": [{
"tag": "4",
"type": "x",
"value": "x"
}, {
"tag": "5",
"type": "x",
"value": "x"
}
]
}, {
"tag": "6",
"value": [{
"tag": "7",
"value": [{
"tag": "8",
"type": "x",
"value": "x"
}, {
"tag": "9",
"value": [{
"tag": "10",
"type": "x",
"value": "I want this!"
}, {
"tag": "11",
"type": "Thanks for the help mate!",
"value": "I want this!"
}
]
}
]
}
]
}, {
"tag": "12",
"type": "x",
"value": "x"
}
]
}, {
"tag": "13",
"value": [{
"tag": "14",
"type": "x",
"value": "x"
}, {
"tag": "15",
"value": [{
"tag": "16",
"value": [{
"tag": "17",
"type": "x",
"value": "x"
}
]
}
]
}
]
}
]
}`)
I would appreciate any help or advice that you could give me.
Your initial attempt didn't work because you used structs where you need a slice of struct (Value []struct{...}). But that won't work either, because in some cases the values are slices and in some cases they're strings, which encoding/json does not like. Your best bet is one of two options: raw text manipulation, which will probably be quicker but more fragile and error-prone, or decoding as in your second example into a map[string]interface{} and doing some gnarly type assertions:
var foo map[string]interface{}
err := json.Unmarshal(blob, &foo)
if err != nil {
fmt.Println("error:", err)
}
foo["value"].([]interface{})[0].(map[string]interface{})["value"].([]interface{})[1].(map[string]interface{})["value"].([]interface{})[0].(map[string]interface{})["value"].([]interface{})[1].(map[string]interface{})["value"].([]interface{})[0].(map[string]interface{})["value"]
Trying to retrieve value "default-token-k99mq" from below JSON in go program ...
const input = `{
"kind": "ServiceAccount",
"apiVersion": "v1",
"metadata": {
"name": "default",
"namespace": "mynamespace",
"selfLink": "/api/v1/namespaces/mynamespace/serviceaccounts/default",
"uid": "483d1043-4d68-11e7-be08-3a3f3b149220",
"resourceVersion": "425039",
"creationTimestamp": "2017-06-09T23:06:34Z"
},
"secrets": [
{
"name": "default-token-k99mq"
}
]
}`
Need to get names from secrets array
You can do this https://play.golang.org/p/27eKFmBCHY
package main
import (
"fmt"
"encoding/json"
)
func main() {
const input = `{
"kind": "ServiceAccount",
"apiVersion": "v1",
"metadata": {
"name": "default",
"namespace": "mynamespace",
"selfLink": "/api/v1/namespaces/mynamespace/serviceaccounts/default",
"uid": "483d1043-4d68-11e7-be08-3a3f3b149220",
"resourceVersion": "425039",
"creationTimestamp": "2017-06-09T23:06:34Z"
},
"secrets": [
{
"name": "default-token-k99mq"
}
]
}`
type NameStruct struct {
Name string `json:"name"`
}
type Secret struct {
Secrets []NameStruct `json:"secrets"`
}
secret := Secret{}
json.Unmarshal([]byte(input), &secret)
fmt.Println(secret.Secrets[0].Name)
}