jsoncpp库常用源码解析及使用介绍(一)

       JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。JSON的应用场景非常广泛,在数据交互、配置保存、网页信息等场景中都可以使用JSON作为媒介。首先简要介绍JSON的语法规则:

        在JavaScript语言中,一切都是对象。因此,任何支持的类型都可以通过JSON来表示,例如字符串、数字、对象、数组等。JSON键值对是用来保存 JS 对象的一种方式,和JavaScript对象的写法也大同小异,键/值对组合中的键名写在前面并用双引号 "" 包裹,使用冒号 : 分隔,然后紧接着值,如下所示展示了JSON表示字符串、数字、数组的方式:

{
 "Computer" : "ASUS",
 "USBNumber" : 3, 
 "USBInfo" : [
 {
  "USBName" : "SanDisk", 
  "isEnable" : true
 },
 
 {
  "USBName" : "Kingston",
  "isEnable" : false
 }
 ]
}

        在C++中,有一个Jsoncpp开源库可以用来解析JSON,轻量又好用,下载地址:https://github.com/open-source-parsers/jsoncpp 。下载之后,主要使用的源码有src/下的json_reader.cpp、json_value.cpp、json_writer.cpp,它们的头文件位于include下的json/文件夹内。编译方法如下:

        在src的lib_json/文件夹下新建文件Makefile,使用vim在Makefile中写入:

CC=g++
AR=ar

SEPARATOR="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"

jsonlib=libjsoncpp.a
SOURCES = json_reader.cpp  json_value.cpp  json_writer.cpp
INCLUDE = -I../../include/

OBJS=$(patsubst %.cpp, %.o, $(SOURCES))

all: clean jsonlib 

.cpp.o:
        $(CC) ${OPTIMIZE} -o $@ -c $*.cpp  $(INCLUDE) -std=c++11
        @echo $(SEPARATOR);

jsonlib:$(OBJS)
        $(AR)  -r -v $(jsonlib) $(OBJS)
        rm -rf *.o
        @echo $(SEPARATOR);

