json数据解析,这是很常见的功能需求。c语言里有有名的cJSON库可用,当然c++里也可以直接用或者做个封装。但是可用不代表着就好用。有些情况下我们拿c++做开发而不是选择c,不就是为了开发上高效,维护上方便,可以做一些大项目么。
这里分享下封装的c++的好用的json解析库,不是原创。从OpenHarmony源码里摘出来的,所以可以放心用。直接学习优秀的开源项目代码好处多多,有时候是看书本学不来的。
摘自开源鸿蒙系统源码的JS UI框架代码。开源鸿蒙应用使用js开发,运行效率不用担心是因为框架使用的还是c++。
c++自从c++11标准之后真是焕然一新,使用变得简单且更好用了。从这个json解析源码里就能看出来一些:如使用了auto,lambda,智能指针等,智能指针的使用使得不用担心什么时候new的忘了释放掉这个心智负担,后续想new的地方要优先考虑使用智能指针。
条款21里有一条:尽量使用std::make_unique和std::make_shared而不直接使用new(《Effective Modern C++》一书)。
c++需要注意的地方之一就是对内存的管理,动态内存的使用经常会出现内存泄漏,或者产生引用非法内存的指针。
新的标准库提供了两种智能指针类型来管理动态对象:
(1)shared_ptr 允许多个指针指向同一个对象
(2)unique_ptr 独占所指向的对象
定义在memory头文件中,他们的作用在于会自动释放所指向的对象。
unique_ptr 是 C++ 11 提供的用于防止内存泄漏的智能指针中的一种实现,独享被管理对象指针所有权的智能指针。unique_ptr对象包装一个原始指针,并负责其生命周期。当该对象被销毁时,会在其析构函数中删除关联的原始指针。
unique_ptr具有->和*运算符重载符,因此它可以像普通指针一样使用。
unique_ptr不能直接复制,必须使用std::move()转移其管理的指针,转移后原 unique_ptr 为空。
unique_ptr支持的操作(C++ Primer Fifth Edition 中文版一书):
这个json解析类的源码里,至少用到了c++14及以上的特性(从std::make_unique这个智能指针可看出),若你的工具链版本低可能不行。
gcc工具链从4.7.0之后开始支持c++11标准。GCC 4.8.1完全支持c++11核心部分,对应的glibc为2.17,gcc 4.9支持c++11正则表达式。gcc从哪个版本之后开始支持c++14?好像是GCC v6.1之后。
源码文件路径:code-v3.0-LTS\OpenHarmony\foundation\ace\ace_engine\frameworks\base\json
json_util.cpp和json_util.h
其实还是对cJSON库的封装:
#include "base/json/json_util.h" #include "cJSON.h" namespace OHOS::Ace { JsonValue::JsonValue(JsonObject* object) : object_(object) {} JsonValue::JsonValue(JsonObject* object, bool isRoot) : object_(object), isRoot_(isRoot) {} JsonValue::~JsonValue() { if (object_ != nullptr && isRoot_) { cJSON_Delete(object_); } object_ = nullptr; } bool JsonValue::IsBool() const { return cJSON_IsBool(object_); } bool JsonValue::IsNumber() const { return cJSON_IsNumber(object_); } bool JsonValue::IsString() const { return cJSON_IsString(object_); } bool JsonValue::IsArray() const { return cJSON_IsArray(object_); } bool JsonValue::IsObject() const { return cJSON_IsObject(object_); } bool JsonValue::IsValid() const { return (object_ != nullptr) && !cJSON_IsInvalid(object_); } bool JsonValue::IsNull() const { return (object_ == nullptr) || cJSON_IsNull(object_); } bool JsonValue::Contains(const std::string& key) const { return cJSON_HasObjectItem(object_, key.c_str()); } bool JsonValue::GetBool() const { return cJSON_IsTrue(object_) != 0; } bool JsonValue::GetBool(const std::string& key, bool defaultValue) const { if (Contains(key) && GetValue(key)->IsBool()) { return GetValue(key)->GetBool(); } return defaultValue; } int32_t JsonValue::GetInt() const { return static_cast<int32_t>((object_ == nullptr) ? 0 : object_->valuedouble); } uint32_t JsonValue::GetUInt() const { return static_cast<uint32_t>((object_ == nullptr) ? 0 : object_->valuedouble); } double JsonValue::GetDouble() const { return (object_ == nullptr) ? 0.0 : object_->valuedouble; } double JsonValue::GetDouble(const std::string& key, double defaultVal) const { auto value = GetValue(key); if (value && value->IsNumber()) { return value->GetDouble(); } return defaultVal; } std::string JsonValue::GetString() const { return ((object_ == nullptr) || (object_->valuestring == nullptr)) ? "" : std::string(object_->valuestring); } std::unique_ptr<JsonValue> JsonValue::GetNext() const { if (object_ == nullptr) { return std::make_unique<JsonValue>(nullptr); } return std::make_unique<JsonValue>(object_->next); } std::unique_ptr<JsonValue> JsonValue::GetChild() const { if (object_ == nullptr) { return std::make_unique<JsonValue>(nullptr); } return std::make_unique<JsonValue>(object_->child); } std::string JsonValue::GetKey() const { return ((object_ == nullptr) || (object_->string == nullptr)) ? "" : std::string(object_->string); } std::unique_ptr<JsonValue> JsonValue::GetValue(const std::string& key) const { return std::make_unique<JsonValue>(cJSON_GetObjectItem(object_, key.c_str())); } std::unique_ptr<JsonValue> JsonValue::GetObject(const std::string& key) const { if (Contains(key) && GetValue(key)->IsObject()) { return GetValue(key); } return std::make_unique<JsonValue>(); } int32_t JsonValue::GetArraySize() const { return cJSON_GetArraySize(object_); } std::unique_ptr<JsonValue> JsonValue::GetArrayItem(int32_t index) const { return std::make_unique<JsonValue>(cJSON_GetArrayItem(object_, index)); } bool JsonValue::Put(const char* key, const char* value) { if (!value || !key) { return false; } cJSON* child = cJSON_CreateString(value); if (child == nullptr) { return false; } cJSON_AddItemToObject(object_, key, child); return true; } const JsonObject* JsonValue::GetJsonObject() const { return object_; } bool JsonValue::Put(const char* key, const std::unique_ptr<JsonValue>& value) { if (!value || !key) { return false; } cJSON* jsonObject = cJSON_Duplicate(value->GetJsonObject(), true); if (jsonObject == nullptr) { return false; } cJSON_AddItemToObject(object_, key, jsonObject); return true; } // add item to array bool JsonValue::Put(const std::unique_ptr<JsonValue>& value) { if (!value) { return false; } cJSON* jsonObject = cJSON_Duplicate(value->GetJsonObject(), true); if (jsonObject == nullptr) { return false; } cJSON_AddItemToArray(object_, jsonObject); return true; } bool JsonValue::Put(const char* key, size_t value) { if (key == nullptr) { return false; } cJSON* child = cJSON_CreateNumber(static_cast<double>(value)); if (child == nullptr) { return false; } cJSON_AddItemToObject(object_, key, child); return true; } bool JsonValue::Put(const char* key, int32_t value) { if (key == nullptr) { return false; } cJSON* child = cJSON_CreateNumber(static_cast<double>(value)); if (child == nullptr) { return false; } cJSON_AddItemToObject(object_, key, child); return true; } bool JsonValue::Put(const char* key, double value) { if (key == nullptr) { return false; } cJSON* child = cJSON_CreateNumber(value); if (child == nullptr) { return false; } cJSON_AddItemToObject(object_, key, child); return true; } bool JsonValue::Put(const char* key, bool value) { if (key == nullptr) { return false; } cJSON* child = cJSON_CreateBool(value); if (child == nullptr) { return false; } cJSON_AddItemToObject(object_, key, child); return true; } bool JsonValue::Replace(const char* key, const char* value) { if ((value == nullptr) || (key == nullptr)) { return false; } cJSON* child = cJSON_CreateString(value); if (child == nullptr) { return false; } if (!cJSON_ReplaceItemInObject(object_, key, child)) { cJSON_Delete(child); return false; } return true; } bool JsonValue::Replace(const char* key, int32_t value) { if (key == nullptr) { return false; } cJSON* child = cJSON_CreateNumber(static_cast<double>(value)); if (child == nullptr) { return false; } if (!cJSON_ReplaceItemInObject(object_, key, child)) { cJSON_Delete(child); return false; } return true; } bool JsonValue::Replace(const char* key, const std::unique_ptr<JsonValue>& value) { if ((value == nullptr) || (key == nullptr)) { return false; } cJSON* jsonObject = cJSON_Duplicate(value->GetJsonObject(), true); if (jsonObject == nullptr) { return false; } if (!cJSON_ReplaceItemInObject(object_, key, jsonObject)) { cJSON_Delete(jsonObject); return false; } return true; } bool JsonValue::Delete(const char* key) { if (key == nullptr) { return false; } cJSON_DeleteItemFromObject(object_, key); return true; } std::string JsonValue::ToString() { std::string result; if (!object_) { return result; } // It is null-terminated. char* unformatted = cJSON_PrintUnformatted(object_); if (unformatted != nullptr) { result = unformatted; cJSON_free(unformatted); } return result; } std::string JsonValue::GetString(const std::string& key, const std::string& defaultVal) const { auto value = GetValue(key); if (value && value->IsString()) { return value->GetString(); } return defaultVal; } int32_t JsonValue::GetInt(const std::string& key, int32_t defaultVal) const { auto value = GetValue(key); if (value && value->IsNumber()) { return value->GetInt(); } return defaultVal; } uint32_t JsonValue::GetUInt(const std::string& key, uint32_t defaultVal) const { auto value = GetValue(key); if (value && value->IsNumber()) { return value->GetUInt(); } return defaultVal; } std::unique_ptr<JsonValue> JsonUtil::ParseJsonData(const char* data, const char** parseEnd) { return std::make_unique<JsonValue>(cJSON_ParseWithOpts(data, parseEnd, true), true); } std::unique_ptr<JsonValue> JsonUtil::ParseJsonString(const std::string& content, const char** parseEnd) { return ParseJsonData(content.c_str(), parseEnd); } std::unique_ptr<JsonValue> JsonUtil::Create(bool isRoot) { return std::make_unique<JsonValue>(cJSON_CreateObject(), isRoot); } std::unique_ptr<JsonValue> JsonUtil::CreateArray(bool isRoot) { return std::make_unique<JsonValue>(cJSON_CreateArray(), isRoot); } } // namespace OHOS::Ace
#ifndef FOUNDATION_ACE_FRAMEWORKS_BASE_JSON_JSON_UTIL_H #define FOUNDATION_ACE_FRAMEWORKS_BASE_JSON_JSON_UTIL_H #include <memory> #include <string> #include "base/utils/macros.h" struct cJSON; namespace OHOS::Ace { using JsonObject = cJSON; class ACE_FORCE_EXPORT JsonValue final { public: JsonValue() = default; explicit JsonValue(JsonObject* object); JsonValue(JsonObject* object, bool isRoot); ~JsonValue(); // check functions bool IsBool() const; bool IsNumber() const; bool IsString() const; bool IsArray() const; bool IsObject() const; bool IsValid() const; bool IsNull() const; bool Contains(const std::string& key) const; // get functions bool GetBool() const; bool GetBool(const std::string& key, bool defaultValue = false) const; int32_t GetInt() const; int32_t GetInt(const std::string& key, int32_t defaultVal = 0) const; uint32_t GetUInt() const; uint32_t GetUInt(const std::string& key, uint32_t defaultVal = 0) const; double GetDouble() const; double GetDouble(const std::string& key, double defaultVal = 0.0) const; std::string GetString() const; std::string GetString(const std::string& key, const std::string& defaultVal = "") const; std::unique_ptr<JsonValue> GetNext() const; std::unique_ptr<JsonValue> GetChild() const; std::string GetKey() const; std::unique_ptr<JsonValue> GetValue(const std::string& key) const; std::unique_ptr<JsonValue> GetObject(const std::string& key) const; int32_t GetArraySize() const; std::unique_ptr<JsonValue> GetArrayItem(int32_t index) const; const JsonObject* GetJsonObject() const; // put functions bool Put(const char* key, const char* value); bool Put(const char* key, size_t value); bool Put(const char* key, int32_t value); bool Put(const char* key, double value); bool Put(const char* key, bool value); bool Put(const char* key, const std::unique_ptr<JsonValue>& value); bool Put(const std::unique_ptr<JsonValue>& value); // replace functions bool Replace(const char* key, const char* value); bool Replace(const char* key, int32_t value); bool Replace(const char* key, const std::unique_ptr<JsonValue>& value); // delete functions bool Delete(const char* key); // serialize std::string ToString(); private: JsonObject* object_ = nullptr; bool isRoot_ = false; }; class ACE_EXPORT JsonUtil final { public: JsonUtil() = delete; ~JsonUtil() = delete; static std::unique_ptr<JsonValue> ParseJsonData(const char* data, const char** parseEnd = nullptr); static std::unique_ptr<JsonValue> ParseJsonString(const std::string& content, const char** parseEnd = nullptr); static std::unique_ptr<JsonValue> Create(bool isRoot); static std::unique_ptr<JsonValue> CreateArray(bool isRoot); }; } // namespace OHOS::Ace #endif // FOUNDATION_ACE_FRAMEWORKS_BASE_JSON_JSON_UTIL_H
使用方法,如以下代码片段,定义了一个右值引用actionEventHandler ,使用了lambda表达式写法,c++新语法用着就是美:
// action event hadnler auto&& actionEventHandler = [this] (const std::string& action) { LOGI("on Action called to event handler"); auto eventAction = JsonUtil::ParseJsonString(action); auto bundleName = eventAction->GetValue("bundleName"); auto abilityName = eventAction->GetValue("abilityName"); auto params = eventAction->GetValue("params"); auto bundle = bundleName->GetString(); auto ability = abilityName->GetString(); LOGI("bundle:%{public}s ability:%{public}s, params:%{public}s", bundle.c_str(), ability.c_str(), params->GetString().c_str()); if (bundle.empty() || ability.empty()) { LOGE("action ability or bundle is empty"); return; } AAFwk::Want want; want.SetElementName(bundle, ability); this->StartAbility(want); };