json 关键原理简述
json可以是null,bool,int, double,string,array,object几个不同类型;
其中,array=vector<json>; object=map<string,json>;
所以 json 是一个多种子类的基类,代码中为 Value;
class Value
{
public:
enum Type
{
NUL,
INT,
DOUBLE,
BOOL,
STRING,
OBJECT,
ARRAY,
};
public:
Value(Type type)
:type_(type)
{
}
virtual std::pair<bool, int> IntValue() const
{
return std::make_pair(false, 0);
}
virtual std::pair<bool, double> DoubleValue() const
{
return std::make_pair(false, 0);
}
virtual std::pair<bool, bool> BoolValue() const
{
return std::make_pair(false, true);
}
virtual std::pair<bool, std::string> StrValue() const
{
return std::make_pair(false, "null string");
}
//virtual Object ObjectValue() const;
//virtual Array ArrayValue() const ;
virtual std::pair<bool, const Json& > at(const std::string& key) const;
virtual std::pair<bool, const Json& > at(size_t i)const;
virtual std::string GetRawStr() const=0;
Type GetType()
{
return type_;
}
private:
Type type_;
};
value具有所有子类的基本函数,子类(null,bool,int, double,string,array,object)通过重写自己的函数,使得value的虚函数具有实际的意义,即返回正确的结果<true,value>。
value的子类是json类的数据成员,通过一层封装,消除不同json类型的构建的差异性,可以通过初始化列表,完成一个复杂json对象的构建。json类还提供解析字符串为json对象的功能,该功能也通过JsonParser对象外包出去。因此Json只是一层皮。
字符串解析为json的过程
字符串解析分为两种模式,一种是带有注释的json字符串解析,一种是无注释。整个解析过程是一个流水线式的解析,通过当前符号区分当前要解析的内容是什么。
Json Parse(int depth)
{
if (depth > max_depth) {
return fail("exceeded maximum nesting depth");
}
char ch = GetNextToken();
if (failed_)
return Json();
if (ch == '-' || (ch >= '0' && ch <= '9')) {
i--;
return ParseNumber();
}
if (ch == 't')
return expect("true", true);
if (ch == 'f')
return expect("false", false);
if (ch == 'n')
return expect("null", Json());
if (ch == '"')
return ParseString();
if (ch == '{') {
Object data;
ch = GetNextToken();
if (ch == '}')
return data;
while (1) {
if (ch != '"')
//return fail("expected '\"' in object, got " + esc(ch));
return fail("expected '\"' in object, got " + ch);
std::string key = ParseString();
if (failed_)
return Json();
ch = GetNextToken();
if (ch != ':')
//return fail("expected ':' in object, got " + esc(ch));
return fail("expected ':' in object, got " + ch);
data[std::move(key)] = Parse(depth + 1);
if (failed_)
return Json();
ch = GetNextToken();
if (ch == '}')
break;
if (ch != ',')
//return fail("expected ',' in object, got " + esc(ch));
return fail("expected ',' in object, got " + ch);
ch = GetNextToken();
}
return data;
}
if (ch == '[') {
Array data;
ch = GetNextToken();
if (ch == ']')
return data;
while (1) {
i--;
data.push_back(Parse(depth + 1));
if (failed_)
return Json();
ch = GetNextToken();
if (ch == ']')
break;
if (ch != ',')
//return fail("expected ',' in list, got " + esc(ch));
return fail("expected ',' in list, got " + ch);
ch = GetNextToken();
(void)ch;
}
return data;
}
//return fail("expected value, got " + esc(ch));
return fail("expected value, got " + ch);
}
主要部分object和array类型的解析都是递归的过程。
关键函数解析
解析过程中出现错误怎么处理?
Json fail(std::string&& msg) {
return fail(move(msg), Json());
}
template <typename T>
T fail(std::string&& msg, const T err_ret) {
if (!failed_)
err_ = std::move(msg);
failed_ = true;
return err_ret;
}
解析过程中出现错误往往要返回一个值,用户通过返回值判断该解析过程或者子解析过程是否出现错误。这是json11处理方式,通过模板可以返回不同的类型满足各部分解析返回值需求,并且生成错误信息。
解析特定类型的函数抽象
Json expect(const std::string& expected, Json res) {
if (i == 0)
{
return fail("expect wrong i(position of str_)", Json());
}
i--;
if (str_.compare(i, expected.length(), expected) == 0) {
i += expected.length();
return res;
}
else {
return fail("parse error: expected " + expected + ", got " + str_.substr(i, expected.length()));
}
}
在对bool和null类型解析是一个类似的过程,采用expect()进行抽象,一个string对应一个json对象。
json对象字符串的输出
不同json类型有不同的字符串输出方式,并且和解析一样存在递归调用如果都放到自己的成员函数下,递归调用就成问题。因此将字符串输出代理给RawStr类。RawStr具有一系列static的GetRawStr()函数,彼此间相互调用。
另一种还是将字符串输出放到各类型内部,递归调用时,通过构建临时Json对象,递归调用获取json字符串的函数。
参考
大部分源码来源于json11,进行了自己的阅读理解,用简单的方式组合在一起,并去除了编码相关的模块,不考虑编码的问题。
源码
|