I have an API that's returning an arbitrary number of maps nested an arbitrary number of levels deep. One example:
data=map[a:map[first_seen:2021-10-20 values:[map[h:<nil> ip:142.250.188.206 ip_count:474360 ip_organization:Google LLC]]] aaaa:map[first_seen:2021-10-20 values:[map[h:<nil> ipv6:2607:f8b0:4004:836::200e ipv6_count:459302 ipv6_organization:<nil>]]] mx:map[first_seen:2021-08-04 values:[map[hostname:aspmx.l.google.com hostname_count:1.3895903e 07 hostname_organization:Google LLC priority:10] map[hostname:alt4.aspmx.l.google.com hostname_count:8.616356e 06 hostname_organization:Google LLC priority:50] map[hostname:alt3.aspmx.l.google.com hostname_count:8.676906e 06 hostname_organization:Google LLC priority:40] map[hostname:alt2.aspmx.l.google.com hostname_count:1.3572714e 07 hostname_organization:Google LLC priority:30] map[hostname:alt1.aspmx.l.google.com hostname_count:1.3653905e 07 hostname_organization:Google LLC priority:20]]] ns:map[first_seen:2021-02-28 values:[map[nameserver:ns4.google.com nameserver_count:5320 nameserver_organization:Google LLC] map[nameserver:ns3.google.com nameserver_count:5328 nameserver_organization:Google LLC] map[nameserver:ns2.google.com nameserver_count:5357 nameserver_organization:Google LLC] map[nameserver:ns1.google.com nameserver_count:5386 nameserver_organization:Google LLC]]] soa:map[first_seen:2021-02-28 values:[map[email:dns-admin.google.com email_count:142373 ttl:900]]] txt:map[first_seen:2021-04-22 values:[map[value:v=spf1 include:_spf.google.com ~all] map[value:google-site-verification=wD8N7i1JTNTkezJ49swvWW48f8_9xveREV4oB-0Hf5o] map[value:google-site-verification=TV9-DBe4R80X4v0M4U_bd_J9cpOJM0nikft0jAgjmsQ] map[value:globalsign-smime-dv=CDYX XFHUw2wml6/Gb8 59BsH31KzUr6c1l2BPvqKX8=] map[value:facebook-domain-verification=22rm551cu4k0ab0bxsw536tlds4h95] map[value:docusign=1b0a6754-49b1-4db5-8540-d2c12664b289] map[value:docusign=05958488-4752-4ef2-95eb-aa7ba8a3bd0e] map[value:apple-domain-verification=30afIBcvSuDV2PLX] map[value:MS=E4A68B9AB2BB9670BCE15412F62916164C0B20BB]]]]
How can I loop recursively through such a data structure? How do I get to the key, value of the map at the deepest level?
CodePudding user response:
If its a JSON response, I have a package for that:
package main
import (
"fmt"
"github.com/89z/parse/json"
)
var data = []byte(`
{
"soa": {
"values":[
{"email_count":142373, "ttl":900}
]
}
}
`)
func main() {
var values []struct {
Email_Count int
TTL int
}
if err := json.UnmarshalArray(data, &values); err != nil {
panic(err)
}
fmt.Printf("% v\n", values) // [{Email_Count:142373 TTL:900}]
}
CodePudding user response:
Something like this ought to do you — simple depth-first map walker. It invokes you callback function visit()
on every leaf node ("leaf" being defined as "not a map"), passing it
- A slice/array containing the path (the keys leading to the item),
- The item's key, and
- The item's value
type Visit func( path []interface{}, key interface{}, value interface{} )
func MapWalker( data map[interface{}]interface{}, visit Visit ) {
traverse( data, []interface{}{}, visit )
}
func traverse( data map[interface{}]interface{}, path []interface{}, visit Visit ) {
for key, value := range data {
if child, isMap := value.(map[interface{}]interface{}); isMap {
path = append( path, key )
traverse( child, path, visit )
path = path[:len(path)-1]
} else {
visit( path, key, child )
}
}
}