利用C++编写一个Json解析器
作者:draracle
这篇文章主要为大家详细介绍了如何利用C++编写一个简单又好用的Json解析器,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
之前用RapidJson来做json的解析,但是,RapidJson还是有麻烦的地方,虽然速度非常快,但是由于用了非常多的优化技巧,反而无法做到我想要的那种简便的访问方式。
比如,有这么一个字符串:
"{ \"a\":1000,\"b\":30000,\"c\":[123,456,789,5555, 1.0e2, true, false, null, \"test\", \"big big world\"]}"
我在C++里面需要非常简单的使用它,例如这样:
static char text[] = "{ \"a\":1000,\"b\":30000,\"c\":[123,456,789,5555, 1.0e2, true, false, null, \"test\", \"big big world\"]}"; atom::CJson root = text; root["a"] = 123; root["c"] = true; root["b"] = "b is the biggest"; atom::CJson test = "{\"new key\": 1037, 'test-key':1234e-5, 'array':[1,2,3,1,1,0] }"; root["e"] = test; test["array"][0] = 1000; atom::a_string value = root.Stringity(); printf( "%s\n", value.c_str() );
而输出结果如下:
{"a":123, "b":"b is the biggest", "c":1, "e":{"new key":1037, "test-key":0.012340, "array":[1000, 2, 3, 1, 1, 0, ], }, }
找了几个Json库,似乎都没有我想要的那种效果。快的访问很麻烦,访问方便点的速度又上不去。后来还是决定自己写一个。
自己写出来后,测试了一下,在不开优化的情况下,时间开销大概是RapidJson的8倍,如果开编译器优化,则时间开销是RapidJson的4倍左右。其实还是有可以再优化的地方,但再优化就必须要损失易用性为代价。想了一下,还是放弃了,这个解析速度和访问的方便程度我已经很满意了。
而且我自己写的Json还能支持序列化到流数据,如果采用这个方式,恢复的速度和RapidJson的解析差不多。
代码如下:有兴趣的可以参考。
tokenizer数据结构的头文件和cpp文件
#ifndef TAGJSONTOKEN_H #define TAGJSONTOKEN_H //Begin section for file tagJsonToken.h //TODO: Add definitions that you want preserved //End section for file tagJsonToken.h #include "../stl/a_string.h" #include "../stl/allocator.h" #include "../tool/CVariablePtr.h" namespace atom { //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" struct tagJsonToken { //Begin section for atom::tagJsonToken //TODO: Add attributes that you want preserved //End section for atom::tagJsonToken public: //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" //typedef CVariablePtr<tagJsonToken> Ptr ; //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" typedef vector<tagJsonToken, atom_allocator<tagJsonToken> > Array ; public: //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" U32 token; //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" size_t start; //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" size_t close; //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" tagJsonToken(); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" tagJsonToken(const tagJsonToken & value); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" tagJsonToken(U32 token); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" tagJsonToken(U32 token, size_t start, size_t close); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" ~tagJsonToken(); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" tagJsonToken & operator=(const tagJsonToken & value); }; //end struct tagJsonToken } //end namespace nova #endif
#include "tagJsonToken.h" //Begin section for file tagJsonToken.cpp //TODO: Add definitions that you want preserved //End section for file tagJsonToken.cpp //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::tagJsonToken::tagJsonToken() : token(0),start(0),close(0) { //TODO Auto-generated method stub } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::tagJsonToken::tagJsonToken(const tagJsonToken & in) : token(in.token),start(in.start),close(in.close) { //TODO Auto-generated method stub } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::tagJsonToken::tagJsonToken(U32 t) : token(t),start(0),close(0) { //TODO Auto-generated method stub } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::tagJsonToken::tagJsonToken(U32 t, size_t s, size_t c) : token(t),start(s),close(c) { //TODO Auto-generated method stub } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::tagJsonToken::~tagJsonToken() { //TODO Auto-generated method stub } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::tagJsonToken & atom::tagJsonToken::operator=(const tagJsonToken & in) { //TODO Auto-generated method stub token = in.token; start = in.start; close = in.close; return( * this ); }
json节点的头文件和cpp文件
#ifndef TAGJSONKEYVALUE_H #define TAGJSONKEYVALUE_H //Begin section for file tagJsonKeyValue.h //TODO: Add definitions that you want preserved //End section for file tagJsonKeyValue.h #include "../stl/a_string.h" #include "../stl/stl_extend.h" #include "../variant/CVariant.h" #include "../tool/CVariablePtr.h" namespace atom { //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" struct tagJsonKeyValue { //Begin section for atom::tagJsonKeyValue //TODO: Add attributes that you want preserved //End section for atom::tagJsonKeyValue public: //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" typedef CVariablePtr<tagJsonKeyValue> Ptr ; //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" typedef vector<pair<size_t, tagJsonKeyValue::Ptr>, atom_allocator<pair<size_t, tagJsonKeyValue::Ptr> > > Array ; public: //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" a_string index; //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" CVariant value; //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" Array group; //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" //Map query; //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" tagJsonKeyValue(); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" tagJsonKeyValue(const char * value); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" tagJsonKeyValue(const CVariant & data); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" tagJsonKeyValue(const char * value, const CVariant & data); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" tagJsonKeyValue(const tagJsonKeyValue & value); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" ~tagJsonKeyValue(); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" tagJsonKeyValue & operator=(const tagJsonKeyValue & value); }; //end struct tagJsonKeyValue } //end namespace atom template<class Archive> inline void Serialize(Archive & archive, atom::tagJsonKeyValue & value, bool isSave) { UNREFERENCED_PARAMETER( isSave ); archive.Bind( value.index ); archive.Bind( value.value ); archive.Bind( value.group ); } #endif
#include "tagJsonKeyValue.h" //Begin section for file tagJsonKeyValue.cpp //TODO: Add definitions that you want preserved //End section for file tagJsonKeyValue.cpp //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::tagJsonKeyValue::tagJsonKeyValue() { //TODO Auto-generated method stub } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::tagJsonKeyValue::tagJsonKeyValue(const char * in): index(in ? in : "") { //TODO Auto-generated method stub } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::tagJsonKeyValue::tagJsonKeyValue(const CVariant & in) : value(in) { //TODO Auto-generated method stub } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::tagJsonKeyValue::tagJsonKeyValue(const char * in_1, const CVariant & in_2) : index(in_1 ? in_1 : ""),value(in_2) { //TODO Auto-generated method stub } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::tagJsonKeyValue::tagJsonKeyValue(const tagJsonKeyValue & in) : index(in.index),value(in.value),group(in.group) { //TODO Auto-generated method stub } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::tagJsonKeyValue::~tagJsonKeyValue() { //TODO Auto-generated method stub } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::tagJsonKeyValue & atom::tagJsonKeyValue::operator=(const tagJsonKeyValue & in) { //TODO Auto-generated method stub index = in.index; value = in.value; group = in.group; return( * this ); }
接下来是 Tokenizer 的实现
#include "CJsonTokenizer.h" #include "../../enumeration/JSON_TOKEN.h" //Begin section for file CJsonTokenizer.cpp //TODO: Add definitions that you want preserved //End section for file CJsonTokenizer.cpp //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::CJsonTokenizer::CJsonTokenizer() { //TODO Auto-generated method stub tokens.reserve( 1024 ); } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::CJsonTokenizer::~CJsonTokenizer() { //TODO Auto-generated method stub } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool atom::CJsonTokenizer::Start(const char * json) { //TODO Auto-generated method stub if( json == NULL ) { return false; } size_t offset = 0; size_t length = strlen( json ); buffer.Alloc( length ); if( buffer ) { buffer.Store( json, length ); } bool result = true; for( ;; ) { // skip any reserved or space characters. for( ; IsSpace(json, offset, length); ++ offset ); // offset check if( offset >= length ) { tokens.push_back( tagJsonToken() ); tokens.back().token = JT_END; break; } char c = json[offset]; // create token if( IsNull(json, offset, length) ) { offset += 4; tokens.push_back( tagJsonToken(JT_NULL) ); } else if( c == ',' ) { offset += 1; tokens.push_back( tagJsonToken(JT_COMMA) ); } else if( c == ':' ) { offset += 1; tokens.push_back( tagJsonToken(JT_COLON) ); } else if( c == '{' ) { offset += 1; tokens.push_back( tagJsonToken(JT_OBJECT_BEGIN) ); } else if( c == '[' ) { offset += 1; tokens.push_back( tagJsonToken(JT_ARRAY_BEGIN) ); } else if( c == ']' ) { offset += 1; tokens.push_back( tagJsonToken(JT_ARRAY_CLOSE) ); } else if( c == '}' ) { offset += 1; tokens.push_back( tagJsonToken(JT_OBJECT_CLOSE) ); } else if( IsTrue(json, offset, length) ) { offset += 4; tokens.push_back( tagJsonToken(JT_BOOL, 1, 0) ); } else if( IsFalse(json, offset, length) ) { offset += 5; tokens.push_back( tagJsonToken(JT_BOOL) ); } else if( c == '\'' || c == '\"' ) { // read string will modify the offset; size_t start(0), close(0); ReadString( json, offset, length, start, close ); if( start == 0 || close == 0 || close <= start ) { char msg[32]; sprintf( msg, "%zu", offset ); errmsg = "Failed read string from offset "; errmsg = errmsg + msg; tokens.clear(); result = false; break; } tokens.push_back( tagJsonToken(JT_STRING, start, close) ); } else if( IsNumber(json, offset, length) ) { size_t start(0), close(0); ReadNumber( json, offset, length, start, close ); // read number will modify the offset; if( start == 0 || close == 0 || close <= start ) { char msg[32]; sprintf( msg, "%zu", offset ); errmsg = "Failed read number from offset "; errmsg = errmsg + msg; tokens.clear(); result = false; break; } tokens.push_back( tagJsonToken(JT_NUMBER, start, close) ); } else { char msg[32]; sprintf( msg, "%zu", offset ); errmsg = "Invalid char at offset "; errmsg = errmsg + msg; tokens.clear(); result = false; break; } } return result; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool atom::CJsonTokenizer::IsNull(const char * json, size_t & offset, size_t length) { //TODO Auto-generated method stub bool result = false; if( json ) { // length must enough. if( (length - offset) + 1 >= 4 ) { const char * site = json + offset; if( *site == 'n' || *site == 'N' ) { ++ site; if( *site == 'u' || *site == 'U' ) { ++ site; if( *site == 'l' || *site == 'L' ) { ++ site; if( *site == 'l' || *site == 'L' ) { result = true; } } } } } } return result; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool atom::CJsonTokenizer::IsTrue(const char * json, size_t & offset, size_t length) { //TODO Auto-generated method stub bool result = false; if( json ) { // length must enough. if( (length - offset) + 1 >= 4 ) { const char * site = json + offset; if( *site == 't' || *site == 'T' ) { ++ site; if( *site == 'r' || *site == 'R' ) { ++ site; if( *site == 'u' || *site == 'U' ) { ++ site; if( *site == 'e' || *site == 'E' ) { result = true; } } } } } } return result; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool atom::CJsonTokenizer::IsFalse(const char * json, size_t & offset, size_t length) { //TODO Auto-generated method stub bool result = false; if( json ) { // length must enough. if( (length - offset) + 1 >= 5 ) { const char * site = json + offset; if( *site == 'f' || *site == 'F' ) { ++ site; if( *site == 'a' || *site == 'A' ) { ++ site; if( *site == 'l' || *site == 'L' ) { ++ site; if( *site == 's' || *site == 'S' ) { ++ site; if( *site == 'e' || *site == 'E' ) { result = true; } } } } } } } return result; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool atom::CJsonTokenizer::IsSpace(const char * json, size_t & offset, size_t length) { //TODO Auto-generated method stub if( !json ) { return false; } bool result = false; if( offset < length ) { if( json[offset] <= 0x20 ) { result = true; } } return result; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool atom::CJsonTokenizer::IsNumber(const char * json, size_t & offset, size_t length) { //TODO Auto-generated method stub if( !json ) { return false; } bool result = false; if( offset < length ) { char c = json[offset]; result = IsDigit( c ) || c == '-'; } return result; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool atom::CJsonTokenizer::IsEscape(const char * json, size_t & offset, size_t length) { //TODO Auto-generated method stub if( !json ) { return false; } bool result = false; if( offset < length ) { char c = json[offset]; if( c == '\"' || c == '\\' || c == '/' || c == 'b' || c == 'f' || c == 'n' || c == 't' || c == 'r' || c == 'u' ) { result = true; } } return result; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool atom::CJsonTokenizer::ReadNumber(const char * json, size_t & offset, size_t length, size_t & start, size_t & close) { //TODO Auto-generated method stub if( !json ) { return false; } if( offset >= length ) { return false; } size_t backup = offset; start = offset; close = offset; if( json[offset] == '-' ) { ++ close; ++ offset; } char c = 0; bool succeed = true; // read integer part size_t bias(0); bool stop(false); for( ;; ++ bias ) { if( offset == length ) { break; } if( offset > length ) { succeed = false; break; } c = json[offset]; // stop flag if( stop == true ) { break; } // if 0 is the first digit. if( bias == 0 && c == '0' ) { ++ close; ++ offset; stop = true; continue; } if( IsDigit(c) ) { ++ close; ++ offset; continue; } // The first char is illegal, set failed. if( bias == 0 ) { succeed = false; } // if c is not digit, break; break; } if( succeed && offset == length ) { return true; } // read frac part if( succeed && c == '.' ) { ++ close; ++ offset; bias = 0; for( ;; ++ bias ) { if( offset == length ) { break; } if( offset > length ) { succeed = false; break; } c = json[offset]; if( IsDigit(c) ) { ++ close; ++ offset; continue; } if( bias == 0 ) { succeed = false; } // if c is not digit, break; break; } } if( succeed && offset == length ) { return true; } // read exp part if( succeed && ( c == 'e' || c == 'E' ) ) { ++ close; ++ offset; bias = 0; for( ;; ++ bias ) { if( offset == length ) { break; } if( offset > length ) { succeed = false; break; } c = json[offset]; if( c == '-' ) { if( bias == 0 ) { ++ close; ++ offset; continue; } else { succeed = false; break; } } if( IsDigit(c) ) { ++ close; ++ offset; continue; } if( bias == 0 ) { succeed = false; } // if c is not digit, break; break; } } if( succeed == false ) { offset = backup; start = close = 0; } return succeed; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool atom::CJsonTokenizer::ReadString(const char * json, size_t & offset, size_t length, size_t & start, size_t & close) { //TODO Auto-generated method stub if( !json ) { return false; } if( offset >= length ) { return false; } size_t backup = offset; char quotation = 0; if (json[offset] == '\"' || json[offset] == '\'') { quotation = json[offset ++]; } start = close = offset; char c; bool succeed = true; for( ;; ) { // check the offset. if( offset >= length ) { succeed = false; break; } c = json[offset ++]; // is escpae ? if( c == '\\' ) { if( !IsEscape(json, offset, length) ) { succeed = false; break; } ++ close; // because the IsEscape function already verified the // offset range. so, here's offset is valid. c = json[offset ++]; ++ close; // Process Unicode,from \u0000 to \uffff if( c == 'u' ) { // memory border check if( length - offset + 1 < 4 ) { succeed = false; break; } for( size_t i = 0; i < 4; ++ i ) { c = json[offset ++]; if( IsHex(c) ) { ++ close; } else { succeed = false; break; } } // if failed to process Unicode, stop the main loop. if( !succeed ) break; } } // another quotation ? else if( c == quotation ) { break; } else if( c == '\r' || c == '\n') { succeed = false; break; } else { ++ close; } } // 如果失败,则清理现场 if( succeed == false ) { offset = backup; start = close = 0; } return succeed; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::tagJsonToken::Array & atom::CJsonTokenizer::GetTokens() { //TODO Auto-generated method stub return tokens; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::a_string atom::CJsonTokenizer::GetError() { //TODO Auto-generated method stub return errmsg; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" const char * atom::CJsonTokenizer::GetString(size_t start, size_t close) { //TODO Auto-generated method stub static char text[] = ""; size_t length = buffer.GetLength(); if( start < length && close < length && close > start ) { buffer.Query<char>()[close] = 0; return & buffer.Query<char>()[start]; } return text; }
Parser的实现:
#include "CJsonParser.h" #include "CJsonTokenizer.h" #include "../stl/string_splite.h" #include "../../enumeration/JSON_TOKEN.h" //Begin section for file CJsonParser.cpp //TODO: Add definitions that you want preserved //End section for file CJsonParser.cpp //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::CJsonParser::CJsonParser() { //TODO Auto-generated method stub } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::CJsonParser::~CJsonParser() { //TODO Auto-generated method stub } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool atom::CJsonParser::Parse(const char * text, CJson & json) { //TODO Auto-generated method stub if( text == NULL ) { error = "Invalid arguments"; return false; } bool result = false; CJsonTokenizer tokenizer; if( tokenizer.Start(text) == false ) { error = tokenizer.GetError(); return false; } if( tokenizer.GetTokens().empty() ) { error = "Empty json string"; return false; } size_t offset = 0; U32 begin_token = tokenizer.GetTokens().front().token; if( begin_token == JT_ARRAY_BEGIN ) { result = ParseArray ( tokenizer, offset, json ); } else if( begin_token == JT_OBJECT_BEGIN ) { result = ParseObject ( tokenizer, offset, json ); } else if( IsPrimary(begin_token) ) { CVariant data; result = ParsePrimary( tokenizer, offset, data ); if( result ) { // 一开始就是原型的字符串必须立即结束 if( tokenizer.GetTokens().size() <= offset || tokenizer.GetTokens().at(offset).token == JT_END ) { json = data; } else { error = "Json should ended after the 1st element"; result = false; } } } return result; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::a_string atom::CJsonParser::GetError() { //TODO Auto-generated method stub return error; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool atom::CJsonParser::IsPrimary(U32 type) { //TODO Auto-generated method stub return type == JT_BOOL || type == JT_NULL || type == JT_NUMBER || type == JT_STRING; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool atom::CJsonParser::ParseArray(CJsonTokenizer & tokenizer, size_t & offset, CJson & node) { //TODO Auto-generated method stub tagJsonToken::Array & tokens = tokenizer.GetTokens(); if( offset >= tokens.size() ) { error = "Invalid offset"; return false; } if( tokens[offset].token != JT_ARRAY_BEGIN ) { error = "Invalid array token"; return false; } size_t backup = offset; // consume [ ++ offset; bool result = true; for( ;; ) { if( offset >= tokens.size() ) { error = "Tokens not complete"; result = false; break; } if( tokens[offset].token == JT_ARRAY_CLOSE ) { ++ offset; // consume ] break; } if( tokens[offset].token == JT_ARRAY_BEGIN ) { CJson data; if( false == ParseArray(tokenizer, offset, data) ) { result = false; break; } node.Push( data ); } else if( tokens[offset].token == JT_OBJECT_BEGIN ) { CJson data; if( false == ParseObject(tokenizer, offset, data) ) { result = false; break; } node.Push( data ); } else if( tokens[offset].token == JT_COMMA ) { ++ offset; } else if( IsPrimary(tokens[offset].token) ) { CVariant data; if( false == ParsePrimary(tokenizer, offset, data) ) { result = false; break; } node.Push( data ); } else { error = "Invalid token in array"; result = false; break; } } if( result == false ) { offset = backup; } return result; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool atom::CJsonParser::ParseObject(CJsonTokenizer & tokenizer, size_t & offset, CJson & node) { //TODO Auto-generated method stub tagJsonToken::Array & tokens = tokenizer.GetTokens(); if( offset >= tokens.size() ) { error = "Invalid offset"; return false; } if( tokens[offset].token != JT_OBJECT_BEGIN ) { error = "Invalid object token"; return false; } size_t backup = offset; // consume { ++ offset; bool result = true; for( ;; ) { if( offset >= tokens.size() ) { error = "Tokens not complete"; result = false; break; } if( tokens[offset].token == JT_OBJECT_CLOSE ) { ++ offset; // consume } break; } if( tokens[offset].token == JT_COMMA ) { ++ offset; // consume , continue; } // 读key,key必须是string类型 if( tokens[offset].token != JT_STRING ) { error = "Invalid key token type"; result = false; break; } // 创建对象的键值对。 CJson value = node[ tokenizer.GetString( tokens[offset].start, tokens[offset].close)]; ++ offset; if( offset >= tokens.size() ) { error = "Tokens not complete"; result = false; break; } if( tokens[offset].token != JT_COLON ) { error = "Invalid splite token type"; result = false; break; } ++ offset; // consume : if( offset >= tokens.size() ) { error = "Tokens not complete"; result = false; break; } if( IsPrimary(tokens[offset].token) ) { CVariant data; if( false == ParsePrimary(tokenizer, offset, data) ) { result = false; break; } value = data; } else if( tokens[offset].token == JT_ARRAY_BEGIN ) { CJson data; if( false == ParseArray(tokenizer, offset, data) ) { result = false; break; } value = data; } else if( tokens[offset].token == JT_OBJECT_BEGIN ) { CJson data; if( false == ParseObject(tokenizer, offset, data) ) { result = false; break; } value = data; } else { error = "Invalid value token type"; result = false; break; } } if( result == false ) { offset = backup; } return result; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool atom::CJsonParser::ParsePrimary(CJsonTokenizer & tokenizer, size_t & offset, CVariant & data) { //TODO Auto-generated method stub tagJsonToken::Array & tokens = tokenizer.GetTokens(); if( offset >= tokens.size() ) { error = "Invalid offset"; return false; } bool result = true; switch( tokens[offset].token ) { case JT_NUMBER: { const char * value = tokenizer.GetString( tokens[offset].start, tokens[offset].close ); size_t length = strlen( value ); size_t splite = 0; for( size_t i = 0; i < length; ++ i ) { if( value[i] == 'e' || value[i] == 'E' ) { splite = i; } } // only one part. if( length > 0 ) { // 先计算指数 char * stop = NULL; I64 exp = 0; if( splite != 0 ) { #if defined(_WIN32) exp = static_cast<I64>( _strtoi64( & value[splite + 1], & stop, 10 ) ); #else exp = static_cast<I64>( strtoll ( & value[splite + 1], & stop, 10 ) ); #endif } if( splite == 0 ) { splite = length; } bool is_float = false; for( size_t i = 0; i < splite; ++ i ) { if( value[i] == '.' ) { is_float = true; } } // 再判断前面部分 if( is_float == false ) { #if defined(_WIN32) I64 integer = static_cast<I64>( _strtoi64( value, & stop, 10 ) ); #else I64 integer = static_cast<I64>( strtoll ( value, & stop, 10 ) ); #endif double range = integer * pow( 10, exp ); abs( range - static_cast<I64>(range) ) < 1e-6 ? data = static_cast<I64>(range): data = range; ++ offset; } else { double decimal = strtod( value, & stop ); double range = decimal * pow( 10, exp ); abs( range - static_cast<I64>(range) ) < 1e-6 ? data = static_cast<I64>(range): data = range; ++ offset; } } else { error = "Invalid number format"; result = false; } } break; case JT_STRING: { data = tokenizer.GetString( tokens[offset].start, tokens[offset].close ); ++ offset; } break; case JT_NULL: { data.Clear(); ++ offset; } break; case JT_BOOL: { bool value = tokens[offset ++].start == 1; data = value; } break; default: error = "Not primary"; result = false; break; } return result; }
最后的重点:CJson 类的实现:
#ifndef CJSON_H #define CJSON_H //Begin section for file CJson.h //TODO: Add definitions that you want preserved //End section for file CJson.h #include "tagJsonKeyValue.h" #include "../variant/CVariant.h" namespace atom { //<p>This class is not thread safe. Should used under critical section's protection.</p> //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" class CJson { //Begin section for atom::CJson //TODO: Add attributes that you want preserved //End section for atom::CJson private: //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" mutable tagJsonKeyValue::Ptr root; //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" mutable U08 type; //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" U08 CheckType(const tagJsonKeyValue::Ptr & node); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool Assign(U08 in_type, const tagJsonKeyValue::Ptr & in, bool & deep); public: //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" CJson(); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" CJson(const CJson & value); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" CJson(const tagJsonKeyValue::Ptr & value); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" CJson(const char * value); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" operator CVariant() const; //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" CJson & operator=(const CJson & value); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" CJson & operator=(const CVariant & value); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" CJson & operator=(const tagJsonKeyValue::Ptr & value); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" CJson & operator=(const char * value); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" CJson operator[](I32 offset); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" CJson operator[](size_t offset); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" CJson operator[](const char * index); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" size_t Length(); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" U08 GetType(); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool Push(const CVariant & data); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool Push(const CJson & data); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" a_string Stringity(); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" a_string Stringity(const tagJsonKeyValue::Ptr & value); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" CJson Clone(); //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" tagJsonKeyValue Clone(const tagJsonKeyValue::Ptr & value); template<class A> inline void Serialize(A & ar, bool save) { ar.Bind( type ); ar.Bind( root ); } }; //end class CJson } //end namespace atom #endif
#include "CJson.h" #include "CJsonParser.h" #include "../stl/stl_extend.h" #include "../../enumeration/JSON_VALUE_TYPE.h" #include "../../enumeration/VARIANT_TYPE.h" //Begin section for file CJson.cpp //TODO: Add definitions that you want preserved //End section for file CJson.cpp //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::CJson::CJson() : type(JVT_NONE) { //TODO Auto-generated method stub } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::CJson::CJson(const CJson & value) : root(value.root),type(value.type) { //TODO Auto-generated method stub } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::CJson::CJson(const tagJsonKeyValue::Ptr & value) : type(JVT_NONE) { //TODO Auto-generated method stub * this = value; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::CJson::CJson(const char * value) : type(JVT_NONE) { //TODO Auto-generated method stub * this = value; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool atom::CJson::Assign(U08 in_type, const tagJsonKeyValue::Ptr & in, bool & deep) { //TODO Auto-generated method stub if( root == NULL ) { root = tagJsonKeyValue(); } if( root == NULL ) { return false; } // 对不同的类型有不同的设置方式; // 此处是深度复制,是否需要浅层复制? deep = true; switch( type ) { case JVT_OBJECT: case JVT_ARRAY: root -> group.clear(); case JVT_NONE: case JVT_PRIMARY: root -> value.Clear(); root -> index = in -> index; root -> value = in -> value; root -> group = in -> group; type = in_type; break; case JVT_PAIR: switch( in_type ) { case JVT_NONE: case JVT_PRIMARY: root -> value.Clear(); if( in ) { root -> value = in -> value; type = JVT_PRIMARY; } break; case JVT_OBJECT: type = JVT_OBJECT; root -> group.clear(); if( in ) { root -> group = in -> group; } break; case JVT_ARRAY: type = JVT_ARRAY; root -> group.clear(); if( in ) { root -> group = in -> group; } break; case JVT_PAIR: type = JVT_OBJECT; root -> value.Clear(); root -> group.clear(); if( in ) { atom_hash<const char *> hasher; root -> group.push_back( make_pair( hasher( in -> index.c_str() ), in) ); // 唯有插入pair变成object时,才是浅层复制 deep = false; } } break; } return true; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::CJson & atom::CJson::operator=(const CJson & in) { //TODO Auto-generated method stub bool deep = false; if( Assign(in.type, in.root, deep) ) { if( deep ) { in.root -> index = root -> index; in.root -> value = root -> value; in.root -> group = root -> group; in.type = type; } } return( * this ); } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::CJson & atom::CJson::operator=(const tagJsonKeyValue::Ptr & in) { //TODO Auto-generated method stub // 该函数直接赋值,因为这个函数仅仅是在Parse时调用 root = in; type = CheckType( in ); return( * this ); } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::CJson & atom::CJson::operator=(const CVariant & value) { //TODO Auto-generated method stub // 如果为空,则赋予初值 if( root == NULL ) { root = tagJsonKeyValue(); } if( root == NULL ) { return( * this ); } // 对不同的类型有不同的设置方式; switch( type ) { case JVT_OBJECT: case JVT_ARRAY: root -> group.clear(); case JVT_NONE: case JVT_PRIMARY: root -> value = value; type = JVT_PRIMARY; break; case JVT_PAIR: root -> value = value; break; } return( * this ); } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::CJson & atom::CJson::operator=(const char * value) { //TODO Auto-generated method stub if( value ) { CJsonParser parser; CJson node; if( parser.Parse(value, node) ) { * this = node; } else { * this = CVariant( value ); } } return( * this ); } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::CJson atom::CJson::operator[](I32 offset) { //TODO Auto-generated method stub return this -> operator[]( static_cast<size_t>(offset) ); } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::CJson atom::CJson::operator[](size_t offset) { //TODO Auto-generated method stub if( root && type == JVT_ARRAY ) { if( offset < root -> group.size() ) { return CJson( root -> group[offset].second ); } } return CJson(); } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::CJson atom::CJson::operator[](const char * index) { //TODO Auto-generated method stub // 访问类成员,本身不能是数组,也就是说root的大小必须为1 // 然后这个index必须存在。 if( !index ) { return CJson(); } // 如果为空,则初始化一个 if( root == NULL ) { root = tagJsonKeyValue(); root -> group.reserve( 32 ); } if( root == NULL ) { return CJson(); } // 任何类型,都强制转换为object,然后重新设置 switch( type ) { case JVT_ARRAY: root -> group.clear(); case JVT_PAIR: root -> index.clear(); case JVT_PRIMARY: root -> value.Clear(); case JVT_NONE: type = JVT_OBJECT; break; case JVT_OBJECT: break; } atom_hash<const char *> hasher; size_t key = hasher( index ); bool finded = false; for( tagJsonKeyValue::Array::iterator it = root -> group.begin(); it != root -> group.end(); ++ it ) { if( it -> first != key ) { continue; } // 必须判断 it second 内是否有值 if( it -> second != NULL ) { finded = true; return CJson( it -> second ); } } if( finded == false ) { root -> group.push_back( make_pair( key, tagJsonKeyValue(index) ) ); // return directly return CJson( root -> group.back().second ); } return CJson(); } namespace atom { //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" CJson::operator CVariant() const { //TODO Auto-generated method stub if( root && type == JVT_PRIMARY || type == JVT_PAIR ) { return CVariant( root -> value ); } return CVariant(); } } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" U08 atom::CJson::CheckType(const tagJsonKeyValue::Ptr & node) { //TODO Auto-generated method stub U08 result = JVT_NONE; if( node ) { if( node -> group.empty() == false ) { node -> group.front().first == 0 ? result = JVT_ARRAY : result = JVT_OBJECT; } else if( node -> index.empty() == false ) { result = JVT_PAIR; } else { result = JVT_PRIMARY; } } return result; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" size_t atom::CJson::Length() { //TODO Auto-generated method stub size_t result = 0; if( root && type == JVT_ARRAY ) { result = root -> group.size(); } return result; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" U08 atom::CJson::GetType() { //TODO Auto-generated method stub return type; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool atom::CJson::Push(const CVariant & data) { //TODO Auto-generated method stub bool result = false; if( root == NULL ) { root = tagJsonKeyValue(); root -> group.reserve( 32 ); } if( root == NULL ) { return false; } result = true; switch( type ) { case JVT_NONE: root -> group.push_back( make_pair( 0, tagJsonKeyValue(data) ) ); type = JVT_ARRAY; break; case JVT_PRIMARY: if( root -> value.Type() != VT_UNKNOW ) { // 先把自己的值插进去 root -> group.push_back( make_pair( 0, tagJsonKeyValue(root -> value) ) ); root -> value.Clear(); root -> group.push_back( make_pair( 0, tagJsonKeyValue(data) ) ); type = JVT_ARRAY; } break; case JVT_PAIR: // 将pair的值变成数组 root -> group.push_back( make_pair( 0, tagJsonKeyValue(root -> value) ) ); root -> value.Clear(); root -> group.push_back( make_pair( 0, tagJsonKeyValue(data) ) ); type = JVT_ARRAY; break; case JVT_OBJECT: { // 将object的变成数组的第一个元素 tagJsonKeyValue value; value.group = root -> group; // 清理掉原有的数据,再插入到数组中 root -> group.clear(); root -> group.push_back( make_pair(0, value) ); value.group.clear(); value.value = data; root -> group.push_back( make_pair(0, value) ); type = JVT_ARRAY; } break; case JVT_ARRAY: root -> group.push_back( make_pair(0, tagJsonKeyValue(data) ) ); break; default: result = false; break; } return result; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" bool atom::CJson::Push(const CJson & data) { //TODO Auto-generated method stub bool result = false; if( root == NULL ) { root = tagJsonKeyValue(); root -> group.reserve( 32 ); } if( root == NULL ) { return false; } if( data.root == NULL ) { return false; } // push a pair into array is not allowd if( data.root -> index.empty() == false ) { return false; } result = true; switch( type ) { case JVT_NONE: { root -> group.push_back( make_pair(0, data.root) ); type = JVT_ARRAY; } break; case JVT_PRIMARY: if( root -> value.Type() != VT_UNKNOW ) { // push back self value first root -> group.push_back( make_pair( 0, tagJsonKeyValue(root -> value) ) ); root -> value.Clear(); // push json object's value root -> group.push_back( make_pair(0, data.root) ); type = JVT_ARRAY; } break; case JVT_PAIR: { // convert pair's value as a array's element root -> group.push_back( make_pair( 0, tagJsonKeyValue(root -> value) ) ); root -> value.Clear(); root -> group.push_back( make_pair( 0, data.root ) ); type = JVT_ARRAY; } break; case JVT_OBJECT: { // push objct into array. tagJsonKeyValue value; value.group = root -> group; root -> group.clear(); root -> group.push_back( make_pair(0, value) ); root -> group.push_back( make_pair(0, data.root) ); type = JVT_ARRAY; } break; case JVT_ARRAY: { root -> group.push_back( make_pair(0, data.root) ); } break; default: result = false; break; } return result; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::a_string atom::CJson::Stringity() { return Stringity( root ); } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::a_string atom::CJson::Stringity(const tagJsonKeyValue::Ptr & value) { a_string result; if( value ) { U08 genre = CheckType( value ); switch( genre ) { case JVT_NONE: result += "null"; break; case JVT_PAIR: result += "\""; result += value -> index; result += "\":"; case JVT_PRIMARY: if( value -> value.Type() == VT_A_STR || value -> value.Type() == VT_W_STR ) { result += "\""; result += static_cast<const char *>( value -> value ); result += "\""; } else { result += static_cast<const char *>( value -> value ); } break; case JVT_ARRAY: if( value -> index.empty() == false ) { result += "\""; result += value -> index; result += "\":"; } result += "["; for( tagJsonKeyValue::Array::const_iterator it = value -> group.begin(); it != value -> group.end(); ++ it ) { if( it -> second ) { result += Stringity( it -> second ); result += ", "; } } result += "]"; break; case JVT_OBJECT: if( value -> index.empty() == false ) { result += "\""; result += value -> index; result += "\":"; } result += "{"; for( tagJsonKeyValue::Array::const_iterator it = value -> group.begin(); it != value -> group.end(); ++ it ) { if( it -> second ) { result += Stringity( it -> second ); result += ", "; } } result += "}"; break; default: break; } } return result; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::CJson atom::CJson::Clone() { CJson result; result.type = type; result.root = Clone( root ); return result; } //@generated "UML to C++ (com.ibm.xtools.transform.uml2.cpp.CPPTransformation)" atom::tagJsonKeyValue atom::CJson::Clone(const tagJsonKeyValue::Ptr & data) { tagJsonKeyValue result; if( !data ) { return result; } result.index = data -> index; result.value = data -> value; // 先克隆下一层的数据; for( tagJsonKeyValue::Array::const_iterator it1 = data -> group.begin(); it1 != data -> group.end(); ++ it1 ) { result.group.push_back( make_pair( it1 -> first, Clone(it1 -> second) ) ); } return result; }
以上就是利用C++编写一个Json解析器的详细内容,更多关于C++ Json解析器的资料请关注脚本之家其它相关文章!