多叉树结构:JSON数据解析(一)

最近做一个实时数据搜索引擎的项目中,在项目架构的偏顶层需要写一个JSON数据解析的模块,由于目前JSON解析没有现成统一开源框架可以利用,目前只是手工利用com.alibaba.fastjson的API来自行转换,非常麻烦且不简洁,由此想到写一个通用工具类,封装成jar包以供调用。

先说下整体实时数据搜索引擎这个产品的整体架构图,以及JSON解析模块的位置:

一、准备工作

JSON是一种通用格式数据,通常手工解析提取字段是利用com.alibaba.fastjson的API来解析。首先需要用mvn配置好pom.xml,具体fastjson的开源工具jar包在这里可以下载:http://www.mvnrepository.com/artifact/com.alibaba/fastjson,这里随意选择一个版本,把依赖字段配置进pom.xml中,并在项目构建路径导入下载好的fastjson-1.1.41.jar。

在pom.xml中配置依赖:

<dependency>

<groupId>com.alibaba</groupId>

<artifactId>fastjson</artifactId>

<version>1.1.41</version>

</dependency>

JSON说到底就是一个字符串String,并且利用fastjsonAPI已经可以直接提取其中的关键字段,无需再从头解析。

首先,这里有几个函数说明下:最常用到的是getJSONObject()getJSONArray()函数

1.      JSONObject getJSONObject(Stringkey);提取json字符串里的字段作为JSONObject

2.      JSONArray getJSONArray(Stringkey);  提取JSONObject数组中的字段作为JSONArray

3.      Object parse(String text); 把JSON文本parse转换为JSONObject或JSONArray

4.      JSONObject parseObject(Stringtext);把JSON文本转换为JSONObject

5.      <T> T parsrObject(Stringtext, Class<T>, clazz); 把JSON文本parse为JavaBean(键值对)

6.      JSONArray parseArray(Stringtext); 把JSON文本转换为JSONArray

7.      <T> List<T>parseArray(String text, class <T> clazz); 把JSON文本转为JavaBean集合

8.      String toJSONString(Objectobject); 把JavaBean序列化为JSON文本

9.      String toJSONString(Objectobject, Boolean prettyFormat);将JavaBean序列化为带格式JSON文本

10.  Object toJSON(ObjectjavaObject); 将JavaBean转换为JSONObject或JSONArray

二、JSON数据转换样例

这里先给个在线查看JSON数据格式的层级关系工具:http://tool.oschina.net/codeformat/json,有了这个东西,查看JSON数据结构就方便多啦……

先来个开胃菜,上个简单的,假设只有两层数据嵌套,先上源码:

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; public class FastJson {
public static void main(String[] args){
String strJson = "{\"sqls\":[{\"sql\":\"INSERT INTO T_BASE_PERSON (PERSON_ID,PERSON_NAME) VALUES (?,?)\",\"values\":\"0dc11abb-967d-11e3-afc0-000c29c3253b,张三\"},{\"sql\":\"UPDATE T_BASE_CLASS SET CLASS_NAME=? WHERE CLASS_ID=?\",\"values\":\"一年一班,538b7ee7-967d-11e3-afc0-000c29c3253b\"}]}"; JSONObject myObj = JSONObject.parseObject(strJson);
JSONArray myArray = myObj.getJSONArray("sqls"); //就是根节点"sql"冒号后的东西[{"sql":"INSERT INTO...", "values":"0dc11abb"}]
System.out.println(myArray);
for(int i=0; i<myArray.size(); i++)
{
JSONObject o = myArray.getJSONObject(i);
System.out.println(o); //o就是第一个花括号{}里包含的所有东西(包括"sql","value"及其所有值)
System.out.println(o.get("sql")); //o.get("sql")就是得到sql冒号后的东西"INSERT INTO..."
System.out.println(o.get("values")); //o.get("value")就是得到value冒号后的东西"0dc11abb..."
} String strJson1 = "[{\"sql\":\"INSERT INTO T_BASE_PERSON (PERSON_ID,PERSON_NAME) VALUES (?,?)\",\"values\":\"0dc11abb-967d-11e3-afc0-000c29c3253b,张三\"},{\"sql\":\"UPDATE T_BASE_CLASS SET CLASS_NAME=? WHERE CLASS_ID=?\",\"values\":\"一年一班,538b7ee7-967d-11e3-afc0-000c29c3253b\"}]"; JSONArray myArray1 = JSONArray.parseArray(strJson1);
System.out.println(myArray1);
for(int j=0; j<myArray1.size(); j++)
{
JSONObject o1 = myArray1.getJSONObject(j);
System.out.println(o1.get("sql"));
System.out.println(o1.get("values"));
}
} }

可以看到,解析JSON字符串,最关键无非就是两个步骤:getJSONObject、getJSONArray,然后for循环遍历Array取得相应字段json对象。

看下运行结果吧:

