如何写一个高效的JSON解析器

市面上90%的解析器,都是逐个字符解析,然后判断是什么内容,解析成什么类型

这种方式无疑会有一种问题,就是解析器会把你不需要的JSON数据,同样处理一遍。

为此,笔者发现了另外一种思路。

例如下面一段JSON:

{
	"d": [{
		"__type": "MdoCommonWs.WsStructures.WsWmsLookupResult",
		"CallResult": {
			"Id": 0,
			"Data": null,
			"ErrorId": 0,
			"ErrorDescription": null
		},
		"Article": {
			"Id": "001",
			"Description": "ANKERMECHANISCH",
			"Unit": "pieces",
			"UnitPrice": 7,
			"MinStock": 0,
			"MaxStock": 0,
			"Info": "ANKERMECHANISCHM12",
			"Photo": [],
			"PhotoUrl": "",
			"WeightUnit": "kg",
			"Weight": 0.05,
			"CountStock": 0
		},
		"Locations": [{
			"LocationId": "00.00.AA.01.01.01.02",
			"Type": 0,
			"IsBlocked": false,
			"ArticleId": "001",
			"Stock": 2,
			"TotalStock": 2,
			"LastActionDate": "/Date(1480334382093)/",
			"LastInventoryDate": "/Date(1480334319527)/"
		}]
	}],
	"s": [1, 2, 3]
}

怎么样,是不是很复杂。如果它变成下面的JSON后呢?

{
	"d": #aaaaa,
	"s": #bbbbb
}

没错,你一眼就能看出来这是一个object,然后用逗号分隔一下,很容易就能获取两个键值对。分别是d:#aaaaa和s:#bbbbb,这样你在获取d的对象时,再去解析d的内容就行了,根本不用去管s是什么。

笔者的方法,就是先把JSON里面的对象({})和数组([])全部替换掉,这样就能得到一个最简单的对象或数组。而那些被替换的内容,只要缓存起来就行,解析的时候再取出来就可以了。

下面是核心的替换代码:

/**
	 * 将json字符串转成块 例{"userid":[1,2,3]}会被转成{"userid":#1669281915687}
	 * 
	 * @param temp
	 *            原始json
	 * @param c1
	 *            块的起始位置
	 * @param c2
	 *            块的终止位置
	 */
	private void replaceJSONBlock(final StringBuffer temp, String c1, String c2) {
		int left = temp.lastIndexOf(c1);
		if (left > -1) {
			int right = temp.indexOf(c2, left);
			if (right > -1) {
				String uniqueKey = JSON.CACHE_PREFIX + System.nanoTime();
				this.cacheMap.put(uniqueKey, temp.substring(left, right + 1));
				temp.replace(left, right + 1, uniqueKey);
				replaceJSONBlock(temp, c1, c2);
			}
		}
	}

这样之后,这个JSON就可以很简单的进行处理了,甚至可以支持最新的JSON5规范。

测试:

long s = System.currentTimeMillis();
System.out.println(
				"self: " + obj.getJSONArray("d").getJSONObject(0).getJSONObject("CallResult").getString("Data"));
		System.out.println("self: " + obj.getJSONArray("d").toJSONString());
		System.out.println("self: " + obj.getJSONArray("s").get(1));
		long s1 = System.currentTimeMillis();
		System.out.println("time:" + (s1 - s));

		com.alibaba.fastjson.JSONObject obj2 = com.alibaba.fastjson.JSON.parseObject(str);
		System.out.println(
				"ali: " + obj2.getJSONArray("d").getJSONObject(0).getJSONObject("CallResult").getString("Data"));
		System.out.println("ali: " + obj2.getJSONArray("d").toJSONString());
		System.out.println("ali: " + obj2.getJSONArray("s").get(1));
		long s2 = System.currentTimeMillis();
		System.out.println("time:" + (s2 - s1));

结果:

self: null
self: [{"__type":"MdoCommonWs.WsStructures.WsWmsLookupResult","CallResult":{"Id":0,"Data":null,"ErrorId":0,"ErrorDescription":null},"Article":{"Id":"001","Description":"ANKER		 M12		 MECHANISCH","Unit":"pieces","UnitPrice":7,"MinStock":0,"MaxStock":0,"Info":"ANKER		 MECHANISCH		 M12","Photo":[],"PhotoUrl":"","WeightUnit":"kg","Weight":0.05,"CountStock":0},"Locations":[{"LocationId":"00.00.AA.01.01.01.02","Type":0,"IsBlocked":false,"ArticleId":"001","Stock":2,"TotalStock":2,"LastActionDate":"/Date(1480334382093)/","LastInventoryDate":"/Date(1480334319527)/"}]}]
self: 2
time:15
ali: null
ali: [{"CallResult":{"ErrorId":0,"Id":0},"__type":"MdoCommonWs.WsStructures.WsWmsLookupResult","Article":{"MinStock":0,"UnitPrice":7,"CountStock":0,"Description":"ANKER\t\t M12\t\t MECHANISCH","MaxStock":0,"WeightUnit":"kg","Photo":[],"Id":"001","PhotoUrl":"","Unit":"pieces","Info":"ANKER\t\t MECHANISCH\t\t M12","Weight":0.05},"Locations":[{"Type":0,"LocationId":"00.00.AA.01.01.01.02","ArticleId":"001","LastInventoryDate":"/Date(1480334319527)/","LastActionDate":"/Date(1480334382093)/","IsBlocked":false,"Stock":2,"TotalStock":2}]}]
ali: 2
time:207

对此,你有什么看法呢?

源码下载 https://gitee.com/yydf/easy-json

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值