本人算法较弱,问了各种 GPT ,始终不能得到期望的结果,特来求助各位爹。需要将一个树形的 JSON 数据,从每一个子节点的最后一级节点向上级节点平铺,转换为单层数据列表,以下是相关 原数据、目标字段 JSONPath 和 期望得到的结果。
{
"mainData": [
{
"id": 1,
"name:": "a",
"sub": [
{
"title": "A",
"used": true
},
{
"title": "B",
"used": false
}
]
},
{
"id": 2,
"name:": "c",
"sub": [
{
"title": "C",
"used": true
},
{
"title": "D",
"used": false,
"s_data": [
{
"s_data_id": 4,
"s_data_value": 0.1
},
{
"s_data_id": 5,
"s_data_value": 0.2
}
]
}
]
}
],
"moreData": [
{
"m_id": 3,
"m_name:": "e",
"sub": [
{
"s_title": "E",
"s_used": true,
"ext": {
"cid": "3_1",
"remark": "complex"
}
},
{
"s_title": "F",
"s_used": false,
"ext": {
"cid": "3_2",
"remark": "complex"
},
"children": [
{
"c_c_id": "3_2_1",
"c_c_title": "321"
},
{
"c_c_id": "3_2_2",
"c_c_title": "322"
}
]
}
]
}
]
}
[
"$.mainData[*].id",
"$.mainData[*].name",
"$.mainData[*].sub[*].title",
"$.mainData[*].sub[*].used",
"$.mainData[*].sub[*].s_data[*].s_data_id",
"$.mainData[*].sub[*].s_data[*].s_data_value",
"$.moreData[*].m_id",
"$.moreData[*].m_name",
"$.moreData[*].sub[*].s_title",
"$.moreData[*].sub[*].s_used",
"$.moreData[*].sub[*].ext.cid",
"$.moreData[*].sub[*].ext.remark",
"$.moreData[*].sub[*].children[*].c_c_id",
"$.moreData[*].sub[*].children[*].c_c_title"
]
[
{
"$.mainData[*].id": 1,
"$.mainData[*].name": "a",
"$.mainData[*].sub[*].title": "A",
"$.mainData[*].sub[*].used": true
},
{
"$.mainData[*].id": 1,
"$.mainData[*].name": "a",
"$.mainData[*].sub[*].title": "B",
"$.mainData[*].sub[*].used": false
},
{
"$.mainData[*].id": 2,
"$.mainData[*].name": "c",
"$.mainData[*].sub[*].title": "C",
"$.mainData[*].sub[*].used": true
},
{
"$.mainData[*].id": 2,
"$.mainData[*].name": "c",
"$.mainData[*].sub[*].title": "D",
"$.mainData[*].sub[*].used": false,
"$.mainData[*].sub[*].s_data[*].s_data_id": 4,
"$.mainData[*].sub[*].s_data[*].s_data_value": 0.1
},
{
"$.mainData[*].id": 2,
"$.mainData[*].name": "c",
"$.mainData[*].sub[*].title": "D",
"$.mainData[*].sub[*].used": false,
"$.mainData[*].sub[*].s_data[*].s_data_id": 5,
"$.mainData[*].sub[*].s_data[*].s_data_value": 0.2
},
{
"$.moreData[*].m_id": 3,
"$.moreData[*].m_name": "e",
"$.moreData[*].sub[*].s_title": "E",
"$.moreData[*].sub[*].s_used": true,
"$.moreData[*].sub[*].ext.cid": "3_1",
"$.moreData[*].sub[*].ext.remark": "complex"
},
{
"$.moreData[*].m_id": 3,
"$.moreData[*].m_name": "e",
"$.moreData[*].sub[*].s_title": "F",
"$.moreData[*].sub[*].s_used": false,
"$.moreData[*].sub[*].ext.cid": "3_2",
"$.moreData[*].sub[*].ext.remark": "complex",
"$.moreData[*].sub[*].children[*].c_c_id": "3_2_1",
"$.moreData[*].sub[*].children[*].c_c_title": "321"
},
{
"$.moreData[*].m_id": 3,
"$.moreData[*].m_name": "e",
"$.moreData[*].sub[*].s_title": "F",
"$.moreData[*].sub[*].s_used": false,
"$.moreData[*].sub[*].ext.cid": "3_2",
"$.moreData[*].sub[*].ext.remark": "complex",
"$.moreData[*].sub[*].children[*].c_c_id": "3_2_2",
"$.moreData[*].sub[*].children[*].c_c_title": "322"
}
]
1
Ayanokouji 12 天前 1
虽然和你的需求不匹配,但是还是可以参考下这个 https://github.com/oliveagle/jsonpath
|
2
whoami9426 12 天前 1
json-path, 1 楼已经给出答案了,自己再组装一下 '路径'->'值'
|
3
MoYi123 12 天前 1
要是其他语言我就直接给你写了, 但是 go 要写一堆反射.
|
4
loveuer 12 天前 1
```go
func TablePrinter(data any, writers ...io.Writer) { var w io.Writer = os.Stdout if len(writers) > 0 && writers[0] != nil { w = writers[0] } t := table.NewWriter() structPrinter(t, "", data) _, _ = fmt.Fprintln(w, t.Render()) } func structPrinter(w table.Writer, prefix string, item any) { Start: rv := reflect.ValueOf(item) if rv.IsZero() { return } for rv.Type().Kind() == reflect.Pointer { rv = rv.Elem() } switch rv.Type().Kind() { case reflect.Invalid, reflect.Uintptr, reflect.Chan, reflect.Func, reflect.UnsafePointer: case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.Interface, reflect.String: w.AppendRow(table.Row{strings.TrimPrefix(prefix, "."), rv.Interface()}) case reflect.Array, reflect.Slice: for i := 0; i < rv.Len(); i++ { p := strings.Join([]string{prefix, fmt.Sprintf("[%d]", i)}, ".") structPrinter(w, p, rv.Index(i).Interface()) } case reflect.Map: for _, k := range rv.MapKeys() { structPrinter(w, fmt.Sprintf("%s.{%v}", prefix, k), rv.MapIndex(k).Interface()) } case reflect.Pointer: goto Start case reflect.Struct: for i := 0; i < rv.NumField(); i++ { p := fmt.Sprintf("%s.%s", prefix, rv.Type().Field(i).Name) field := rv.Field(i) //log.Debug("TablePrinter: prefix: %s, field: %v", p, rv.Field(i)) if !field.CanInterface() { return } structPrinter(w, p, field.Interface()) } } } func TableMapPrinter(data []byte) { m := make(map[string]any) if err := json.Unmarshal(data, &m); err != nil { log.Warn(err.Error()) return } t := table.NewWriter() addRow(t, "", m) fmt.Println(t.Render()) } func addRow(w table.Writer, prefix string, m any) { rv := reflect.ValueOf(m) switch rv.Type().Kind() { case reflect.Map: for _, k := range rv.MapKeys() { key := k.String() if prefix != "" { key = strings.Join([]string{prefix, k.String()}, ".") } addRow(w, key, rv.MapIndex(k).Interface()) } case reflect.Slice, reflect.Array: for i := 0; i < rv.Len(); i++ { addRow(w, fmt.Sprintf("%s[%d]", prefix, i), rv.Index(i).Interface()) } default: w.AppendRow(table.Row{prefix, m}) } } ``` 感觉你这个可以参考这个,我主要是用来打印程序启动时候的配置 struct 的 |
5
loveuer 12 天前
table 是这个库,如果你想跑一下看看的话 "github.com/jedib0t/go-pretty/v6/table"
|
7
Projection 12 天前 1
原始的 JSON 数据中有几个 typo 需要修正回来:
"name:" "m_name:" 由于我不太明确你的具体需求,只能根据你想要的输出结果来写(将空格替换回来): ```python import json def unwind(root): ␣␣␣␣def dfs(node, inherit=False): ␣␣␣␣␣␣␣␣state = states[-1] ␣␣␣␣␣␣␣␣if not inherit: ␣␣␣␣␣␣␣␣␣␣␣␣states.append(state := states[-1].copy()) ␣␣␣␣␣␣␣␣for k, v in node.items(): ␣␣␣␣␣␣␣␣␣␣␣␣if isinstance(v, list): ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣continue ␣␣␣␣␣␣␣␣␣␣␣␣path.append(k) ␣␣␣␣␣␣␣␣␣␣␣␣if isinstance(v, dict): ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣dfs(v, True) ␣␣␣␣␣␣␣␣␣␣␣␣else: ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣state[".".join(path)] = v ␣␣␣␣␣␣␣␣␣␣␣␣path.pop() ␣␣␣␣␣␣␣␣is_parent = any(isinstance(v, list) for v in node.values()) ␣␣␣␣␣␣␣␣if is_parent: ␣␣␣␣␣␣␣␣␣␣␣␣for k, v in node.items(): ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣if isinstance(v, list): ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣for vv in v: ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣path.append(k + "[*]") ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣dfs(vv) ␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣␣path.pop() ␣␣␣␣␣␣␣␣elif not inherit: ␣␣␣␣␣␣␣␣␣␣␣␣result.append(state.copy()) ␣␣␣␣␣␣␣␣if not inherit: ␣␣␣␣␣␣␣␣␣␣␣␣states.pop() ␣␣␣␣path = ["$"] ␣␣␣␣states = [{}] ␣␣␣␣result = [] ␣␣␣␣dfs(root, True) ␣␣␣␣return result def main(): ␣␣␣␣with open("a.json", "rb") as f: ␣␣␣␣␣␣␣␣data = json.load(f) ␣␣␣␣print(json.dumps(unwind(data), indent=2)) if __name__ == "__main__": ␣␣␣␣main() ``` |
8
Ashe007 11 天前 via iPhone 1
Java 中使用 Jackson 采取递归思路,可以处理任意 JSON 结构的扁平化解析,限定递归深度即可
|
9
Seves OP @Projection 非常感谢,我研究一下
|
10
Seves OP @Projection 再次感谢爹,基本解决了我的问题。https://github.com/iTanken/ExampleFlattenJSON.git
|
11
Projection 11 天前 1
@Seves 别这样,正常交流而已
|