Go json裁剪

背景

项目中遇到一个使用场景:服务端要保存用户上传的json格式示例,但是服务端针对这个json格式示例有大小限制,比如1KB,超过这个大小后服务端就不能正常保存了。此时用户正好手里有个比较大(>1KB)的json示例,他要想将这个示例正常保存可以进行两种不同操作:

  1. 手动去裁剪这个json字符串;
  2. 通过智能的方式自动将一些重复且不必要的数据删除掉,以达到json裁剪的目的

显然,针对第一种方式不太明智,那我们如果采用第二种方式的话,又该怎么做呢?

操刀

在Go里面,我们引用官方标准库encoding/json对json进行序列化和反序列化时用的最多的也是下面的两个方法:

  • func Unmarshal(data []byte, v interface{}) error
  • func Marshal(v interface{}) ([]byte, error)

注意里面的入参interface类型参数,第一个是将data里面数据反序列化到v中,第二个是将v中参数序列化成json字符串。而我们json格式对象常用的格式基本上都是下面这两种类型的:

[
    xxx,xxx,...
]

{
    xxx:ooo,...
}

我们正好可以分别用[]interface{}表示数组和map[string]interface{}表示大对象,然后顺理成章的采用递归的方式,循环处理里面的数据。
代码如下:

func knife(itf interface{}) interface{} {
	var t interface{}

	if _, ok := itf.(string); ok {
		t = ""
	} else if im, ok := itf.(map[string]interface{}); ok {
		for k := range im {
			im[k] = knife(im[k])
		}
		t = im
	} else if ia, ok := itf.([]interface{}); ok {
		if len(ia) != 0 {
			t = []interface{}{knife(ia[0])}
		} else {
			t = ia
		}
	} else {
		t = itf
	}

	return t
}

上面knife方法实现的机制为:

  1. 采用递归循环判断传递进来的对象类型,如果为map对象则对map中每个key所对应的value值进行循环判断,如果为数组对象则直接选取数组对象中的第一个元素;
  2. 上面例子中奖所有string类型value全都重置成了空字符串

然后达到了裁剪json的目的,且不损失json格式完整性。

注:
  • 以上方式主要目的是给你们一个启迪作用,具体要达到怎样的效果,可以根据实际也许需求来执行,比如要在一个未知的json里面新增固定key:value、字符串批量替换等骚操作都可以采用这种方式稍微魔改一下就行了。
PingD

PingD

一个阶段一个目标,多冷静下来思考思考
Chengdu.China