// data = output of jsonDecode() sclass JSONKeyTree { new TreeSet out; new MultiMap examples; S render(O data) { process(data); ret lines(out, key -> { var xmpls = examples.get(key); ret key + (empty(xmpls) ? "" : ", e.g. " + jsonEncode(first(xmpls))); }); } Set get(O data) { process(data); ret out; } void process(S prefix default "", O data) { if (data cast L) { out.add(prefix + " is a list"); S s = prefix + "[]"; for (O o : data) process(s, o); } else if (data cast Map) { out.add(prefix + " is a map"); for (O key, O val : castMapToMapO(data)) { S s = addDotIfNempty(prefix) + key; out.add(s); process(s, val); } } else if (data == null) out.add(prefix + " is null"); else { out.add(prefix + " is a " + shortClassName(data)); examples.put(prefix, data); } } }