clean:
        rm -f ./$(jsonlib)
        rm -f ./*.o
        @echo $(SEPARATOR);

        大体的目录结构应该都是这样,如有不同之处,修改成相应的目录结构即可。然后直接make,就可以生成libjsoncpp.a库。这样,就可以使用这个开源库来解析JSON了。本篇首先介绍最常使用的json_value.cpp中的一部分,内容比较基础,可以当做对C++的一些基础内容进行一次复习。

        在value.h中,类Json::Value主要构造和析构函数声明如下:

class JSON_API Value {

    Value(ValueType type = nullValue);
    Value(Int value);
    Value(UInt value);

#if defined(JSON_HAS_INT64)
    Value(Int64 value);
    Value(UInt64 value);
#endif // if defined(JSON_HAS_INT64)

    Value(double value);
    Value(const char* value); 
    Value(const char* begin, const char* end); 
    Value(const StaticString& value);
    Value(const String& value); 
                              
#ifdef JSON_USE_CPPTL
    Value(const CppTL::ConstString& value);
#endif

    Value(bool value);
    Value(const Value& other);
    Value(Value&& other);
    ~Value();
    
    ...
};

        其中,构造函数为ValueType参数的实现如下,可以看到,默认类型就是nullValue类型,也就是空,其余如果构造成相应的类型,如intValue,则给结构体ValueHolder的相应类型的参数默认的值设置成0,其余的声明的实现也一样,就是给这个结构体赋值为其他值。

union ValueHolder {
    LargestInt int_;
    LargestUInt uint_;
    double real_;
    bool bool_;
    char* string_; 
    ObjectValues* map_;
  } value_;

enum ValueType {
  nullValue = 0, ///< 'null' value
  intValue,      ///< signed integer value
  uintValue,     ///< unsigned integer value
  realValue,     ///< double value
  stringValue,   ///< UTF-8 string value
  booleanValue,  ///< bool value
  arrayValue,    ///< array value (ordered list)
  objectValue    ///< object value (collection of name/value pairs).
};

Value::Value(ValueType type) {
  static char const emptyString[] = "";
  initBasic(type);
  switch (type) {
  case nullValue:
    break;
  case intValue:
  case uintValue:
    value_.int_ = 0;
    break;
  case realValue:
    value_.real_ = 0.0;
    break;
  case stringValue:
    // allocated_ == false, so this is safe.
    value_.string_ = const_cast<char*>(static_cast<char const*>(emptyString));
    break;
  case arrayValue:
  case objectValue:
    value_.map_ = new ObjectValues();
    break;
  case booleanValue:
    value_.bool_ = false;
    break;
  default:
    JSON_ASSERT_UNREACHABLE;
  }
}

        根据源码中的构造函数,构造JSON时的示例如下所示,打印JSON时,可以将JSON转为string类型,再转为char*类型打印:

#include "json/json.h"
#include <iostream>
#include <stdio.h>
#include <string.h>

int main()
{
    Json::Value message0;               //nullValue
    Json::Value message1(1);            //Int、UInt、Int64、UInt64
    Json::Value message2(4.2);          //double
    
    char ch[5] = "abcd";
    Json::Value message3(ch);           //char* value

    char* begin = ch;
    char* end = ch + 3;
    Json::Value message4(begin, end);   //char* begin, char* end

    std::string str("string");
    Json::Value message5(str);          //String

    Json::Value message6(false);        //bool

    Json::Value json(true);
    Json::Value message7(json);         //Value& other

    Json::Value&& json1 = 100;
    Json::Value message8(json1);        //Value&& other

    printf("message1 = %s\n", message1.toStyledString().c_str());
    printf("message2 = %s\n", message2.toStyledString().c_str());
    printf("message3 = %s\n", message3.toStyledString().c_str());
    printf("message4 = %s\n", message4.toStyledString().c_str());
    printf("message5 = %s\n", message5.toStyledString().c_str());
    printf("message6 = %s\n", message6.toStyledString().c_str());
    printf("message7 = %s\n", message7.toStyledString().c_str());
    printf("message8 = %s\n", message8.toStyledString().c_str());
   
    return 0;
}

        打印结果如下所示:

./jsontest 

message1 = 1

message2 = 4.2000000000000002

message3 = "abcd"

message4 = "abc"

message5 = "string"

message6 = false

message7 = true

message8 = 100

        Value类中,还对赋值号进行了重载,使得我们可以直接把一个JSON对象赋值给另一个JSON对象:

Value& operator=(const Value& other);
Value& operator=(Value&& other);

//示例
Json::Value message9 = message4;
Json::Value message10 = json1;

//结果
message9 = "abc"

message10 = 100

        Value类常用的还有swap函数和copy函数,分别用作对JSON对象的交换和拷贝,如下:

//声明
void swap(Value& other);
void copy(const Value& other);

//实现(摘要)
void Value::swap(Value& other) {    //swap主要就是调用了std中的swap函数,进行一些值的交换操作
  swapPayload(other);

/*swapPayload:
  std::swap(bits_, other.bits_);
  std::swap(value_, other.value_);
*/
  std::swap(comments_, other.comments_);
  std::swap(start_, other.start_);
  std::swap(limit_, other.limit_);
}

void Value::copy(const Value& other) {
  copyPayload(other);
/*
  void Value::dupPayload(const Value& other) {     //copy函数对类型进行了判断,如果是基本类型,则直接进行拷贝操作,如果是对象或字符串string类型,则进行相应的深拷贝操作。具体的实现思想就是深拷贝的那套流程。
  setType(other.type());
  setIsAllocated(false);
  switch (type()) {
  case nullValue:
  case intValue:
  case uintValue:
  case realValue:
  case booleanValue:
    value_ = other.value_;
    break;
  case stringValue:
    if (other.value_.string_ && other.isAllocated()) {
      unsigned len;
      char const* str;
      decodePrefixedString(other.isAllocated(), other.value_.string_, &len,
                           &str);
      value_.string_ = duplicateAndPrefixStringValue(str, len);
      setIsAllocated(true);
    } else {
      value_.string_ = other.value_.string_;
    }
    break;
  case arrayValue:
  case objectValue:
    value_.map_ = new ObjectValues(*other.value_.map_);
    break;
  default:
    JSON_ASSERT_UNREACHABLE;
  }
}
*/

  delete[] comments_;
  dupMeta(other);
}