三、JSON数据转换——穷举遍历法、无根节点多叉树随机访问

项目中需要解析的json样本数据,层级结构非常多,层层嵌套,有的甚至可能达10+层甚至30+层之多,如果仍旧如同上例每一层一层地去嵌套地利用for循环解析,采用硬编码指定固定字段名称的方式,效率非常低下,并且程序可扩展性太差。

我们的目的就是要把json里的字段全部有序地提取出来,只提取”aggregation”字段下的数据,并且能支持随机访问每个字段,可以用硬编码方式,也可以用优化的方式,即采用一个好的数据结构来对应这种json数据格式。

这里先给个样例,看下数据嵌套的规模吧。(注意这里为了区分单值和多值节点,首先对样本数据作了个小处理:凡是该节点下没有多个数组的为单值节点,全部以”ss_”开头作为标记,凡是该节点下有多个数组的为多值节点,全部以”bb_”开头作为标记,并且”bb_”开头的下面可能还有多值节点,即又是”bb_”开头的数据):

3.1 最笨的方法——穷举循环遍历

最开始没有什么好的方法,也还没想好什么数据结构来应对,先一步一步硬编码的方式去解析,大不了就是体力活,层层地“剥洋葱”,这里先给出源码:

import java.io.File;
import java.io.IOException;
//import java.util.Iterator;
//import java.util.LinkedHashMap;
import org.apache.commons.io.FileUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; public class DataFour {
public static void main(String[] args) throws IOException {
DataFour d = new DataFour();
String json = FileUtils.readFileToString(new File("e:/data/json4.txt"));
JSONObject jsono = JSONObject.parseObject(json);
JSONObject b = jsono.getJSONObject("aggregations"); //"预处理",得到"aggregation"下的所有字段
//d.buildResult(b); //------原始样例函数buildResult(b)-------//
d.Function(b,0); //------(新建)逐层解析函数Function(b)-----//
} public void Function(JSONObject b, int level){
String levelstr = level + "";
for(int i=0; i<level; i++){
levelstr += "\t";
}
for(String key : b.keySet()){
if(key.startsWith("bb_")){
JSONObject buckets = b.getJSONObject(key);
JSONArray bArray = buckets.getJSONArray("buckets");
for(int i=0; i<bArray.size(); i++){
JSONObject o = bArray.getJSONObject(i);
System.out.println("level"+level+"key:"+o.get("key")); //key:UZ6958037483314
System.out.println("level"+level+"doc_count:"+o.get("doc_count")); //doc_count:361 JSONObject vcod_buckets = o.getJSONObject("bb_versionCode");
JSONArray vcod_Array = vcod_buckets.getJSONArray("buckets");
System.out.println("level"+level+"bb_versionCode:");
for(int j=0; j<vcod_Array.size(); j++){
JSONObject o1 = vcod_Array.getJSONObject(j);
System.out.println("level"+(level+1)+"\t"+"key:" + o1.get("key"));
System.out.println("level"+(level+1)+"\t"+"doc_count:" + o1.get("doc_count")); JSONObject isNewVersion_buckets = o1.getJSONObject("bb_isNewVersion");
JSONArray isNewVersion_Array = isNewVersion_buckets.getJSONArray("buckets");
System.out.println("level"+(level+1)+"\t"+"bb_isNewVersion:");
for(int k=0; k<isNewVersion_Array.size(); k++){
JSONObject o2 = isNewVersion_Array.getJSONObject(k);
System.out.println("level"+(level+2)+"\t"+"\t"+"key:"+o2.get("key"));
System.out.println("level"+(level+2)+"\t"+"\t"+"doc_count:"+o2.get("doc_count"));
} JSONObject isNew_buckets = o1.getJSONObject("bb_isNew");
JSONArray isNew_Array = isNew_buckets.getJSONArray("buckets");
System.out.println("level"+(level+1)+"\t"+"bb_isNew:");
for(int k=0; k<isNew_Array.size(); k++){
JSONObject o2 = isNew_Array.getJSONObject(k);
System.out.println("level"+(level+2)+"\t"+"\t"+"key:"+o2.get("key"));
System.out.println("level"+(level+2)+"\t"+"\t"+"doc_count:"+o2.get("doc_count"));
} System.out.println("level"+(level+1)+"\t"+"ss_usercount/value:" + o1.getJSONObject("ss_usercount").getString("value"));
}
}
}
}
}
}

运行结果:

虽然通过这样的方式的确能把数据提取出来,但是代码中充斥着大量重复代码段,完全可以进行代码级重构,即把公用代码抽取出来,作为公有函数调用。但这种方式,代码量不会减少太多,并且效率得不到提升。

先写到这里,优化的方法到下篇文章再写。

(原创文章,转载请注明出处)

