- 浏览: 146337 次
- 性别:
- 来自: 北京
最新评论
-
二飞在这里:
你好,这个代码里有很多方法都没有写呢,比如parseTailB ...
解析Json文本——如何将Json文本转化为Java对象 -
liuxingyu0909:
...
解析Json——Json类的实例方法 -
Hbin_0517:
写得很详细,读了内容之后···只能表示感谢!
JavaScript对象的创建、继承及原型 -
sunmoonma:
非常感谢楼主,果断是好东西。。。。
Json与XML -
wellway:
学习了,很好的东东
解析Json——Json类的实例方法
Json是一种简单小巧的数据交换格式,在Web开发中获得了广泛应用。网络上有很多Json库,光用Java编写的就不下二十个之多。无论哪一个Json库都必须具有一个基本功能,就是把Json文本转换为用本语言表示的数据结构,本文就是介绍如何把Json文本一字符一字符的解析成Java对象。
如果要问解析Json需要哪些基础知识的话,计算机科班出身的读者立马就能想到大学时学过的编译原理这门课程。解析Json就是需要利用编译原理的知识,不过Json非常简单,解析它不必使用所有的编译技术,只要了解词法分析就可以了。不了解词法分析也不要紧,Json非常简单,不用词法分析也能解析。本文根据bantouyan-json库中解析Json文本的方法编写,不需要词法分析的基础。
在介绍怎样解析Json文本之前,我们先回顾一下Json的定义。如果要了解Json的详细定义可以查看RFC4627文档,或者www.json.org网站。本文只作简要的介绍。
上面的五幅图像分别定义了Json的对象、数组、Value、字符串与数字。Json文本由一个Json对象或Json数组构成,无论是Json对象或者Json数组,还是Json字符串或数字,都是一个Json Value。
Json文本由构成Json的必要字符和额外的空白字符构成,解析它就要忽略额外的空白字符并将剩余部分转换为Java对象。本文按照bantouyan-json库提供的方法解析Json文本,介绍时做了一些适当的简化。
bantouyan-json库的解析功能由内部类JsonTextParser提供,JsonTextParser类的定义如下:
JsonTextParser类的核心成员有reader和ch,reader存储要解析的字符串,ch表示当前被扫描的字符,方法next()每执行一次扫描一个字符,当ch的值是-1时表明字符串扫描结束。 在详细介绍解析算法之前,先介绍JsonTextParser类的几个关键方法, boolean isBlankCharacter(int ch),判断字符ch是不是空白字符;void parseTailBlank(int endChar) 与void parseTailBlank(int endChar1, int endChar2),扫描并Json文本,在遇到终止字符endChar之前如果已经扫描完Json文本则抛出异常,扫描到第一个终止字符时退出该方法。 Json文本的解析从方法parse()开始(一个JsonTextParser对象方法parse只能被执行一次,这样设计也许并不合理,但它是内部类,不影响使用),其代码如下: parseTailBlank(-1)表示扫描完整个字符串前不允许出现非空白字符。Json文本只允许表示一个对象或数组,所以在字符“[”、“{”之前不允许出现非空白字符,扫描完第一个对象或数组(正常情况下只有一个)后也不允许再出现非空白字符。 方法parseJsonObject负责扫描并解析一个Json对象,调用该方法时正好扫描到Json对象的开始字符'{',得到Json对象后,扫描到对象的结束字符'}'的下一个字符时退出,parseJsonObject的代码如下: 方法parseName 负责解析JsonObject子元素的Name部分(包括分界符':'),parseValue负责解析JsonObject子元素的Value部分。 方法parseJsonArray负责扫描并解析一个Json数组,调用该方法时正好扫描到Json数组的开始字符'[',得到Json数组后,扫描到数组的结束字符']'的下一个字符时退出,parseJsonArray的代码如下: 方法parseValue负责解析Json数组的子元素。 方法parseName负责扫描并解析Json对象子元素的Name部分,调用该方法时正好扫描到Name部分的第一个字符(非空白字符),得到Name后,扫描到Name部分的结束字符':'的下一个字符时退出,parseName的代码如下: JsonObject子元素的Name部分就是一个字符串,方法parseName扫描这个字符串和随后的结束符':' 。 parseJsonObject与parseJsonArray都调用到方法parseValue, 方法parseValue负责解析一个Json Value。在Json中,Value可以是Json对象、Json数组、Json字符串、Json数字、true、false或null,它出现在Json对象子元素的Value部分和Json数组的子元素处,把这两处用到的代码归纳在一起,就是方法parseValue。调用parseValue时正好扫描到Value部分的第一个字符(可以是Value部分的第一个前导空白字符),扫描完Value部分(不包括后缀空白字符)后遇到下一个字符时退出,parseValue的代码如下: Value部分第一个非空白字符如果是'{'则Value是一个Json对象,如果是字符'[' 则Value是一个Json数组,如果是字符'"'则肯定是Json字符串,如果是字符'-'或字符'0'到'9'则肯定是Json数字,如果是字符't'则肯定是Json常量true,如果是字符'f'则肯定是常量false,如果是字符'n'则肯定是常量null,否则肯定Json文本格式有误,因而无法解析。 parseJsonObject与parseJsonArray前面都已经给予了介绍,下面介绍剩余的方法。 方法parseString负责扫描并解析一个Json字符串,调用该方法时正好扫描到Json字符串的开始字符'"',扫描完Json字符串后,扫描到字符串的结束字符'"'的下一个字符时退出,parseString的代码如下: 解析Json字符串的关键在于处理转义字符序列,要能够恰当的将转义字符序列转换为对应的字符,遇到非法转义字符时要报告错误。 Json中的数字与通常意义上的数字字面量有点不同,它不允许有不必要的前导零,也不允许有前导符号'+'。方法parseNumber负责扫描并解析一个Json数子,调用该方法时正好扫描到Json数字的开始字符,扫描完Json数字后,扫描到数字的下一个字符时退出,parseString的代码如下: 解析Json数字时使用一个StringBuilder存储表示数字的字符串,一边扫描一遍检查数字格式,最后根据扫描到的字符串能否转换为整数决定是用Long.parseLong(String)解析还是用Double.parseDouble(String)解析。 方法parseJsonConstant()负责解析Json常量true、false和null,调用时正好扫描到常量的第一个字符,退出时扫描到常量的下一个字符时退出,如果常量的下一个字符既不是分界符也不是是空白字符,那么认为所扫描到的不是一个Json常量处理。parseJsonConstant()的代码如下: 参数endChar表示Json常量后除','外允许跟的另外一个分界符,参数constAry用于比较所扫描的字符,参数constName用来报告更直观的异常。 本文介绍的算法对字符串只进行一次扫描,不需要回溯,因此时间复杂度为O(n)。一遍扫描的好处是不用回溯,算法简单,坏处是如果被解析的字符串格式不正确,那么只能报告所发现的第一个错误。好在大多数情况下本解析的Json文本都是正确的,而且代码一般也不负责修复Json文本的错误,所以采用一次扫描的策略是可行的。 相关阅读:class JsonTextParser
{
private Reader reader;
private int ch = -1;
public JsonTextParser(String text)throws IOException
{
StringReader strReader = new StringReader(text);
this.reader = strReader;
next();
}
private void next() throws IOException
{
ch = reader.read();
}
}
public Json parse() throws IOException, JsonException
{
Json json = null;
while(ch != -1)
{
if(ch == '{')
{
json = parseObject();
parseTailBlank(-1);
}
else if(ch == '[')
{
json = parseArray();
parseTailBlank(-1);
}
else if(! isBlankCharacter(ch))
{
// throw exception
}
next();
}
return json;
}
private JsonObject parseObject() throws IOException, JsonException
{
JsonObject json = new JsonObject();
boolean needNextElement = false;
next(); //skip character '{'
while(ch != -1)
{
//还没有遇到JsonObject的子元素,扫描到'}'可直接结束
if(needNextElement == false && ch == '}') break;
if(isBlankCharacter(ch))
{
next(); //skip blank character
}
else
{
String name = parseName();
Json value = parseValue('}');
parseTailBlank(',', '}');
json.set(name, value);
if (ch == '}') //子元素后是'}',JsonObject结束
{
break;
}
else //子元素后是',',需解析下一个子元素(Name Value对)
{
next(); // skip character ','
needNextElement = true;
}
}
}
if(ch == '}')
{
next(); // skip character '}'
}
else
{
// throw exception
}
return json;
}
private JsonArray parseArray() throws IOException, JsonException
{
JsonArray json = new JsonArray();
boolean needNextElement = false;
next(); // skip character '['
while(ch != -1)
{
//还没有遇到JsonArray的子元素,扫描到']'可直接结束
if(needNextElement == false && ch == ']') break;
if (isBlankCharacter(ch))
{
next(); //skip blank character
}
else
{
Json value = parseValue(']');
json.append(value);
parseTailBlank(',', ']');
if (ch == ']') //子元素后是']',数组结束
{
break;
}
else //子元素后是',',需解析下一个子元素
{
next(); // skip character ','
needNextElement = true;
}
}
}
if(ch == ']')
{
next(); // skip character ']'
}
else
{
// throw exception
}
return json;
}
private String parseName() throws IOException, JsonException
{
String name = null;
name = parseString(ch);
parseTailBlank(':');
if(ch == ':') //Name部分正常结束
{
next(); //skip character ':'
}
else
{
// throw exception
}
return name;
}
private Json parseValue(int endChar) throws IOException, JsonException
{
Json json = null;
while(ch != -1)
{
if(isBlankCharacter(ch))
{
next(); // skip blank character
}
else if(ch == '{')
{
json = parseObject();
break;
}
else if(ch == '[')
{
json = parseArray();
break;
}
else if(ch == 't') // parse true
{
json = parseJsonConstant("true", trueAry, endChar);
//trueAry是一个私有静态数组,内容是{'t', 'r', 'u', 'e'}
break;
}
else if(ch == 'f') //parse false
{
json = parseJsonConstant("false", falseAry, endChar);
//falseAry是一个私有静态数组,内容是{'f', 'a', 'l', 's', 'e'}
break;
}
else if(ch == 'n') //parse null
{
json = parseJsonConstant("null", nullAry, endChar);
//nullAry是一个私有静态数组,内容是{'n', 'u', 'l', 'l'}
break;
}
else if(ch == '\"')
{
String str = parseString();
json = new JsonPrimitive(str);
break;
}
else if(ch == '-' || (ch >= '0' && ch<= '9'))
{
Number num = parseNumber(endChar);
json = new JsonPrimitive(num);
break;
}
else
{
// throw exception
}
}
return json;
}
private String parseString() throws IOException, JsonException
{
StringBuilder build = new StringBuilder();
next(); // skip quatorChar "
while(ch != -1)
{
if(ch == '"') break;
if(ch < 0x0020)
{
// throw exception
}
if(ch == '\\')
{
next();
switch(ch)
{
case '\"':
ch = '\"';
break;
case '\'':
ch = '\'';
break;
case '\\':
ch = '\\';
break;
case '/':
ch = '/';
break;
case 'b':
ch = '\b';
break;
case 'f':
ch = '\f';
break;
case 'n':
ch = '\n';
break;
case 'r':
ch = '\r';
break;
case 't':
ch = '\t';
break;
case 'u':
for(int i=0; i<4; i++)
{
next();
if((ch >='0' && ch <='9') || (ch >= 'a' && ch <='f')
|| (ch>= 'A' && ch <= 'F'))
{
unicodeChar[i] = (char)ch;
// unicodeChar是一个私有字符数组,长度为4
}
else
{
// throw exception
}
}
ch = Integer.parseInt(new String(unicodeChar), 16);
break;
default:
// throw exception
}
}
build.append((char)ch);
next();
}
if(ch == '"')
{
next(); // skip quator char
}
else
{
// throw exception
}
return build.toString();
}
private Number parseNumber(int endChar) throws IOException, JsonException
{
StringBuilder build = new StringBuilder();
boolean isInt = true;
// parse minus sign
if(ch == '-')
{
build.append((char)ch);
next();
}
//parse integer part
if(ch == '0') //begin with 0
{
build.append((char)ch);
next();
if(ch >= '0' && ch <= '9')
{
// throw exception
}
}
else if(ch > '0' && ch <= '9') //begin with 1..9
{
build.append((char)ch);
next();
while(ch != -1)
{
if(ch >= '0' && ch <= '9')
{
build.append((char)ch);
}
else
{
break;
}
next();
}
}
else
{
// throw exception
}
//parse fraction
if(ch == '.')
{
build.append((char)ch);
isInt = false;
next(); //skip character '.'
if(ch>='0' && ch<='9')
{
while(ch != -1)
{
if(ch>='0' && ch<='9')
{
build.append((char)ch);
}
else
{
break;
}
next();
}
}
else
{
// throw exception
}
}
// parse exponent
if(ch == 'e' || ch == 'E')
{
build.append((char)ch);
isInt = false;
next(); //skip character e
//parse plus or minus sign
if(ch == '+' || ch == '-')
{
build.append((char)ch);
next();
}
if(ch>='0' && ch<='9')
{
while(ch != -1)
{
if(ch>='0' && ch<='9')
{
build.append((char)ch);
}
else
{
break;
}
next();
}
}
else
{
// throw exception
}
}
if(ch != ',' && ch != endChar && !isBlankCharacter(ch))
{
// throw exception
}
String numStr = build.toString();
try
{
if(isInt)
{
return Long.parseLong(numStr);
}
else
{
return Double.parseDouble(numStr);
}
}
catch (NumberFormatException e)
{
// throw exception
}
}
private JsonPrimitive parseJsonConstant(String constName, int[] constAry, int endChar)
throws IOException, JsonException
{
JsonPrimitive json = null;
for(int i=0; i<constAry.length; i++)
{
if(ch != constAry[i])
{
// throw exception
}
next();
}
if(ch != ',' && ch != endChar && !isBlankCharacter(ch))
{
// throw exception
}
json = (constAry == trueAry)? Json.trueJson:
(constAry == falseAry)? Json.falseJson: Json.nullJson;
return json;
}
评论
发表评论
-
解析Json——操纵JsonArray
2011-03-15 02:44 64651Json数组是子元素的有序集合,每个子元素都有一个 ... -
解析Json——操纵JsonObject
2011-03-15 01:42 21502Json对象是Name Va ... -
解析Json——Json类的实例方法
2011-03-09 04:22 7158作为所有Json实例的基类Json定义了操作Jso ... -
解析Json——Json类的静态方法
2011-03-05 18:43 9578要使用bantouyan-j ... -
解析Json——bantouyan-json库概述
2011-03-04 03:20 3780bantouyan-json库是用来解析与编码Js ... -
Json与XML
2011-02-19 16:26 2064上研究生时对XML ...
相关推荐
解决当内存资源不充足时大数据量的JSON文本解析为JSON对象会导致内存溢出的问题。 基于org.json的部分源代码,以及新增的JsonLazyer类。 原理:用时创建的规则降低传统解析器一次性将文本转成Java对象而占用大量内存...
java 解析 json文件java 解析 json文件java 解析 json文件java 解析 json文件java 解析 json文件
linux下解析json数据的一个工具包。是一个可执行文件,下载后放到某个目录中就可直接使用。详见:https://www.ibm.com/developerworks/cn/linux/1612_chengg_jq/index.html
此压缩包包含两个jar:json-lib-2.4-jdk15.jar和ezmorph-1.0.6.jar 这两个包都是java解析json数据的依赖包,而且是最新版,开源的东东好多人还要分,俺不要分,只希望对你有用。
附件内容为:Java组装map数据,然后转换为json数据格式;Java解析json数据
java解析Json字符串java解析Json字符串java解析Json字符串java解析Json字符串
C#的一个解析JSON的工具类,像java一样优雅的解析JSON数据,包含有JSONObject和JSONArray对象。 JSONObject json = new JSONObject(); json.Put("sex", "男"); json.Put("age", 123); json.Put("name", "张三"); ...
解析Json字符串直接转换为对象(包括多层List集合 嵌套)所用jar包
java获取网络json数据包和解析json数据完整案例。 需要用到json.org也包含在里边。
JSON官网上推荐的使用java解析json的类库,官网下载后的是未编译打包的java文件,这是我打包后的东东,使用时直接添加进Build path即可,简单实用……
JAVA解析JSON相关.docx
java解析json需要jar包。java解析json需要jar包。java解析json需要jar包。java解析json需要jar包。
java中需要解析前端传过来的json数据,完成相应的格式转换~
答:将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象] 从Java对象生成JSON的过程称为 [序列化Java对象到JSON] 为什么用它? 答:我数据库中的主键是使用雪花算法生成的,就是因为用id的位数太多,导致在...
json paser 属于idea插件 用于解析json json paser 属于idea插件 用于解析json json paser 属于idea插件 用于解析json json paser 属于idea插件 用于解析json json paser 属于idea插件 用于解析json json paser 属于...
json格式与java类对象相互转换。json格式转换成java类对象,List,Map。类对象转换成json。
1.解析json字符串 2.将json字符串转换为java对象 3.将java对象转换为json字符串
一个自制的json转换jar 直接调用JsonFactory.toJson()方法可将javaBean转换成json
这是本人写的一个基于JSON的完整项目,实现了Java对象、数组、集合转换为Json(Json转化为Java对象、数组、集合)。这是一个完整的项目,下载解压后直接导入MyEclipse/Eclipse中,运行com.demo.JSONDemo类即可看到效果...
使用该方法可以轻松解析JSON数组,方便取出JSON数据