//使用示例
 Json::Value message11("message11");
 message11.swap(message10);

 Json::Value message12;
 message12.copy(message10);

//结果
message10 = "message11"

message11 = 100

message12 = "message11"

        Value类中对"<"、"<="、">="、">"、"=="、"!="进行了重载,重载这些符号的原理与我们写其他类重载符号一致,可以根据源码复习下,并提供了compare函数用于比较两个JSON对象的大小,声明及部分实现如下:

//声明
bool operator<(const Value& other) const;
bool operator<=(const Value& other) const;
bool operator>=(const Value& other) const;
bool operator>(const Value& other) const;
bool operator==(const Value& other) const;
bool operator!=(const Value& other) const;
int compare(const Value& other) const;

//实现(摘要)
bool Value::operator<(const Value& other) const {
  int typeDelta = type() - other.type();
  if (typeDelta)
    return typeDelta < 0 ? true : false;
  switch (type()) {
  case nullValue:
    return false;
  case intValue:                            //对于基本数据类型,直接判断是否“<”即可
    return value_.int_ < other.value_.int_;
  case uintValue:
    return value_.uint_ < other.value_.uint_;
  case realValue:
    return value_.real_ < other.value_.real_;
  case booleanValue:
    return value_.bool_ < other.value_.bool_;
  case stringValue: {
    if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
      if (other.value_.string_)
        return true;
      else
        return false;
    }
    unsigned this_len;
    unsigned other_len;
    char const* this_str;
    char const* other_str;
    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
                         &this_str);
    decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
                         &other_str);
    unsigned min_len = std::min<unsigned>(this_len, other_len);
    JSON_ASSERT(this_str && other_str);
    int comp = memcmp(this_str, other_str, min_len);  //对于字符串对象类,前面是做字符串提取的操作,然后使用memcmp进行字符串的比较,根据比较结果确定是否"<"
    if (comp < 0)
      return true;
    if (comp > 0)
      return false;
    return (this_len < other_len);
  }
  case arrayValue:
  case objectValue: {
    int delta = int(value_.map_->size() - other.value_.map_->size());
    if (delta)
      return delta < 0;
    return (*value_.map_) < (*other.value_.map_);
  }
  default:
    JSON_ASSERT_UNREACHABLE;
  }
  return false; // unreachable
}

bool Value::operator<=(const Value& other) const { return !(other < *this); }  //有了"<"的重载,这里只需要直接使用,变通下逻辑即可,后面几个符号重载也是如此

bool Value::operator>=(const Value& other) const { return !(*this < other); }

bool Value::operator>(const Value& other) const { return other < *this; }

bool Value::operator==(const Value& other) const {
  if (type() != other.type())
    return false;
  switch (type()) {
  case nullValue:
    return true;
  case intValue:
    return value_.int_ == other.value_.int_;
  case uintValue:
    return value_.uint_ == other.value_.uint_;
  case realValue:
    return value_.real_ == other.value_.real_;
  case booleanValue:
    return value_.bool_ == other.value_.bool_;  //对于基本数据类型,直接判断是否“==”即可
  case stringValue: {
    if ((value_.string_ == nullptr) || (other.value_.string_ == nullptr)) {
      return (value_.string_ == other.value_.string_);
    }
    unsigned this_len;
    unsigned other_len;
    char const* this_str;
    char const* other_str;
    decodePrefixedString(this->isAllocated(), this->value_.string_, &this_len,
                         &this_str);
    decodePrefixedString(other.isAllocated(), other.value_.string_, &other_len,
                         &other_str);
    if (this_len != other_len)
      return false;
    JSON_ASSERT(this_str && other_str);
    int comp = memcmp(this_str, other_str, this_len);//通重载"<"一样,对于字符串对象类,前面是做字符串提取的操作,然后使用memcmp进行字符串的比较,根据比较结果是否为0确定是否"=="
    return comp == 0;
  }
  case arrayValue:
  case objectValue:
    return value_.map_->size() == other.value_.map_->size() &&
           (*value_.map_) == (*other.value_.map_);
  default:
    JSON_ASSERT_UNREACHABLE;
  }
  return false; // unreachable
}