多叉树结构:JSON数据解析(一)的更多相关文章

  1. 多叉树结构:JSON数据解析(二)

    多叉树结构:JSON数据解析(二) 在上篇文章中提到了JSON数据解析的基本方法,但是方法效率太低,这里接着上篇文章写写如何利用多叉树结构,定义对象,实现JSON数据字段快速随机访问. JSON数据通 ...

  2. 使用Gson轻松解决复杂结构的Json数据解析

    转载请注明来源: http://blog.csdn.net/kjunchen/article/details/50961803 JSON简介 JSON(JavaScript Object Notati ...

  3. JSON数据解析 基础知识及链接收集

    JSON数据解析学习 JSON介绍 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式. JSON 是存储和交换文本信息的语法.类似 XML.但是JSON 比 ...

  4. JSON数据解析(转)

    JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,采用完全独立于语言的文本格式,为Web应用开发提供了一种理想的数据交换格式. 本文将主要介绍在Android ...

  5. iOS - JSON 数据解析

     iOS - JSON 数据解析 前言 NS_CLASS_AVAILABLE(10_7, 5_0) @interface NSJSONSerialization : NSObject @availab ...

  6. Silverlight项目笔记7:xml/json数据解析、TreeView、引用类型与数据绑定错误、图片加载、虚拟目录设置、silverlight安全机制引发的问题、WebClient缓存问题

    1.xml/json数据解析 (1)xml数据解析 使用WebClient获取数据,获取到的数据实例化为一个XDocument,使用XDocument的Descendants(XName)方法获得对应 ...

  7. Android学习笔记之JSON数据解析

    转载:Android学习笔记44:JSON数据解析 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,采用完全独立于语言的文本格式,为Web应用开发提供了一种 ...

  8. 【spark】文件读写和JSON数据解析

    1.读文件 通过 sc.textFile(“file://") 方法来读取文件到rdd中. val lines = sc.textFile("file://")//文件地 ...

  9. [开源 .NET 跨平台 数据采集 爬虫框架: DotnetSpider] [四] JSON数据解析

    [DotnetSpider 系列目录] 一.初衷与架构设计 二.基本使用 三.配置式爬虫 四.JSON数据解析与配置系统 场景模拟 假设由于漏存JD SKU对应的店铺信息.这时我们需要重新完全采集所有 ...

随机推荐

  1. B树的生成

    B树的生成 flyfish 2015-7-19 从空树開始构建一棵B树 逐个插入keyword 规则: 除根结点之外的全部非终端结点至少有⌈m/2⌉棵子树,所以keyword的个数必须 n为keywo ...

  2. CUGBACM_Summer_Tranning1 二进制枚举+模拟+离散化

    整体感觉:这个组队赛收获还挺多的.自从期末考试以后已经有一个多月没有 做过组队赛了吧,可是这暑假第一次组队赛就找回了曾经的感觉.还挺不错的!继续努力!! 改进的地方:这次组队赛開始的时候题目比較难读懂 ...

  3. C# Winform 中webBrowser显示html内容时禁止错误提示的方法

    在winform中有一个控件可以显示html的内容,该控件就是webbrowser,设置它的DocumenText属性为HTML的内容即可. 在使用WebBrowser做UI的时候,我们有时不希望里面 ...

  4. oracle sqlplus 常用操作

    命令 含义 / 运行 SQL 缓冲区 ? [关键词] 对关键词提供 SQL 帮助 @[@] [文件名] [参数列表] 通过指定的参数,运行指定的命令文件 ACC[EPT] 变量 [DEF[AULT] ...

  5. JavaScript读书笔记(4)-变量、作用域和内存问题

    1.ECMAScript数据类型分为:基本类型值和引用类型值: ECMAScript中所有函数的参数都是按值传递的: 检查对象的类型:varible instanceof constructor Al ...

  6. EF架构~终于自己架构了一个相对完整的EF方案

    EF4.1学了有段时间了,没有静下来好好研究它的架构,今天有空正好把它的架构及数据操作这段拿出来,希望给大家带来帮助,对我自己也是一种总结:P 从图中可以看到,我们用的是MVC3进行程序开发的,哈哈, ...

  7. pygame 安装教程

    步骤: 1.去官网下载PyGame 注意:要下载对应版本的包 官网地址:http://www.pygame.org/download.shtml 其中,如果python为以下版本: python 3. ...

  8. 13.JavaScript 类

    JavaScript 类 JavaScript 是面向对象的语言,但 JavaScript 不使用类. 在 JavaScript 中,不会创建类,也不会通过类来创建对象(就像在其他面向对象的语言中那样 ...

  9. ABAP 将Range 条目数转化

    RANGES:r_vbeln FOR lips-vbeln. r_vbeln-sign = 'I'. r_vbeln-option = 'EQ'. LOOP AT gt_item INTO gw_it ...

  10. jps不显示java进程信息

    本来想自己整理,发现已经有前人整理,并且完美解决了我的问题,故转载,感谢分享 转自:http://trinea.iteye.com/blog/1196400 对于jps较熟悉可以直接查看第二部分的分析 ...