1、json语法
json文本是一个标记(token)序列,标记包含6种结构字符,字符串,数字和3个字面量。
1)6中结构字符:
begin-array = ws %x5B ws; [ 左中括号
begin-object = ws %x7B ws;{ 左大括号
end-array = ws %x5D ws;]右中括号
end-object = ws %7D ws;}右大括号
name-separator = ws %x3A ws; :冒号
value-separator = ws % 2C ws; ,逗号
2)字符串:
字符串用引号作为开头和结尾。
3)数字包含一个可选的减号为前缀的整数部分,其后面可以有小数部分和/,或者指数部分。
八进制和十六机制是不允许的,以0开头是不允许的。
4)3个字符面量:
a)false;
b)null;
c)true;
三个字面量必须是小写的,其他字面量不允许使用。
5)对象
对象结构表示为一对大括号包含着0到多个名/值对(或者叫成员)。
6)数组
数组结构表示为一对中括号包含着0到多个值(或者叫元素),值与值之间用逗号分隔。
2、chrome的base::JSONReader类中针上述语法的定义:
class BASE_EXPORT JSONReader {
public:
// A struct to hold a JS token.
class Token {
public:
enum Type {
OBJECT_BEGIN, // {
OBJECT_END, // }
ARRAY_BEGIN, // [
ARRAY_END, // ]
STRING,
NUMBER,
BOOL_TRUE, // true
BOOL_FALSE, // false
NULL_TOKEN, // null
LIST_SEPARATOR, // ,
OBJECT_PAIR_SEPARATOR, // :
END_OF_INPUT,
INVALID_TOKEN,
};
//其他代码暂忽略
};
//其他代码暂忽略
};
代码中的定义的枚举类型对应了上面的6种结构字符,字符串,数字和3个字面量。
3、Json的反序列化
Value* JsonToValue(const std::string& json, bool check_root, bool allow_trailing_comma);
参数:
1)json,符合json格式的一个字符串;如果字符串json不符合json的格式,该函数将返回空指针NULL,并且还有一个详细的错误码能够通过error_message()获取;
2)check_root;如果check_root为true,那么json字符串类型必须是一个对象或者数组,否则json字符串将是一个无效的json类型;
3)allow_trailing_comma;如果allow_trailing_comma为true,那么json对象或者数组末尾含有的逗号将被忽略。
返回值:
通过读取解析字符串json,返回一个指向Value对象的指针。
4、函数Value* JsonToValue(const std::string& json, bool check_root, bool allow_trailing_comma)的实现逻辑
1)函数JSonToValue的实现:
Value* JSONReader::JsonToValue(const std::string& json, bool check_root,
bool allow_trailing_comma) {
// 输入的字符串必须是UTF-8格式的。
if (!IsStringUTF8(json.c_str())) {
error_code_ = JSON_UNSUPPORTED_ENCODING;
return NULL;
}
std::wstring json_wide(UTF8ToWide(json));
start_pos_ = json_wide.c_str();
if (!json_wide.empty() && start_pos_[0] == 0xFEFF) {
++start_pos_;
}
json_pos_ = start_pos_;
allow_trailing_comma_ = allow_trailing_comma;
stack_depth_ = 0;
error_code_ = JSON_NO_ERROR;
//依据输入的字符串给出相应的Value类型。
scoped_ptr<Value> root(BuildValue(check_root));
if (root.get()) {
if (ParseToken().type == Token::END_OF_INPUT) {
return root.release();
} else {
SetErrorCode(JSON_UNEXPECTED_DATA_AFTER_ROOT, json_pos_);
}
}
if (error_code_ == 0)
SetErrorCode(JSON_SYNTAX_ERROR, json_pos_);
return NULL;
}
2)函数BuildValue的实现:
Value* JSONReader::BuildValue(bool is_root) {
++stack_depth_;
if (stack_depth_ > kStackLimit) {
SetErrorCode(JSON_TOO_MUCH_NESTING, json_pos_);
return NULL;
}
//判断输入的字符串符合哪种json序列(是布尔值,空指针,数字,字符串,数组还是对象)
Token token = ParseToken();
// The root token must be an array or an object.
if (is_root && token.type != Token::OBJECT_BEGIN &&
token.type != Token::ARRAY_BEGIN) {
SetErrorCode(JSON_BAD_ROOT_ELEMENT_TYPE, json_pos_);
return NULL;
}
scoped_ptr<Value> node;
switch (token.type) {
case Token::END_OF_INPUT:
case Token::INVALID_TOKEN:
return NULL;
//空指针
case Token::NULL_TOKEN:
node.reset(Value::CreateNullValue());
break;
//布尔值true
case Token::BOOL_TRUE:
node.reset(Value::CreateBooleanValue(true));
break;
//布尔值false
case Token::BOOL_FALSE:
node.reset(Value::CreateBooleanValue(false));
break;
//数字
case Token::NUMBER:
node.reset(DecodeNumber(token));
if (!node.get())
return NULL;
break;
//字符串
case Token::STRING:
node.reset(DecodeString(token));
if (!node.get())
return NULL;
break;
//数组
case Token::ARRAY_BEGIN:
{
json_pos_ += token.length;
token = ParseToken();
node.reset(new ListValue());
while (token.type != Token::ARRAY_END) {
Value* array_node = BuildValue(false);
if (!array_node)
return NULL;
static_cast<ListValue*>(node.get())->Append(array_node);
// After a list value, we expect a comma or the end of the list.
token = ParseToken();
if (token.type == Token::LIST_SEPARATOR) {
json_pos_ += token.length;
token = ParseToken();
// Trailing commas are invalid according to the JSON RFC, but some
// consumers need the parsing leniency, so handle accordingly.
if (token.type == Token::ARRAY_END) {
if (!allow_trailing_comma_) {
SetErrorCode(JSON_TRAILING_COMMA, json_pos_);
return NULL;
}
// Trailing comma OK, stop parsing the Array.
break;
}
} else if (token.type != Token::ARRAY_END) {
// Unexpected value after list value. Bail out.
return NULL;
}
}
if (token.type != Token::ARRAY_END) {
return NULL;
}
break;
}
//对象
case Token::OBJECT_BEGIN:
{
json_pos_ += token.length;
token = ParseToken();
node.reset(new DictionaryValue);
while (token.type != Token::OBJECT_END) {
if (token.type != Token::STRING) {
SetErrorCode(JSON_UNQUOTED_DICTIONARY_KEY, json_pos_);
return NULL;
}
scoped_ptr<Value> dict_key_value(DecodeString(token));
if (!dict_key_value.get())
return NULL;
// Convert the key into a wstring.
std::string dict_key;
bool success = dict_key_value->GetAsString(&dict_key);
DCHECK(success);
json_pos_ += token.length;
token = ParseToken();
if (token.type != Token::OBJECT_PAIR_SEPARATOR)
return NULL;
json_pos_ += token.length;
token = ParseToken();
Value* dict_value = BuildValue(false);
if (!dict_value)
return NULL;
static_cast<DictionaryValue*>(node.get())->SetWithoutPathExpansion(
dict_key, dict_value);
// After a key/value pair, we expect a comma or the end of the
// object.
token = ParseToken();
if (token.type == Token::LIST_SEPARATOR) {
json_pos_ += token.length;
token = ParseToken();
// Trailing commas are invalid according to the JSON RFC, but some
// consumers need the parsing leniency, so handle accordingly.
if (token.type == Token::OBJECT_END) {
if (!allow_trailing_comma_) {
SetErrorCode(JSON_TRAILING_COMMA, json_pos_);
return NULL;
}
// Trailing comma OK, stop parsing the Object.
break;
}
} else if (token.type != Token::OBJECT_END) {
// Unexpected value after last object value. Bail out.
return NULL;
}
}
if (token.type != Token::OBJECT_END)
return NULL;
break;
}
default:
// We got a token that's not a value.
return NULL;
}
json_pos_ += token.length;
--stack_depth_;
return node.release();
}
3)函数ParseToken()的实现:
JSONReader::Token JSONReader::ParseToken() {
EatWhitespaceAndComments();
Token token(Token::INVALID_TOKEN, 0, 0);
switch (*json_pos_) {
//当前字符为’\0‘,返回Token:END_OF_INPUT(输入结束)
case '\0':
token.type = Token::END_OF_INPUT;
break;
//匹配空指针
case 'n':
if (NextStringMatch(kNullString, arraysize(kNullString) - 1))
token = Token(Token::NULL_TOKEN, json_pos_, 4);
break;
//匹配布尔值true
case 't':
if (NextStringMatch(kTrueString, arraysize(kTrueString) - 1))
token = Token(Token::BOOL_TRUE, json_pos_, 4);
break;
//匹配布尔值false
case 'f':
if (NextStringMatch(kFalseString, arraysize(kFalseString) - 1))
token = Token(Token::BOOL_FALSE, json_pos_, 5);
break;
//匹配右中括号,返回数组类型序列
case '[':
token = Token(Token::ARRAY_BEGIN, json_pos_, 1);
break;
case ']':
token = Token(Token::ARRAY_END, json_pos_, 1);
break;
case ',':
token = Token(Token::LIST_SEPARATOR, json_pos_, 1);
break;
//匹配对象序列
case '{':
token = Token(Token::OBJECT_BEGIN, json_pos_, 1);
break;
case '}':
token = Token(Token::OBJECT_END, json_pos_, 1);
break;
case ':':
token = Token(Token::OBJECT_PAIR_SEPARATOR, json_pos_, 1);
break;
//匹配数字序列
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
token = ParseNumberToken();
break;
//匹配字符串序列
case '"':
token = ParseStringToken();
break;
}
return token;
}
阅读上述代码可知,函数JsonToValue中调用了函数BuildValue,函数BuildValue依据字符串json的Token类型(字符串、数字、数组或者是对象),来最终给出字符串json反序列化后的Value类型。
【参考文献】
1)http://laichendong.com/rfc4627-zh_cn/
2)http://www.rfc-editor.org/rfc/rfc4627.txt