bool Value::operator!=(const Value& other) const { return !(*this == other); }

//compare的实现可以直接使用上面重载过的符号进行
int Value::compare(const Value& other) const {
  if (*this < other)
    return -1;
  if (*this > other)
    return 1;
  return 0;
}

//示例
if(message12 == message10)
    {
        printf("message12 == message10, message12 = %s, message10 = %s\n", message12.toStyledString().c_str(), message10.toStyledString().c_str());
    }

    if(message9 < message10)
    {
        printf("message9 < message10, message9 = %s, message10 = %s\n", message9.toStyledString().c_str(), message10.toStyledString().c_str());
    }

    int compareRet = message9.compare(message10);
    printf("compareRet = %d\n", compareRet);

//结果
message12 == message10, message12 = "message11"
, message10 = "message11"

message9 < message10, message9 = "abc"
, message10 = "message11"

compareRet = -1  //<0表示小于,==0表示等于,>0表示大于

        接下来在源码中,就是一些比较重要的重载"[]"函数,有了各式各样的重载"[]"函数后,JSON对象就可以以键值对的形式进行读取和写入了,下面的代码展示了重载"[]"的多种形式,其中有很多相同参数的重载,但只是函数前加了const修饰,有些没有const修饰,这个的主要作用就是用来设定使JSON键值可以做左值和右值,做左值时,可以进行赋值和修改,这里的实现主要运用到了std::map,在JSON键值对中,会在map中对JSON左值中的键进行查找,如果键存在,则直接根据键从map中进行读取值,若键不存在,则插入map中。做右值时,只可以根据键从map中进行读取。

//声明(最常用)
Value& operator[](ArrayIndex index);
Value& operator[](int index);
const Value& operator[](ArrayIndex index) const;
const Value& operator[](int index) const;
Value& operator[](const char* key);
const Value& operator[](const char* key) const;
Value& operator[](const String& key);
const Value& operator[](const String& key) const;

//实现(摘要)
//获取或插入数组类型元素,注意在使用到角标为0的时候,必须是无符号型,即value[0u]
Value& Value::operator[](ArrayIndex index) {
  JSON_ASSERT_MESSAGE(
      type() == nullValue || type() == arrayValue,
      "in Json::Value::operator[](ArrayIndex): requires arrayValue");
  if (type() == nullValue)
    *this = Value(arrayValue);
  CZString key(index);
  auto it = value_.map_->lower_bound(key);
  if (it != value_.map_->end() && (*it).first == key)  //根据index的序号,查找map
    return (*it).second;                               //查找成功,就直接返回它的值

  ObjectValues::value_type defaultValue(key, nullSingleton());
  it = value_.map_->insert(it, defaultValue);          //未找到,则进行插入(赋值)
  return (*it).second;
}

