本文将会刨析我写的库,Simple JSON的实现,Simple JSON 的实现非常简单,只有一个 hpp 文件;下面是一个使用 Simple JSON 解析文件的实例:
#include "sJson.hpp"
int main()
{
sJSONParser Parser(R"({
"sites": [
{ "name":"codeforce" , "url":"www.codeforces.com", "rank":3 },
{ "name":"google" , "url":"www.google.com", "rank":2 },
{ "name":"github" , "url":"www.github.com", "rank":1 }
]
})");
// 解析 JSON
auto Root = Parser.Parse();
// 序列化 JSON 对象
printf("JSON in format : %s\n", sJSONWriter::WriteJSON(Root).c_str());
printf("JSON in not format : %s\n\n", sJSONWriter::WriteJSON(Root, false).c_str());
// 读取 JSON 文件
for (auto Object = Root["sites"].ArrayBegin(); Object != Root["sites"].ArrayEnd(); ++Object)
{
auto ObjectExpand = sJSONElementFinder((*Object)->To<sJSONObject*>());
for (auto Instance : ObjectExpand)
{
printf("<%s, ", Instance.first.c_str());
if (sJSONString::Equal(**Instance.second)) {
printf("%s> ", (**Instance.second->To<sJSONString*>()).c_str());
}
if (sJSONInt::Equal(**Instance.second)) {
printf("%d> ", **Instance.second->To<sJSONInt*>());
}
}
printf("\n");
}
return 0;
}
上面的代码会输出:
JSON in format : {
"sites":[
{
"name":"codeforce",
"rank":3,
"url":"www.codeforces.com"
},
{
"name":"google",
"rank":2,
"url":"www.google.com"
},
{
"name":"github",
"rank":1,
"url":"www.github.com"
}
]
}
JSON in not format : {"sites":[{"name":"codeforce","rank":3,"url":"www.codeforces.com"},{"name":"google","rank":2,"url":"www.google.com"},{"name":"github","rank":1,"url":"www.github.com"}]}
<name, codeforce> <rank, 3> <url, www.codeforces.com>
<name, google> <rank, 2> <url, www.google.com>
<name, github> <rank, 1> <url, www.github.com>
本文会以此代码为切入点去解析 Simple JSON 的实现
让我们来关注 sJSONParser 的构造函数 sJSONParser::sJSONParser
。
sJSONParser(std::string Code) : RootObject(new sJSONObject()), Lexer(Code, &Status)
{
}
可以看到 sJSONParser 中初始化了一个对象 RootObject
和 Lexer
对象,先关注 RootObject
对象,查看发现 RootObject
的类型为 sJSONObject
,而 RootObject
则是代表 JSON 树的根节点。
这里再先说一下 Parser 的大概工作原理,Parser 实际上做的工作便是将 JSON 代码转换为一个树形结构储存在内存中,这个其实就是树其实就是 AST(Abstract Syntax Tree)抽象语法树,事实上生成 AST 树在现代语言中只不过是一个最上层的一环,但是在 JSON 的读取中我们只需要获得一个 AST 树就可以了。
再来说一些性内容:
{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}
在上面这个例子中,形如 "glossary"
,"GlossDef"
的称之为键(Key),而引号过后接着的一律称为值(Value),一堆值和键称为键值对。
回过头来,再来关注 sJSONObject 的定义(此处略去一些成员函数):
/**
* sJSON 树节点
*/
typedef class sJSONElementNode : public sJSONValue
{
public:
sJSONElementNode()
{
Value = nullptr;
}
sJSONElementNode(const std::string &Tag, sJSONValue *Value)
{
this->Tag = Tag;
this->Value = Value;
}
sJSONElementNode(std::map<std::string, sJSONElementNode *> SetChildren) : Children(SetChildren), Value(nullptr)
{
}
public:
sJSONValue *Value;
std::string Tag;
std::map<std::string, sJSONElementNode *> Children;
} sJSONObject;
可以看到 sJSONObject
实际上只是 sJSONElementNode
的别名,其继承自 sJSONValue
,所以说,sJSONObject 实际上是一个值,之所以这么设计是因为在 JSON 中一个键对应的值可以是一个对象,而一个对象又包含很多值对,所以对于一个对象值其在代码实现中既可以做值也可以做 AST 节点也可以做值。
而 sJSONElementNode::Tag
则就是这个节点的键名(如果该节点有键名)。
sJSONObject
中还有一个指针 Value
,这便是当前节点的值,这或许有点绕,这个类本身可以作为一个值,但是其又可以有一个值,难道是值中套了个值?实则不然,这个 Value
仅在当当前对象表示为 sJSONElementNode
的时候有效,而当其表示为一个值的时候是无效的,sJSONElementNode
中的三个构造函数就对应了这两种情况。
那么 sJSONObject
所继承的 sJSONValue
是什么呢,跳转到 sJSONValue
的定义如下:
/**
* sJSON 值的基类
*/
class sJSONValue
{
public:
sJSONValue() = default;
~sJSONValue() = default;
public:
virtual __forceinline const sJSONValueType GetType() const = 0;
virtual __forceinline const size_t GetHash() const
{
return 0;
}
template <class Object> Object To()
{
return static_cast<Object>(this);
}
};
这个类的定义非常简单,sJSONValue
其实就是一个抽象的基类,其就是 JSON 的值,其中有一个纯虚函数 sJSONValue::GetType
和一个默认返回 0 的虚函数 sJSONValue::GetHash
,先不管 sJSONVaue::GetHash
函数,先来看 sJSONValue::GetType
其返回一个 sJSONValueType
,代表当前值的类型,sJSONValueType
的定义如下:
/**
* sJSON 对象值的类型
*/
enum class sJSONValueType
{
Value,
Array,
Object,
Null
};
对象类型分为:实值、数组、对象、空,后三个很好理解,实值是什么意思呢?在 Simple JSON 中,将所有的实际值(例如数字,字符串,布尔值)都抽象成为了实值,实值没有对应的类型的实现,只有一个模板类如下:
/**
* sJSON 中的实值
*/
template <class Type> class sJSONRealValue : public sJSONValue
{
public:
sJSONRealValue(const Type &SetValue) : Value(SetValue)
{
}
~sJSONRealValue() = default;
__forceinline sJSONValueType const GetType() const override
{
return sJSONValueType::Value;
}
__forceinline const size_t GetHash() const override
{
return typeid(Type).hash_code();
}
static constexpr bool Equal(const sJSONValue *Judgement)
{
if (Judgement->GetType() != sJSONValueType::Value)
{
return false;
}
else
{
return Judgement->GetHash() == typeid(Type).hash_code();
}
}
Type operator*()
{
return Value;
}
public:
Type Value;
};
using sJSONString = sJSONRealValue<std::string>;
using sJSONInt = sJSONRealValue<int>;
using sJSONDouble = sJSONRealValue<double>;
using sJSONBoolean = sJSONRealValue<bool>;
所以在 Simple JSON 中所有实值类型其实都是模板类 sJSONRealValue
的别名而已,而在 sJSONRealValue::GetHash
中使用了 C++ 中提供的 typeid
来返回当前类型的哈希值,以用来内部区分不同的实值类型。