精华内容
下载资源
问答
  • JSON作为一种重要的数据格式,具有良好的可读性以及自描述性,广泛地应用在各种数据传输场景中。...GoLand可以使用标准库encoding/json解析JSON数据,此外还有第三方包ffjson、easyjson、jsoniter...

    JSON作为一种重要的数据格式,具有良好的可读性以及自描述性,广泛地应用在各种数据传输场景中。在网络爬虫中,当网页采用AJAX方式渲染数据时,我们必须找出AJAX的异步请求方式,并且模拟发送AJAX,从中获取数据内容,AJAX的响应数据大部分采用JSON格式表示。
    GoLang可以使用标准库encoding/json解析JSON数据,此外还有第三方包ffjsoneasyjsonjsoniterjsonparser等等。在性能上,第三方包完胜标准库encoding/json,本文将分别讲述标准库encoding/json和第三包jsoniter的使用。

    标准库encoding/json

    回顾GoLang—爬虫入门基础—数据清洗(goquery),我们将HTTP发起请求封装在函数SendHttp,主函数main实现函数SendHttp调用和响应内容的数据处理。本文继续沿用上一节的功能代码,将发送HTTP的网址改为12306的余票查询,当我们在网页上输入查询信息并点击查询按钮即触发AJAX请求,如图所示。
    在这里插入图片描述
    图上的AJAX请求的响应内容为JSON格式,标准库encoding/json解析JSON有两种方式:根据JSON内容格式定义对应的结构体(struct)、使用map[string]interface{}加载JSON数据。
    实际工作中,个人不建议采用根据JSON内容格式定义对应的结构体(struct),当JSON内容格式过于复杂的时候,对应的结构体(struct)会随之增加,这样会增加大量的代码。我们采用使用map[string]interface{}加载JSON数据,实现代码如下。

    package main
    
    import (
    	"encoding/json"
    	"fmt"
    	"io/ioutil"
    	"net/http"
    	"net/url"
    	"time"
    )
    
    
    // 使用映射传递函数参数,requestMode作为HTTP的请求方式
    func SendHttp(urls string, method string, rawurl string, cookie []http.Cookie)string{
    	req, _ := http.NewRequest(method ,urls, nil)
    	//为请求对象NewRequest设置请求头
    	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
    	req.Header.Add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36")
    
    	//设置Cookies信息
    	if cookie != nil {
    		for _, v := range cookie{
    			req.AddCookie(&v)
    		}
    	}
    
    	//设置代理IP,代理IP必须以为fun形式表示
    	client := &http.Client{}
    	if rawurl != "" {
    		proxy := func(_ *http.Request) (*url.URL, error) {
    			return url.Parse(rawurl)
    		}
    		transport := &http.Transport{Proxy: proxy}
    		//在Client对象设置参数Transport即可实现代理IP
    		client.Transport = transport
    	}
    
    	//执行HTTP请求
    	resp, _ := client.Do(req)
    
    	//读取响应内容
    	body, _ := ioutil.ReadAll(resp.Body)
    	return string(body)
    
    }
    
    func main() {
    	urls := "https://kyfw.12306.cn/otn/leftTicket/queryT?leftTicketDTO.train_date=2019-09-17&leftTicketDTO.from_station=SHH&leftTicketDTO.to_station=GZQ&purpose_codes=ADULT"
    	method := "GET"
    	//rawurl := "http://111.231.93.66:8888"
    	rawurl := ""
    	var cookie []http.Cookie
    	c := http.Cookie{Name: "clientcookieid", Value: "121", Expires: time.Now().Add(111 * time.Second)}
    	cookie = append(cookie, c)
    	result := SendHttp(urls, method, rawurl, cookie)
    	fmt.Println(result)
    
    	// 定义make(map[string]interface{})
    	r := make(map[string]interface{})
    	fmt.Println([]byte(result))
    	// 调用标准库encoding/json的Unmarshal
    	// 将JSON数据(JSON以字符串形式表示)转换成[]byte,并将数据加载到对象r的内存地址
    	json.Unmarshal([]byte(result), &r)
    	// r["data"]是读取JSON最外层的key
    	// 如果嵌套JSON数据,则使用map[string]interface{}读取下一层的JSON数据
    	// 如读取key为data里面嵌套的result:r["data"].(map[string]interface{})["result"]
    	// 如果JSON的某个key的数据以数组表示,则使用([]interface{})[index]读取数组中某个数据。
    	// 如读取key为result的第四个数据:r["data"].(map[string]interface{})["result"].([]interface{})[3]
    	fmt.Println(r["data"].(map[string]interface{})["result"].([]interface{})[3])
    }
    
    
    

    运行上述代码,其运行结果如图所示。
    在这里插入图片描述
    除了可以使用Unmarshal函数来解封 JSON,还可以使用Decoder手动地将 JSON 数据解码到结构里面,以此来处理流式的 JSON 数据(即JSON数据过大的时候),如图所示。
    在这里插入图片描述
    通过调用NewDecoder并传入一个包含 JSON 数据的io.Reader,程序创建出了一个新的解码器。在把指向Post结构的引用传递给解码器的Decode方法之后,被传入的结构就会填充上相应的数据,然后这些数据就可以为程序所用了。当所有 JSON 数据都被解码完毕时,Decode方法将会返回一个EOF,而程序则会在检测到这个EOF之后退出for循环。

    在面对 JSON 数据时,我们可以根据输入决定使用Decoder还是Unmarshal:如果 JSON 数据来源于io.Reader流,如http.Request的Body,那么使用Decoder更好;如果 JSON 数据来源于字符串或者内存的某个地方,那么使用Unmarshal更好。

    **除此之外,标准库encoding/json还可以调用函数Marshal或MarshalIndent(MarshalIndent将JSON数据格式化输出,会将数据自动分段分行处理),将特定的数据转化成JSON数据。此外还可以使用Decoder,代码如下。
    在这里插入图片描述
    程序会创建一个用于存储 JSON 数据的 JSON 文件,并通过把这个文件传递给NewEncoder函数来创建一个编码器。接着,程序会调用编码器的Encode方法,并向其传递一个指向Post结构的引用。在此之后,Encode方法会从结构里面提取数据并将其编码为 JSON 数据,然后把这些 JSON 数据写入创建编码器时给定的 JSON 文件里面。

    第三包jsoniter

    第三包jsoniter是100% 兼容原生库,但是性能超级好,预先缓存了对应struct的decoder实例,然后unsafe.Pointer省掉了一些interface{}的开销,还有一些文本解析上的优化。
    首先在CMD里输入第三包jsoniter的安装指令,如下所示:

    go get github.com/json-iterator/go
    

    jsoniter的使用方式也相对简单,只需定义ConfigCompatibleWithStandardLibrary对象即可,由该对象调用Unmarshal或Marshal函数即可实现JSON的解析和转换,比如上述代码中,我们只需修改包的引入和定义ConfigCompatibleWithStandardLibrary即可,代码如下

    import (
    	"fmt"
    	"github.com/json-iterator/go"
    	"io/ioutil"
    	"net/http"
    	"net/url"
    	"time"
    )
    ……………………(省略相同代码)
    func main() {
    	……………………(省略相同代码)
    	// 定义make(map[string]interface{})
    	r := make(map[string]interface{})
    	var json = jsoniter.ConfigCompatibleWithStandardLibrary
    	json.Unmarshal([]byte(result), &r)
    	fmt.Println(r["data"].(map[string]interface{})["result"].([]interface{})[3])
    }
    

    如果想要了解第三包jsoniter的实现原理,可以参考官方的Github地址:jsoniter

    综合上述,本博文只简单讲述了标准库encoding/json和第三包jsoniter如何解析JSON数据,下一节将讲述如何将爬取的数据进行入库处理。

    展开全文
  • 我们在使用AJAX来做服务器端和客户端交互的时候,一般的做法是让服务器端返回一段JSON字符串,然后在客户端把它解析成JavaScript对象。解析时用到的方法一般是eval或者new function,而目前IE8和Firefox3.1又内置了...

    我们在使用AJAX来做服务器端和客户端交互的时候,一般的做法是让服务器端返回一段JSON字符串,然后在客户端把它解析成JavaScript对象。解析时用到的方法一般是eval或者new function,而目前IE8和Firefox3.1又内置了原生的JSON对象(据说会有一定的性能提升)。那我们在实际使用的时候怎样从这三种方法(因为性能问题,不考虑用javascript实现的解析)里面来选择呢?面对众多的浏览器,哪种方式的性能是最好的呢?

    一、测试方法

    1、首先指定测试次数及JSON字符串

       1: var count = 10000, o = null, i = 0, jsonString = '{"value":{"items": [{"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}, {"x":1,"y":2,"z":3}]},"error":null}';

    2、循环解析并记录时间

    • eval
       1: var beginTime = new Date();
       2: for ( i = 0; i < count; i++ ) {
       3:     o = eval( "(" + jsonString + ")" );
       4: }
       5: Console.output( "eval:" + ( new Date() - beginTime ) );
    • new Function
       1: var beginTime = new Date();
       2: for ( i = 0; i < count; i++ ) {
       3:     o = new Function( "return " + jsonString )();
       4: }
       5: Console.output( "new Function:" + ( new Date() - beginTime ) );
    • native
       1: if ( typeof JSON !== "undefined" ) {
       2:     var beginTime = new Date();
       3:     for ( i = 0; i < count; i++ ) {
       4:         o = JSON.parse( jsonString );     }
       5:     Console.output( "native:" + ( new Date() - beginTime ) );
       6: } else {
       7:     Console.output( "native:not support!" );
       8: }

    二、测试对象

    选择目前主流的浏览器(不考虑Maxthon一类的外壳),包括IE6、7、8,Firefox2、3、3.1,Chrome,Opera及Safari3、4。

     

    三、测试环境

    T9300 CPU + 4G RAM + Windows2003,其中IE8使用的是Vista的环境,IE7在另外一台工作机(2G CPU + 2G RAM + Windows2003),考虑到主要是测试浏览器客户端的性能,结果的误差应该能够接受。

     

    四、测试结果

    JavaScript

    *数值越小越好

    *在当前列中绿色背景的表示性能最好,红色性能最差

    1、Firefox2、3全部垫底,IE6的性能优于IE7(可能和机器不一致有关),Chrome和Safari4的性能远远超出其它浏览器。

    2、不同的浏览器下eval和new Function的性能不一致,总的来说eval更好,但Firefox下new Function的性能是eval的一倍,为了更好的兼容各个浏览器,我们把对JSON的解析单独封装成一个对象来处理:

    • wrapper
       1: var __json = null;
       2: if ( typeof JSON !== "undefined" ) {
       3:     __json = JSON;
       4: }
       5: var browser = Browser;
       6: var JSON = {
       7:     parse: function( text ) {
       8:         if ( __json !== null ) {
       9:             return __json.parse( text );
      10:         }
      11:         if ( browser.gecko ) {
      12:             return new Function( "return " + text )();
      13:         }
      14:         return eval( "(" + text + ")" )
      15:     }
      16: };          
      17: var beginTime = new Date();
      18: for ( i = 0; i < count; i++ ) {
      19:     o = JSON.parse( jsonString ); }
      20: Console.output( "wrapper:" + ( new Date() - beginTime ) );

    加入Wrapper后的结果:

    由于涉及到调用对象的开销,封装后JSON对象会比单独调用更慢,但它能保证在各个浏览器下使用最适合的方法。

    学习web前端可以关注下知海匠库互联网学院,核心管理来自网易系。 

    五、结论

    解析Json字符串时,不同的浏览器选择不同的方法:

    • IE6、7使用eval
    • IE8使用原生的JSON对象
    • Firefox2、3使用new Function
    • Safari4使用eval
    • 其它浏览器下eval和new Function的性能基本一致
    展开全文
  • 写此json数据解析库的主要原因,因为最近在看json相关的程序,发现在linux下有完整的json库,而查看了这个json库后发现,这种json-c的库并不适用于单片机系统,尤其是没有OS的单片机系统,里面对内存的开销很大,...

    写此json数据解析库的主要原因,因为最近在看json相关的程序,发现在linux下有完整的json库,而查看了这个json库后发现,这种json-c的库并不适用于单片机系统,尤其是没有OS的单片机系统,里面对内存的开销很大,大量使用了malloc()和free()函数进行内存分配,考虑到在单片机系统内,这写函数都是尽量不使用,同时内存并不多,出于爱好,先写了个基于纯C语言的简单的json解析库。

    该库具备的特性:

    1.能够解析json字符串内的子json数据。

    2.能够解析str类型的json数据

    3.能够解析INT型数据

    4.能够解析bool型数据

    暂不支持的特性:

    1.不支持解析json数组类型数据(若去解析json数据中存在数组类型数据,将会返回出错)(json数组在单片机中用得确实少)

    2.不支持内存不够的判断(在使用API时需要保证所给的buff能够装得下所解析的数据,这也是单片机中常用的做法)

    3.基本库所解析回来的INT,bool等数据类型都是字符串的形式存在,可以通过扩张库转化为数字和bool变量

     

     

    eg:例程使用了linux下的json-c生成了一段json字符串,然后调用我编写的json解析获取数据

    #include <string.h>
    #include <stdlib.h>
    #include <stddef.h>
    
    #include "json.h"
    #include "hgetjson.h"          //针对于单片机提供的json库头文件
    
    
    
    int main(int argc, char *argv[])
    {
    	json_object *smart_home_protocol = NULL, *hellotest = NULL, *test11 = NULL;
    	
    	smart_home_protocol = json_object_new_object();
    	hellotest = json_object_new_object();
    	test11 = json_object_new_object();
    	
    	
    	if(smart_home_protocol == NULL)
    	{
    		printf("New Json Object Fail!\n");
    		exit(1);
    	}
    	int rc = json_object_object_add(smart_home_protocol, "Smart Home", smart_home_protocol);
    	json_object_object_add(smart_home_protocol, "heihei", json_object_new_int(66));
    	json_object_object_add(test11, "haha", json_object_new_int(35));
    	json_object_object_add(hellotest, "test0", hellotest);
    	json_object_object_add(hellotest, "haha",json_object_new_int(36));
    	json_object_object_add(hellotest, "heihei", test11);
    	json_object_object_add(smart_home_protocol, "test", hellotest);
    	//if (rc != -1)
    	//{
    		//printf("ERROR: able to successfully add object to itself!\n");
    		//fflush(stdout);
    	//}
    	json_object_object_add(smart_home_protocol, "router", json_object_new_string("Normal"));
    	json_object_object_add(smart_home_protocol, "temperature", json_object_new_int(36));
    	json_object_object_add(smart_home_protocol, "haha",json_object_new_int(37));
    	json_object_object_add(smart_home_protocol, "safe", json_object_new_boolean(1));
    	
    	
    	char *jsonstr = json_object_to_json_string(smart_home_protocol);
    	
    	printf("Json data :%s\n", jsonstr); //linux json-c 生成的json字符串
    	
    	char buff1[50] = {0};            //用来存放数据的buff
    	char buff2[50] = {0};
    	
    	int ret = get_json_object(buff1, "test", jsonstr);    //从jsonstr中获取名称为test的子json数据
    	if(ret)
    		printf("ERROR\n");
    	else
    	{
    		printf("\ntest json from jsonstr:%s\n", buff1);
    	}
    	
    	ret = get_json_object(buff2, "heihei", buff1);     //从子testjson中获取名为heihei的子json数据
    	if(ret)
    		printf("ERROR\n");
    	else
    	{
    		printf("\nheihei json from test:%s\n", buff2);
    	}
    	
    	ret = get_json_object(buff1, "heihei", jsonstr); //直接从jsonstr获取名为heihei的子json数据,直接穿过test 的子json
    	if(ret)
    		printf("ERROR\n");
    	else
    	{
    		printf("\nheihei json from jsonstr:%s\n", buff1);
    	}
    	
    	const char testname[4][10] = {"heihei", "haha", "router", "safe"};
    	
    	printf("\n");
    	for(int ii = 0; ii < 4; ii++)      //获取不同的数据和数据类型
    	{
    		ret = get_json_dat(buff2, &testname[ii][0], jsonstr);
    	
    		if(ret == STRTYPE)
    			printf("%s is STR dat from jsonstr, dat is %s\n", &testname[ii][0], buff2);
    		else if(ret == INTTYPE)
    			printf("%s is INT dat from jsonstr, dat is %s\n", &testname[ii][0], buff2);
    		else if(ret == BOOLTYPE)
    			printf("%s is BOOL dat from jsonstr, dat is %s\n", &testname[ii][0], buff2);
    		else
    			printf("Get ERROR\n");
    	}
    	
    
    	json_object_put(smart_home_protocol);        //释放掉linux json-c的内存
    	
    	
    	return 0;
    }

    运行结果如图:

     

     

    单片机hjson使用说明:

    获取json数据中子json API

    int get_json_object(char *buff, char *object_name, char *json_dat)

    buff:用于保存解析后的数据存储指针

    object_name:获取子json数据名称指针

    json_dat:原始json数据指针

    返回值:0,获取成功,1获取失败

     

    获取json内部数据的API:

    int get_json_dat(char *buff, char *dat_name, char *json)

    buff:用于保存解析后的数据存储指针

    dat_name:获取数据的名称指针

    json:原始json数据(注意:获取数据只会从根json中获取,不会从内部包含的子json中回去数据,若需要获取子json中的数据,需要先把子json给提取出来)

    返回值:#define NONETYPE        0
                  #define STRTYPE            1
                  #define INTTYPE            2
                  #define BOOLTYPE        3

    返回-1,者是没有找到该数据

     

    源码见:

    V1.0版本

    https://download.csdn.net/download/qq_18604707/10741372

    V1.1 处理了个别情况下字符串类型读取数据不正确的问题

    https://download.csdn.net/download/qq_18604707/12419134

    展开全文
  • Java解析json(二):jackson

    千次阅读 2017-02-03 16:30:02
    Jackson框架是基于Java平台的一套数据处理工具,被称为“最好的Java Json解析器”。 Jackson有两个主要分支,1.x处于维护状态,只会发布bug修复版本。2.x还在积极地开发当中。这两个版本的Java包名和Maven artifact...

    官方参考

    Jackson Home Page:https://github.com/FasterXML/jackson
    Jackson Wiki:http://wiki.fasterxml.com/JacksonHome
    Jackson doc: https://github.com/FasterXML/jackson-docs
    Jackson Download Page:http://wiki.fasterxml.com/JacksonDownload

    简介

    Jackson框架是基于Java平台的一套数据处理工具,被称为“最好的Java Json解析器”。

    Jackson有两个主要分支,1.x处于维护状态,只会发布bug修复版本。2.x还在积极地开发当中。这两个版本的Java包名和Maven artifact不一样,所以它们不互相兼容,但是可以和平共存,也就是项目可以同时依赖1.x和2.x而不会发生冲突。

    Jackson版本: 1.x (目前版本从1.1~1.9)与2.x。1.x与2.x从包的命名上可以看出来,1.x的类库中,包命名以:org.codehaus.jackson.xxx开头,而2.x类库中包命令:com.fastxml.jackson.xxx开头。

    本文以2.x为主…

    主要模块

    1. 核心模块

     核心模块是扩展模块构建的基础,到2.7版本为止,共有3个核心模块(依赖关系从上到下):
    
     ***Streaming*** :   jackson-core jar,定义了底层的streaming API和实现了Json特性。
     ***Annotations*** :  jackson-annotations jar,包含了标准的Jackson注解。
     ***Databind*** :   jackson-databind jar,实现了数据绑定和对象序列化,它依赖于streaming和annotations的包。
    

    2. 第三方数据类型模块

    这些扩展是插件式的Jackson模块,用ObjectMapper.registerModule()注册,并且通过添加serializers和deserializers以便Databind包(ObjectMapper / ObjectReader / ObjectWriter)可以读写这些类型,来增加对各种常用的Java库的数据类型的支持。参考https://github.com/FasterXML/jacksonThird-party datatype modules。

    3. 数据格式模块

    Jackson也有处理程序对JAX-RS标准实现者例如Jersey, RESTeasy, CXF等提供了数据格式支持。处理程序实现了MessageBodyReader和MessageBodyWriter,目前支持的数据格式包括JSON, Smile, XML, YAML和CBOR。

    数据格式提供了除了Json之外的数据格式支持,它们绝大部分仅仅实现了streaming API abstractions,以便数据绑定组件可以按照原来的方式使用。另一些(几乎不需要)提供了databind标准功能来处理例如schemas。参考https://github.com/FasterXML/jacksonData format modules

    准备工作

    JDK1.7,依赖jackon的三个核心类库:

    • jackson-core-2.5.3.jar
    • jackson-annotations-2.5.3.jar
    • jackson-databind-2.5.3.jar

    maven依赖:

    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.7.4</version>
    </dependency>
    
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.7.4</version>
    </dependency>
    
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.7.4</version>
    </dependency>

    处理Json

    Jackson提供了三种可选的Json处理方法:流式API(Streaming API) 、树模型(Tree Model)、数据绑定(Data Binding)。三种处理Json的方式的特性:

    • Streaming API:是效率最高的处理方式(开销低、读写速度快,但程序编写复杂度高)
    • Tree Model:是最灵活的处理方式
    • Data Binding:是最常用的处理方式

    1.Data Binding

    主要使用ObjectMapper来操作Json,默认情况下会使用BeanSerializer来序列化POJO。
    如果是解析,那么如下的例子里的TestJson必须要有setters,且setters必须是public修饰的,否则属性的值将会为null。
    如果是生成,那么必须有getters,且getters必须是public修饰的。
    如果属性不是private修饰,那么可以不用有getters和setters。(参考访问修饰符)
    要点:
    ObjectMapper mapper = new ObjectMapper();
    mapper.writeValue(jsonFile, Bean);
    mapper.readValue(jsonFile, Bean.class/Collection< Bean >);

    (1)生成json

    city.java

    package com.myjackson.databinding;
    //市
    public class City {
        private Integer id;
        private String cityName;
        public City(){}
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getCityName() {
            return cityName;
        }
        public void setCityName(String cityName) {
            this.cityName = cityName;
        }
    
    }

    province.java

    package com.myjackson.databinding;
    import java.util.Date;
    import java.util.List;
    //省
    public class Province {
        private Integer id;
        private String name;
        private Date birthDate;
        private List<City> cities;
        public Province(){}
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public List<City> getCities() {
            return cities;
        }
        public void setCities(List<City> cities) {
            this.cities = cities;
        }
        public Date getBirthDate() {
            return birthDate;
        }
        public void setBirthDate(Date birthDate) {
            this.birthDate = birthDate;
        }
    }

    counry.java

    package com.myjackson.databinding;
    
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    //国家
    public class Country {
    
        private Integer id;
        private String countryName;
        private Date establishTime;
        private List<Province> provinces;
        private String[] lakes;  
        private Map<String, String> forest = new HashMap<String, String>();
        public Country(){
    
        }
        public Integer getId() {
            return id;
        }
        public void setId(Integer id) {
            this.id = id;
        }
        public String getCountryName() {
            return countryName;
        }
        public void setCountryName(String countryName) {
            this.countryName = countryName;
        }
        public Date getEstablishTime() {
            return establishTime;
        }
        public void setEstablishTime(Date establishTime) {
            this.establishTime = establishTime;
        }
        public List<Province> getProvinces() {
            return provinces;
        }
        public void setProvinces(List<Province> provinces) {
            this.provinces = provinces;
        }
        public String[] getLakes() {
            return lakes;
        }
        public void setLakes(String[] lakes) {
            this.lakes = lakes;
        }
        public Map<String, String> getForest() {
            return forest;
        }
        public void setForest(Map<String, String> forest) {
            this.forest = forest;
        }  
    
    }

    测试案例

    @Test
        public void Bean2JsonStr() throws ParseException, JsonGenerationException, JsonMappingException, IOException{
            // 使用ObjectMapper转化对象为Json  
            ObjectMapper mapper = new ObjectMapper(); 
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");  
            mapper.setDateFormat(dateFormat);   //设置日期序列化格式
            City city1 = new City();
            city1.setId(1);
            city1.setCityName("gz");
            City city2 = new City();
            city2.setId(2);
            city2.setCityName("dg");
    
            Province province = new Province();
            province.setId(1);
            province.setName("GD");
            province.setBirthDate(new Date());
            List<City> cities = new ArrayList<City>();
            cities.add(city1);
            cities.add(city2);
            province.setCities(cities);
    
            Country country = new Country();
            country.setCountryName("China");
            country.setId(1);
            country.setEstablishTime(dateFormat.parse("1949-10-01"));
            country.setLakes(new String[] { "Qinghai Lake", "Poyang Lake","Dongting Lake", "Taihu Lake" });
            HashMap<String, String> forest = new HashMap<String, String>();
            forest.put("no.1", "dxal");
            forest.put("no.2", "xxal");
            country.setForest(forest);
            List<Province> provinces = new ArrayList<Province>();
            provinces.add(province);
            country.setProvinces(provinces);
            mapper.configure(SerializationFeature.INDENT_OUTPUT, true);     // 为了使JSON视觉上的可读性,在生产中不需如此,会增大Json的内容  
            mapper.setSerializationInclusion(Include.NON_EMPTY);  // 配置mapper忽略空属性  
            mapper.writeValue(new File("country.json"), country);  // 默认情况,Jackson使用Java属性字段名称作为 Json的属性名称,也可以使用Jackson annotations(注解)改变Json属性名称    
        }

    运行得到country.json:

    {
      "id" : 1,
      "countryName" : "China",
      "establishTime" : "1949-10-01",
      "provinces" : [ {
        "id" : 1,
        "name" : "GD",
        "birthDate" : "2017-02-04",
        "cities" : [ {
          "id" : 1,
          "cityName" : "gz"
        }, {
          "id" : 2,
          "cityName" : "dg"
        } ]
      } ],
      "lakes" : [ "Qinghai Lake", "Poyang Lake", "Dongting Lake", "Taihu Lake" ],
      "forest" : {
        "no.1" : "dxal",
        "no.2" : "xxal"
      }
    }

    (2)解析json

    @Test
        public void JsonStr2Bean() throws JsonParseException, JsonMappingException, IOException{
             ObjectMapper mapper = new ObjectMapper();  
             File jsonFile = new File("country.json");
             //当反序列化json时,未知属性会引起的反序列化被打断,这里我们禁用未知属性打断反序列化功能,  
             //因为,例如json里有10个属性,而我们的bean中只定义了2个属性,其它8个属性将被忽略  
             mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
             Country country = mapper.readValue(jsonFile, Country.class);
             System.out.println(country.getCountryName()+country.getEstablishTime());
             List<Province> provinces = country.getProvinces();  
                for (Province province : provinces) {  
                    System.out.println("province:"+province.getName() + "\n" + "birthDate:"+province.getBirthDate());  
                    for (City city: province.getCities()) {
                         System.out.println(city.getId()+" "+city.getCityName());
                    }
                }  
        }

    输出结果:

    ChinaSat Oct 01 08:00:00 CST 1949
    province:GD
    getBirthDate:Sat Feb 04 08:00:00 CST 2017
    1 gz
    2 dg

    解析的时候如果碰到集合类,那么可以使用TypeReference类

    @Test
        public void JsonStr2List() throws IOException{
             City city1 = new City();
             city1.setId(1);
             city1.setCityName("gz");
             City city2 = new City();
             city2.setId(2);
             city2.setCityName("dg");
    
             List<City> cities = new ArrayList<City>();
             cities.add(city1);
             cities.add(city2);
    
             ObjectMapper mapper = new ObjectMapper();  
             String listJsonStr = mapper.writeValueAsString(cities);
             System.out.println(listJsonStr);
             List<City> list = mapper.readValue(listJsonStr, new  TypeReference<List<City>>(){} );
             for (City city: list) {
                System.out.println("id:"+city.getId()+" cityName:"+city.getCityName());
             }
    
        }

    2.Streaming API

    Jackson提供了一套底层API来解析Json字符串,这个API为每个Json对象提供了符号。例如, ‘{’ 是解析器提供的第一个对象(writeStartObject()),键值对是解析器提供的另一个单独对象(writeString(key,value))。这些API很强大,但是需要大量的代码。大多数情况下,Tree Model和Data Binding可以代替Streaming API。

    上面代码如果注释掉 city1.setId(1);这行,结果为:

    [{"id":null,"cityName":"gz"},{"id":2,"cityName":"dg"}]
    id:null cityName:gz
    id:2 cityName:dg

    但假如想让id为null的不输出,不为null的输出除了 mapper.setSerializationInclusion(Include.NON_EMPTY); // 配置mapper忽略空属性 这种方法外还可以在ObjectMapper中注册一个自定义的序列化JsonSerializer和反序列化
    JsonDeSerializer:

    CityJsonSerializer.java

    package com.myjackson.databinding;
    
    import java.io.IOException;
    
    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.JsonSerializer;
    import com.fasterxml.jackson.databind.SerializerProvider;
    
    public class CityJsonSerializer  extends JsonSerializer<City>{
    
        @Override
        public void serialize(City city, JsonGenerator jsonGenerator, SerializerProvider arg2)
                throws IOException, JsonProcessingException {
             jsonGenerator.writeStartObject();  
             if ( city.getId()!=null) {
                 jsonGenerator.writeNumberField("id", city.getId());  
             }
             jsonGenerator.writeStringField("cityName", city.getCityName());  
             jsonGenerator.writeEndObject();  
    
        }
    
    }

    CityJsonDeSerializer.java

    package com.myjackson.databinding;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import com.fasterxml.jackson.core.JsonParser;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.core.JsonToken;
    import com.fasterxml.jackson.databind.DeserializationContext;
    import com.fasterxml.jackson.databind.JsonDeserializer;
    
    public class CityJsonDeSerializer  extends JsonDeserializer<List<City>>{
    
    
        @Override
        public List<City> deserialize(JsonParser parser,DeserializationContext deserializationcontext) throws IOException,
                JsonProcessingException {
            List<City> list = new ArrayList<City>();
            // 开始解析数组,第一个JsonToken必须是JsonToken.START_ARRAY"["
             if (!JsonToken.START_ARRAY.equals(parser.getCurrentToken())) {
                 System.out.println(parser.getCurrentToken());
                 return null;
             }
            // 解析符号直到字符串结尾  
            while (!parser.isClosed()) { 
                // 如果有必要的话,这个方法会沿着流前进直到足以确下一个JsonToken的类型  
                JsonToken token = parser.nextToken();  
                // 如果是最后一个JsonToken,那么就结束了  
                if (token == null)  
                    break; 
                // 数组的每个元素都是对象,因此下一个JsonToken是JsonToken.START_OBJECT"{"  
                if (!JsonToken.START_OBJECT.equals(token)) {  
                    break;  
                }  
                City city = null;
                // 输出id字段的值  
                while (true) { 
                    if (JsonToken.START_OBJECT.equals(token)) {  
                        city = new City();
                    } 
                    token = parser.nextToken();  
                    if (token == null)  
                        break;  
    
                    if (JsonToken.FIELD_NAME.equals(token) ) {
    
                        if("id".equals(parser.getCurrentName())){
                            token = parser.nextToken();  
                            city.setId(parser.getIntValue());
                        }else if("cityName".equals(parser.getCurrentName())){
                            token = parser.nextToken();
                            city.setCityName(parser.getText());
                        }
    
                    }  
                    if(JsonToken.END_OBJECT.equals(token)){
                        list.add(city);
                    }
    
                }  
    
            }  
            return list;
        }
    }

    测试:

    @Test
        public void StreamJsonStr2List() throws IOException{
             City city1 = new City();
             //city1.setId(1);
             city1.setCityName("gz");
             City city2 = new City();
             city2.setId(2);
             city2.setCityName("dg");
    
             List<City> cities = new ArrayList<City>();
             cities.add(city1);
             cities.add(city2);
    
             ObjectMapper mapper = new ObjectMapper();  
             SimpleModule module = new SimpleModule();  
             module.addSerializer(City.class, new CityJsonSerializer());  
             mapper.registerModule(module);  
             String listJsonStr = mapper.writeValueAsString(cities);
    
             System.out.println(listJsonStr);
    
             ObjectMapper mapper2 = new ObjectMapper();  
             SimpleModule module2 = new SimpleModule();  
             module2.addDeserializer(List.class, new CityJsonDeSerializer());  
             mapper2.registerModule(module2);  
             List<City> list = mapper2.readValue(listJsonStr, new  TypeReference<List<City>>(){} );
    
             for (City city: list) {
                System.out.println("id:"+city.getId()+" cityName:"+city.getCityName());
             }
    
        }

    也可以简单一点,使用注解,省去在ObjectMapper 中注册SimpleModule

    import com.fasterxml.jackson.databind.annotation.JsonSerialize;
    @JsonSerialize(using=CityJsonSerializer.class)
    public class City {
        ...
    }

    运行结果:

    [{"cityName":"gz"},{"id":2,"cityName":"dg"}]
    id:null cityName:gz
    id:2 cityName:dg

    ###3.Tree Mode
    如果不想为Json结构写一个class的话,Tree Mode是一个很好的选择。

    生成json:

    @Test
        public void TreeMode2Json() throws IOException{
    
            //创建一个节点工厂,为我们提供所有节点  
            JsonNodeFactory factory = new JsonNodeFactory(false);  
            //创建一个json factory来写tree modle为json  
            JsonFactory jsonFactory = new JsonFactory();  
            //创建一个json生成器  
            JsonGenerator generator = jsonFactory.createGenerator(new FileWriter(new File("country2.json")));  
            //注意,默认情况下对象映射器不会指定根节点,下面设根节点为country  
            ObjectMapper mapper = new ObjectMapper();  
            ObjectNode country = factory.objectNode();  
            country.put("id",   1);
            country.put("countryName","China");
            country.put("establishTime", "1949-10-01");
    
            ArrayNode provinces = factory.arrayNode(); 
            ObjectNode province = factory.objectNode();
            ObjectNode city1 = factory.objectNode();
            city1.put("id", 1);
            city1.put("cityName", "gz");
            ObjectNode city2 = factory.objectNode();
            city2.put("id", 1);
            city2.put("cityName", "dg");
            ArrayNode cities = factory.arrayNode();
            cities.add(city1).add(city2);
            province.put("cities", cities);
            provinces.add(province);
            country.put("provinces",provinces);
    
            ArrayNode lakes = factory.arrayNode();  
            lakes.add("QingHai Lake").add("Poyang Lake").add("Dongting Lake").add("Taihu Lake");
            country.put("lakes",lakes);
    
            ObjectNode forest = factory.objectNode();  
            forest.put("no.1","dxal");  
            forest.put("no.2", "xxal"); 
            country.put("forest", forest);
    
            mapper.setSerializationInclusion(Include.NON_EMPTY);  // 配置mapper忽略空属性  
            mapper.writeTree(generator, country);  
        }

    结果:

    {
        "id":1,
        "countryName":"China",
        "establishTime":"1949-10-01",
        "provinces":[
            {"cities":[
                {"id":1,"cityName":"gz"},
                {"id":1,"cityName":"dg"}
                ]
            }
        ],
        "lakes":["QingHai Lake","Poyang Lake","Dongting Lake","Taihu Lake"],
        "forest":{"no.1":"dxal","no.2":"xxal"}
    }

    读取json:

    @Test
    public void TreeModeReadJson() throws IOException{
             ObjectMapper mapper = new ObjectMapper();  
             // Jackson提供一个树节点被称为"JsonNode",ObjectMapper提供方法来读json作为树的JsonNode根节点  
             JsonNode node = mapper.readTree(new File("country2.json"));  
             // 看看根节点的类型  
             System.out.println("node JsonNodeType:"+node.getNodeType());  
             System.out.println("---------得到所有node节点的子节点名称----------------------");  
             Iterator<String> fieldNames = node.fieldNames();  
             while (fieldNames.hasNext()) {  
                 String fieldName = fieldNames.next();  
                 System.out.print(fieldName+" ");  
             }   
             System.out.println("\n---------------------------------------------------");  
    
             JsonNode lakes = node.get("lakes");  
             System.out.println("lakes:"+lakes+" JsonNodeType:"+lakes.getNodeType());  
    }

    运行结果:

    node JsonNodeType:OBJECT
    ---------得到所有node节点的子节点名称-------------------------
    id countryName establishTime provinces lakes forest 
    -----------------------------------------------------
    lakes:["QingHai Lake","Poyang Lake","Dongting Lake","Taihu Lake"] JsonNodeType:ARRAY

    结束

    Stream API方式是开销最低、效率最高,但编写代码复杂度也最高,在生成Json时,需要逐步编写符号和字段拼接json,在解析Json时,需要根据token指向也查找json值,生成和解析json都不是很方便,代码可读性也很低。
    Databinding处理Json是最常用的json处理方式,生成json时,创建相关的java对象,并根据json内容结构把java对象组装起来,最后调用writeValue方法即可生成json,
    解析时,就更简单了,直接把json映射到相关的java对象,然后就可以遍历java对象来获取值了。
    TreeModel处理Json,是以树型结构来生成和解析json,生成json时,根据json内容结构,我们创建不同类型的节点对象,组装这些节点生成json。解析json时,它不需要绑定json到java bean,根据json结构,使用path或get方法轻松查找内容。
    以上为个人参考网上博客以及一些个人实践,不对之处烦请指正,感激不尽~

    参考:

    http://blog.csdn.net/gjb724332682/article/details/51586701#
    http://blog.csdn.net/java_huashan/article/details/46375857

    展开全文
  • 在使用AJAX来做服务器端和客户端交互的时候,一般的做法是让服务器端返回一段JSON字符串,然后在客户端把它解析成JavaScript 对象。解析的方法有三种,eval,new function,或者目前IE8和Firefox3.1中内置的原生JSON...
  • 现在比较交流行和常用的对于网络请求数据的解析的方式基本就是XML解析Json解析 下面我们来对这两种解析方式做一些总结 一、XML解析: 服务器端解析是通过一般的XSLT转换工具(如Java下的Xalan)将XML和XSL合成...
  • XML与JSON解析

    2017-07-25 16:05:09
    不涉及DOM所必须的开销和概念跳跃。SAX API是一个基于事件的API,适用于处理数据流,即随着数据的流动而依次处理数据。SAX API在其解析文档时发生一定事件的时候会通知您。在您对其相应时,您不做保证的数据将会被...
  • C语言实现的json解析程序

    千次阅读 2020-06-23 21:23:43
    作用就是读取json文件,然后解析为若干个互相关联的结构,结构如下: typedef enum json_st { djson_string = 1, djson_number, djson_object, djson_array, djson_bool, djson_null }json_st; struct js {...
  • 与大多数JSON解析器不同, jstream具有文档位置和深度感知功能-能够提取指定深度的值,从而消除了分配包含数组或对象的开销; 例如: 使用以下示例文档: 我们可以选择仅提取并操作顶级数组中的对象: f , _ :=...
  • JSON解析框架汇总

    2017-05-16 09:44:43
    JSON解析框架汇总 转载地址:http://json.tongxiehui.net/?post/zdchoy.html 1、Gson Gson是Google提供的一个能够将Java对象转换成相应JSON表达形式的一个开源Java类库,当然用Gson也能将JSON字符串...
  • json解析之C++库nlohmann / json

    千次阅读 2020-08-27 12:20:45
    项目地址:...在像Python这样的语言中,JSON就像是一个一流的数据类型。我们使用了现代C++的所有操作符魔法,在您的代码中实现了相同的感觉。查看以下示例你会明白我的意思。
  • Json 解析方法总结

    2009-08-23 23:21:22
    Json 即为 Douglas Crockford 引入的数据传输格式,对于如何将这种...由于json是javascript的语法子集,而javascript又具有动态特性,则可利用eval直接动态解析即可。 注意要加括号来得到返回对象。速度最快 ...
  • Jackson解析与生成Json字符串

    千次阅读 2016-09-19 11:25:08
    流式API读取和写入JSON内容离散事件。 JsonParser读取数据,而JsonGenerator写入数据。它是三者中最有效的方法,是最低开销和最快的读/写操作。它类似于XML的Stax解析器。 在本文中,我们将展示的使用Jackson的流式...
  • Json文件解析(上)

    2020-07-14 18:55:34
    Json文件解析(上) 代码地址:https://github.com/nlohmann/json 自述文件 alt=GitHub赞助商 data-canonical-src=“https://img.shields.io/badge/GitHub-Sponsors-ff69b4” v:shapes="_x0000_i1025"> 设计目标 ...
  • JSON和XML解析的理解

    2016-07-26 18:01:55
    ◆可读性 JSON(Java Object Notation) 和XML的可读性可谓...XML有丰富的编码工具,比如Dom4j、JDom等,JSON也有json.org提供的工具,但是JSON的编码明显比XML容易许多,即使不借助工具也能写出JSON的代码,可是
  • 诞生于JavaScript,json的前世今生json含义在开始之前,问个问题,什么是json?a:我猜它应该是某一门高深的技术(语重心长)b:json这个词为啥谷歌翻译?是啥新词语嘛?是不是搞错了哟?(底气十足)c:json这个我听过,...
  • 前一阵子看到了一个Golang的JSON库go-simplejson,用来封装与解析匿名的JSON,说白了就是用map或者slice等来解析JSON,觉得挺好玩,后来有个项目恰好要解析JSON,于是就试了试,不小心看了一眼源代码,发现竟然是用...
  • // 两种URL类型相等,都是嵌套了一个json,需要继续进行解析 if(status==2){ Map, Object> map12 = JSONObject.parseObject(map1.get(key).toString(), Map.class); Map, Object> map13 = JSONObject.parseObject...
  • 然而这些通用的数据结构的使用是需要付出昂贵的代价的,主要体现在对cpu资源和io资源的特殊需求上,包括对json/xml数据流的解析产生的计算需求,以及传输过程中tag标签所引起的额外数据输出开销,另外一方面,xml/...
  • ios学习--XML&JSON解析

    2014-05-18 01:37:02
    XML & JSON 简介 XML --可扩展标记语言 --用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言 --易读性高,编码手写难度小,数据量大...
  • 区别: (1)可读性方面:基本相同,xml的可读性比较好 (2)可扩展性方面:都具有很好的扩展性 (3)编码难度方面:相对而言:JSON的编码比较容易 ...(6)数据交互方面:json与JavaScript的交互更加方面,更容易解析
  • 在这种方法中,JSON库变成了一个词法分析器,所有实际的解析都委托给应用程序,该应用程序必须实现一些手写的巧妙状态机,该状态机将: 将键映射到字段, 在对象和数组上切换上下文的开始/结束, 跳过所有不需要...
  • 高效的 C++ JSON 解析/生成器,提供 SAX 及 DOM 风格 API RapidJSON 是一个 C++ 的 JSON 解析器及生成器。它的灵感来自 RapidXml。 RapidJSON 小而全。它同时支持 SAX 和 DOM 风格的 API。SAX 解析器只有约 500 行...
  • 区别: (1)可读性方面:基本相同,xml的可读性比较好 (2)可扩展性方面:都具有很好的扩展性 (3)编码难度方面:相对而言:JSON的编码比较容易...(6)数据交互方面:json与JavaScript的交互更加方面,更容易解析处理,更好
  • “ 阅读本文大概需要 5分钟。 ”今天我们来聊聊 Java 中解析 JSON 的三个主流类库:FastJSON、Gson 和 Jackson。先来看下这三货在 Github 上的基本数...
  • 这期我们来聊聊Java中解析JSON的三个主流类库: FastJSON、Gson和Jackson。 先来看下这三货在Github上的基本数据: FastJson Github地址:https://github.com/alibaba/fastjson Jackson Github地址:...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 21,486
精华内容 8,594
关键字:

解析json开销