//获取数组类型的元素(只读)
const Value& Value::operator[](ArrayIndex index) const {
  JSON_ASSERT_MESSAGE(
      type() == nullValue || type() == arrayValue,
      "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
  if (type() == nullValue)
    return nullSingleton();
  CZString key(index);
  ObjectValues::const_iterator it = value_.map_->find(key);
  if (it == value_.map_->end())
    return nullSingleton();          //根据index的序号,查找map,查到返回值,查不到返回空
  return (*it).second;
}

//也是获取数组类型的元素,与ArrayIndex相同,只是这里的参数类型是int,上面的是arrayIndex类型
Value& Value::operator[](int index) {
  JSON_ASSERT_MESSAGE(
      index >= 0,
      "in Json::Value::operator[](int index): index cannot be negative");
  return (*this)[ArrayIndex(index)];
}

const Value& Value::operator[](int index) const {
  JSON_ASSERT_MESSAGE(
      index >= 0,
      "in Json::Value::operator[](int index) const: index cannot be negative");
  return (*this)[ArrayIndex(index)];
}

//根据JSON键key获取值(只读)
const Value& Value::operator[](const char* key) const {
  Value const* found = find(key, key + strlen(key));
  if (!found)
    return nullSingleton();
  return *found;
}

//根据JSON键key获取值(只读)
Value const& Value::operator[](const String& key) const {
  Value const* found = find(key.data(), key.data() + key.length());
  if (!found)
    return nullSingleton();
  return *found;
}

Value& Value::operator[](const char* key) {
  return resolveReference(key, key + strlen(key)); //resolveReference实现见下面
}

Value& Value::resolveReference(char const* key, char const* end) {
  JSON_ASSERT_MESSAGE(
      type() == nullValue || type() == objectValue,
      "in Json::Value::resolveReference(key, end): requires objectValue");
  if (type() == nullValue)
    *this = Value(objectValue);
  CZString actualKey(key, static_cast<unsigned>(end - key),
                     CZString::duplicateOnCopy);
  auto it = value_.map_->lower_bound(actualKey);
  if (it != value_.map_->end() && (*it).first == actualKey)
    return (*it).second;                     //根据key值,查找map,查到返回值

  ObjectValues::value_type defaultValue(actualKey, nullSingleton());
  it = value_.map_->insert(it, defaultValue); //查找不到时,插入
  Value& value = (*it).second;
  return value;
}

Value& Value::operator[](const String& key) {
  return resolveReference(key.data(), key.data() + key.length());
}

//示例
//JSON数组
 Json::Value jsonMess0 = Json::Value::null;
 Json::Value jsonMess1 = Json::Value::null;
 jsonMess0[0u] = "array0";
 jsonMess0[1] = 250;
 jsonMess1[0u] = jsonMess0[1];
 jsonMess1[1] = jsonMess0[0u];
 printf("jsonMess0 = %s, jsonMess1 = %s\n", jsonMess0.toStyledString().c_str(),  jsonMess1.toStyledString().c_str());
//结果
jsonMess0 = [
	"array0",
	250
]
, jsonMess1 = [
	250,
	"array0"
]

//JSON键值对
Json::Value jsonMess2 = Json::Value::null;
jsonMess2["name"] = "Tom";
jsonMess2["age"] = 18;
jsonMess2["isMarried"] = false;
printf("jsonMess2 = %s\n", jsonMess2.toStyledString().c_str());
jsonMess2["name"] = "Bob";
printf("jsonMess2 = %s\n", jsonMess2.toStyledString().c_str());
//结果,(内部还是使用map实现的)
jsonMess2 = {
	"age" : 18,
	"isMarried" : false,
	"name" : "Tom"
}
jsonMess2 = {
	"age" : 18,
	"isMarried" : false,
	"name" : "Bob"
}

//JSON数组和键值对结合
Json::Value jsonMess3 = Json::Value::null;
jsonMess3[0u]["Computer"] = "ASUS";
jsonMess3[0u]["MemorySize"] = 500 * 1024 * 1024;
jsonMess3[0u]["USB"][0u] = "SanDisk";
jsonMess3[0u]["USB"][1] = "Kingston";
jsonMess3[1]["Computer"] = "Apple";
jsonMess3[1]["MemorySize"] = 256 * 1024 * 1024;
jsonMess3[1]["USB"][0u] = "Toshiba";
jsonMess3[1]["USB"][1] = "WestData";
//这里故意直接跳到不连续序号,且随机赋值
jsonMess3[3]["UUUUU"][3] = "XXXXX";
printf("jsonMess3 = %s\n", jsonMess3.toStyledString().c_str());

//结果:少了的角标为2的元素为null,且角标为3的元素只有赋值了的地方有值,其余为null,这样就能把我们要表达的东西原模原样表达出来
jsonMess3 = [
	{
		"Computer" : "ASUS",
		"MemorySize" : 524288000,
		"USB" : 
		[
			"SanDisk",
			"Kingston"
		]
	},
	{
		"Computer" : "Apple",
		"MemorySize" : 268435456,
		"USB" : 
		[
			"Toshiba",
			"WestData"
		]
	},
	null,
	{
		"UUUUU" : 
		[
			null,
			null,
			null,
			"XXXXX"
		]
	}
]

         关于json_value中的其他源码介绍,下次继续分解。

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值