You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言如何反序列化含混合类型的嵌套JSON数组?

解决Go中嵌套混合数组JSON的反序列化问题

你的问题很典型——这个JSON是混合类型的嵌套表达式结构,既有三元组数组(比如["name", "contains", "test"]),又有逻辑运算符字符串("and"),还有更深层的嵌套表达式,直接用[]map[string]interface{}肯定不行,因为Go会尝试把每个元素解析成键值对map,但实际元素是数组或字符串,自然会报错。

下面给你两种可行的解决方案:


方案一:用interface{}接收并递归遍历处理

如果只是需要读取或遍历这个结构的数据,最快速的方式是用interface{}来接收整个JSON,然后通过类型断言递归解析每个元素:

package main

import (
	"encoding/json"
	"fmt"
)

func parseFilterNode(node interface{}) {
	switch val := node.(type) {
	case []interface{}:
		// 处理数组节点:可能是三元组条件,也可能是逻辑表达式组
		if len(val) == 3 {
			// 匹配三元组条件 [字段, 操作符, 值]
			field, _ := val[0].(string)
			operator, _ := val[1].(string)
			value := val[2]
			fmt.Printf("条件:%s %s %v\n", field, operator, value)
		} else {
			// 匹配逻辑表达式组,格式是 [表达式, 操作符, 表达式, ...]
			for i := 0; i < len(val); i++ {
				if i%2 == 0 {
					// 递归处理子表达式
					parseFilterNode(val[i])
				} else {
					// 处理逻辑运算符
					op, _ := val[i].(string)
					fmt.Printf("逻辑运算符:%s\n", op)
				}
			}
		}
	case string:
		// 这里一般是逻辑运算符,不过也可以根据实际情况扩展
		fmt.Printf("运算符:%s\n", val)
	default:
		fmt.Printf("未知类型节点:%T %v\n", val, val)
	}
}

func main() {
	// 模拟你的请求参数
	f := `[ [ "name", "contains", "test" ], "and", [ "group", "=", "123" ], "and", [ [ "date", ">=", "2020-06-30T23:00:00Z" ], "and", [ "date", "<", "2020-07-31T23:00:00Z" ] ] ]`

	var dat interface{}
	if err := json.Unmarshal([]byte(f), &dat); err != nil {
		panic(err)
	}

	// 递归解析整个过滤表达式
	parseFilterNode(dat)
}

这种方式不需要定义复杂的结构体,适合快速处理数据的场景。


方案二:自定义类型实现json.Unmarshaler接口

如果需要把这个JSON转换成强类型的Go对象(方便后续业务逻辑处理,比如生成SQL语句),可以定义对应的表达式类型,并手动实现反序列化逻辑:

package main

import (
	"encoding/json"
	"fmt"
)

// FilterExpr 统一的过滤表达式接口
type FilterExpr interface{}

// Condition 三元组条件:[字段, 操作符, 值]
type Condition struct {
	Field    string
	Operator string
	Value    interface{}
}

// LogicalExpr 逻辑表达式:由运算符连接多个子表达式
type LogicalExpr struct {
	Operator string
	Exprs    []FilterExpr
}

// UnmarshalJSON 自定义反序列化逻辑
func (e *FilterExpr) UnmarshalJSON(data []byte) error {
	// 先尝试解析成数组
	var arr []interface{}
	if err := json.Unmarshal(data, &arr); err != nil {
		return err
	}

	// 判断是三元组条件还是逻辑表达式
	if len(arr) == 3 {
		// 解析为Condition
		field, ok1 := arr[0].(string)
		op, ok2 := arr[1].(string)
		if !ok1 || !ok2 {
			return fmt.Errorf("invalid condition format")
		}
		*e = Condition{
			Field:    field,
			Operator: op,
			Value:    arr[2],
		}
		return nil
	}

	// 解析为LogicalExpr
	exprs := make([]FilterExpr, 0)
	var operator string
	for i := 0; i < len(arr); i++ {
		if i%2 == 0 {
			// 递归解析子表达式
			subData, err := json.Marshal(arr[i])
			if err != nil {
				return err
			}
			var subExpr FilterExpr
			if err := json.Unmarshal(subData, &subExpr); err != nil {
				return err
			}
			exprs = append(exprs, subExpr)
		} else {
			// 记录逻辑运算符(这里假设所有运算符一致,比如都是and,你可以根据需求扩展)
			op, ok := arr[i].(string)
			if !ok {
				return fmt.Errorf("invalid operator at index %d", i)
			}
			operator = op
		}
	}

	*e = LogicalExpr{
		Operator: operator,
		Exprs:    exprs,
	}
	return nil
}

func main() {
	f := `[ [ "name", "contains", "test" ], "and", [ "group", "=", "123" ], "and", [ [ "date", ">=", "2020-06-30T23:00:00Z" ], "and", [ "date", "<", "2020-07-31T23:00:00Z" ] ] ]`

	var expr FilterExpr
	if err := json.Unmarshal([]byte(f), &expr); err != nil {
		panic(err)
	}

	// 这里可以强类型断言处理不同的表达式
	logicalExpr, ok := expr.(LogicalExpr)
	if ok {
		fmt.Printf("逻辑运算符:%s\n", logicalExpr.Operator)
		for _, subExpr := range logicalExpr.Exprs {
			if cond, ok := subExpr.(Condition); ok {
				fmt.Printf("条件:%s %s %v\n", cond.Field, cond.Operator, cond.Value)
			} else if subLogical, ok := subExpr.(LogicalExpr); ok {
				fmt.Printf("嵌套逻辑运算符:%s\n", subLogical.Operator)
				for _, c := range subLogical.Exprs {
					cond := c.(Condition)
					fmt.Printf("嵌套条件:%s %s %v\n", cond.Field, cond.Operator, cond.Value)
				}
			}
		}
	}
}

这种方式可以把松散的JSON结构转换成清晰的Go对象,适合需要基于这个结构做复杂业务处理的场景。


为什么你的原始代码会报错?

你用了[]map[string]interface{}来接收,但这个JSON的元素不全是键值对的map——比如第一个元素是数组["name","contains","test"],第三个是字符串"and",Go在反序列化时会尝试把这些元素转换成map[string]interface{},显然无法完成,所以抛出了json: cannot unmarshal array into Go value of type map[string]interface {}的错误。

内容的提问来源于stack exchange,提问作者Shadoweb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 14:17:36