日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Json文件解析(下

發布時間:2023/11/28 生活经验 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Json文件解析(下 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Json文件解析(下)

代碼地址:https://github.com/nlohmann/json

從STL容器轉換

任何序列容器(std::array,std::vector,std::deque,std::forward_list,std::list),其值可以被用于構建JSON值(例如,整數,浮點數,布爾值,字符串類型,或者再次在本節中描述STL容器)可被用于創建JSON陣列。這同樣適用于類似的關聯容器(std::set,std::multiset,std::unordered_set,std::unordered_multiset),但是在這些情況下,數組中的元素的順序取決于元素是如何在各個STL容器排序。

std ::矢量< INT > c_vector {
1,2,3,4 };

json j_vec(c_vector);

// [1、2、3、4]

std ::雙端隊列< 雙 > c_deque { 1.2,2.3,3.4,5.6 };

json j_deque(c_deque);

// [1.2、2.3、3.4、5.6]

std :: list < bool > c_list { true,true,false,true };

json j_list(c_list);

// [true,true,false,true]

std ::修飾符Modifiers < 的int64_t > c_flist { 12345678909876,23456789098765,34567890987654,45678909876543 };

json j_flist(c_flist);

// [12345678909876、23456789098765、34567890987654、45678909876543]

std ::陣列< 無符號 長,4 > c_array {{
1,2,3,4 }};

json j_array(c_array);

// [1、2、3、4]

std :: set c_set { “一個”,“兩個”,“三個”,“四個”,“一個” };

json j_set(c_set); //僅使用“一個”的一個條目

// // [“四個”,“一個”,“三個”,“兩個”]

std :: unordered_set
c_uset { “一”,“二”,“三”,“四”,“一” };

json j_uset(c_uset); //僅使用“一個”的一個條目

// //可能是[“兩個”,“三個”,“四個”,“一個”]

std :: multiset
c_mset { “一個”,“兩個”,“一個”,“四個” };

json j_mset(c_mset); //使用兩個用于“一個”的條目

//也許[[一個”,“兩個”,“一個”,“四個”]

std :: unordered_multiset c_umset { “一”,“二”,“一”,“四” };

json j_umset(c_umset); //使用兩個用于“一個”的條目

//也許[[一個”,“兩個”,“一個”,“四個”]

同樣,任何締鍵值容器(std::map,std::multimap,std::unordered_map,std::unordered_multimap),其鍵可以構造一個std::string,并且其值可以被用于構建JSON值(見上文實施例)可用于創建一個JSON對象。請注意,在使用多圖的情況下,JSON對象中僅使用一個鍵,并且該值取決于STL容器的內部順序。

std :: map <std :: string,int > c_map {{ “一個”,1 },{ “兩個”,2 },{ “三個”,3 }};

json j_map(c_map);

// {“一個”:1,“三個”:3,“兩個”:2}

std :: unordered_map < const char *,double > c_umap {{ “一個”,1.2 },{ “兩個”,2.3 },{ “三個”,3.4 }};

json j_umap(c_umap);

// {“一個”:1.2,“兩個”:2.3,“三個”:3.4}

std :: multimap <std :: string,bool > c_mmap {{ “一個”,true },{ “兩個”,true },{ “三個”,false },{ “三個”,true }};

json j_mmap(c_mmap); //僅使用鍵“三”的一個條目

// //也許{“一個”:true,“兩個”:true,“三個”:true}

std :: unordered_multimap <std :: string,bool > c_ummap {{
“一”,true },{ “二”,true },{ “三”,false },{ “三”,true }};

json j_ummap(c_ummap); //僅使用鍵“三”的一個條目

// //也許{“一個”:true,“兩個”:true,“三個”:true}

JSON指針和JSON補丁

該庫支持JSON指針(RFC 6901)作為解決結構化值的替代方法。除此之外,JSON Patch(RFC 6902)允許描述兩個JSON值之間的差異-有效地允許Unix已知的patch和diff操作。

// JSON值

json j_original = R“( {{


baz“:[” one“,” two“,” three“],


foo“:” bar“

} )” _json;

//使用JSON指針(RFC 6901)訪問成員

j_original [ “ / baz / 1 ” _json_pointer];

// “兩個”

//一個JSON修補程序(RFC 6902)

json j_patch = R“( [[

{”
op“:” replace“,” path“:” / baz“,” value“:” boo“},

{”
op“:” add “,” path“:” / hello“,” value“:[” world“]},

{”
op“:” remove“,” path“:” / foo“}

] )” _json;

//應用補丁

json j_result = j_original.patch(j_patch);

// {

//
“ baz”:“ boo”,

//
“ hello”:[“ world”]

// }

//根據兩個JSON值計算JSON補丁

json :: diff(j_result,j_original);

// [

//
{“ op”:“ replace”,“ path”:“ / baz”,“ value”:[“ one”,“ Two”,“ three”]},

//
{“ op”:“ remove“,” path“:” / hello“},

//
{” op“:” add“,” path“:” / foo“,” value“:” bar“}

// ]

JSON合并補丁

該庫支持JSON合并補丁(RFC 7386)作為補丁格式。沒有使用JSON指針(請參見上文)來指定要操作的值,而是使用一種語法來描述更改,該語法與擬修改的文檔非常相似。

// JSON值

json j_document = R“( {


a“:” b“,


c“:{

d“:” e“,

f“:” g“

}

}} )” _json;

//補丁

json j_patch = R“( {


a“:” z“,


c“:{

f“:null

}

} )” _json;

//應用補丁

j_document.merge_patch(j_patch);

// {

//
“ a”:“ z”,

// “
c”:{

//
“ d”:“ e”

//
}

// }

隱式轉換

支持的類型可以隱式轉換為JSON值。

建議不要使用隱式轉換從一個JSON值。可以在此處找到有關此建議的更多詳細信息。

//字符串

std :: string s1 = “世界好!” ;

json js = s1;

自動 s2 = js.get
();

//不推薦

std :: string s3 = js;

std :: string s4;

s4 = js;

//布爾

值bool b1 = true ;

json jb = b1;

自動 b2 = jb.get
< bool >();

//不推薦

bool b3 = jb;

布爾 b4;

b4 = jb;

//數字

int i = 42 ;

json jn = i;

自動 f = jn.get <
double >();

//不推薦使用

double f2 = jb;

雙 f3;

f3 = jb;

//等

請注意,char類型不會自動轉換為JSON字符串,而是自動轉換為整數。必須明確指定轉換為字符串:

char ch = ’ A ’ ; // ASCII值65

json j_default = ch; //存儲整數65

json j_string = std :: string(1,ch); //存儲字符串“ A”

任意類型轉換

每種類型都可以用JSON序列化,而不僅僅是STL容器和標量類型。通常,會按照以下方式進行操作:

名稱空間 ns {

 // //一個簡單的結構,用于對人員進行建模struct  person {

std :: string名稱;

std :: string地址;

INT年齡;

};

}

ns :: person p = { “ Ned Flanders ”,“ 744 Evergreen Terrace ”,60 };

//轉換為JSON:將每個值復制到JSON對象中

json j;

j [ “ name ” ] = p.name;

j [ “ address ” ] = p.address;

j [ “ age ” ] = p.age;

// …

//從JSON轉換:復制JSON對象中的每個值

ns :: person p {

j

[ “ name ” ]。得到 (),

j

[ “ address ” ]。得到 (),

j

[ “年齡” ]。獲取 < int >()

};

可以工作,但是有很多樣板…幸運的是,有更好的方法:

//創建一個人

ns :: person p { “ Ned Flanders ”, “ 744 Evergreen Terrace ”, 60 };

//轉換:person-> json

json j = p;

std :: cout << j << std ::
endl;

// {“地址”:“ 744 Evergreen Terrace”,“年齡”:60,“名稱”:“ Ned Flanders”}

//轉換:

json- > person auto p2 = j.get
();

//就是

斷言(p == p2);

基本用法

要使與一種類型一起使用,只需提供兩個功能:

使用 nlohmann ::
json;

命名空間 ns {

 void  to_json(json&j,const person&p){

j = json {{ “ name ”,p。名稱 },{ “地址”,第 地址 },{ “年齡”,第 年齡 }};

}無效 from_json(const json&j,person&p){

j。在(“名稱”)。get_to(第名);

j。在(“地址”)。get_to(第地址);

j。在(“年齡”)。get_to(第年齡);

}

} //名稱空間ns

就這樣!當json使用類型調用構造函數時,自定義to_json方法將被自動調用。同樣,在調用get<your_type>()或時get_to(your_type&),from_json將調用該方法。

一些重要的事情:

這些方法必須位于類型的名稱空間(可以是全局名稱空間)中,否則庫將無法找到(在本示例中,位于定義的名稱空間ns中person)。
在使用這些轉換的任何地方,這些方法都必須可用(例如,必須包含適當的標頭)。請查看問題1108,了解否則可能發生的錯誤。
使用時get<your_type>(),your_type 必須為DefaultConstructible。(有一種繞過此要求的方法,將在后面介紹。)
在函數中from_json,使用函數at()訪問對象值而不是operator[]。萬一鍵不存在,at將引發可以處理的異常,而operator[]表現出未定義的行為。
無需為STL類型添加序列化器或反序列化器,例如std::vector:該庫已經實現了這些。

使用宏簡化生活

如果只想對一些結構進行序列化/反序列化,則to_json/ from_json函數可能會很多。

只要(1)想要將JSON對象用作序列化和(2)要將成員變量名稱用作該對象中的對象鍵,就有兩個宏可以使生活更輕松:

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1,
member2, …) 將在要為其創建代碼的類/結構的名稱空間內定義。
NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1,
member2, …)在要為其創建代碼的類/結構中定義。該宏還可以訪問私有成員。

在兩個宏中,第一個參數是類/結構的名稱,其余所有參數都為成員命名。

例子

上面結構的to_json/ from_json函數person可以通過以下方式創建:

命名空間 ns {

 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(人,姓名,地址,年齡)

}

這是一個NLOHMANN_DEFINE_TYPE_INTRUSIVE需要私人成員的示例:

命名空間 ns {

 類 地址 {

私有:

std :: string street;

INT housenumber;

INT郵編;

公開:

NLOHMANN_DEFINE_TYPE_INTRUSIVE(地址,街道,門牌號,郵政編碼)

};

}

如何轉換第三方類型?

這需要更高級的技術。但首先,讓看看這種轉換機制是如何工作的:

該庫使用JSON序列化器將類型轉換為json。默認的序列化器nlohmann::json為nlohmann::adl_serializer(ADL表示參數依賴查找)。

這樣實現(簡化):

template < typename T>

struct adl_serializer {

 static  void  to_json(json&j,const T&value){

//在T的命名空間中調用“ to_json”方法

}static  void  from_json(const json&j,T&value){

//相同,但使用“ from_json”方法

}

};

當可以控制類型的名稱空間時,此序列化程序可以正常工作。但是,關于boost::optional或std::filesystem::path(C ++ 17)呢?劫持boost名稱空間是非常糟糕的,并且向模板添加模板專業化以外的內容是非法的std。

為了解決這個問題,需要adl_serializer在nlohmann名稱空間中添加的特殊化,這是一個示例:

//部分專業化(也可以完全專業化)

名稱空間 nlohmann {

模板 <類型名 T>struct  adl_serializer <boost ::

optional > {

靜態 void to_json(json&j, const boost ::
optional &opt){

如果(opt == boost ::
none){

            j = nullptr ;

} 其 {

          j = * opt; //這將調用adl_serializer <T> :: to_json將//發現T的命名空間中的自由函數to_json!

}

}

靜態 無效 from_json(const json&j,boost ::
optional &opt){

if(j。is_null()){

            opt = boost :: none;

} 其 {

            選擇= j。得到 <T>(); //與上述相同,但//使用 adl_serializer <T> :: from_json

}

}

};

}

如何get()用于非默認的可構造/不可復制類型?

如果類型為MoveConstructible,則有一種方法。還需要專門化adl_serializer,但要有一個特殊的from_json重載:

struct move_only_type {

 move_only_type()= 刪除 ;move_only_type(int ii):i(ii){}move_only_type(const move_only_type&)= delete ;move_only_type(move_only_type &&)= 默認值;詮釋 I;

};

名稱空間 nlohmann {

 template <>struct  adl_serializer

<move_only_type> {

//注意:返回類型不再是’void’,該方法僅

//使用一個參數

static move_only_type from_json(const json&j){

return {j。get < int >()};

}

//這就是陷阱!必須提供to_json方法!否則

//

將//無法將move_only_type轉換為json,因為完全//對該類型的adl_serializer進行了專門化//

static void to_json(json&j,move_only_type t){

 j = t  ;

}

};

}

可以編寫自己的序列化器嗎?(高級使用)

是。可能需要看一下unit-udt.cpp測試套件,以查看一些示例。

如果編寫自己的序列化器,則需要做一些事情:

使用不同的basic_json別名nlohmann::json(的最后一個模板參數basic_json是JSONSerializer)
basic_json在所有to_json/ from_json方法中使用別名(或模板參數)
使用nlohmann::to_json以及nlohmann::from_json何時需要ADL

這是一個示例,沒有簡化,僅接受大小<= 32的類型,并使用ADL。

// //應該使用void作為第二個模板參數

// //如果不需要對T

template < typename T, typename SFINAE = typename std ::
enable_if < sizeof(T)<= 32 > :: type進行編譯時檢查 >

struct less_than_32_serializer {

模板 <類型名稱BasicJsonType>靜態 void  to_json(BasicJsonType&j,T值){

//要使用ADL,并

使用 nlohmann :: to_json調用正確的to_json重載;//這個方法由adl_serializer調用,

                             //這就是

to_json(j,value)發生魔術的地方;

}template < typename

BasicJsonType>

 靜態 無效 from_json(const BasicJsonType&j,T&value){

//

使用 nlohmann :: from_json進行相同操作;

from_json(j,值);

}

};

重新實現序列化器時要非常小心,如果不注意,可能會導致堆棧溢出:

模板 < 類型名 T,無效 >

結構 bad_serializer

{

template < typename

BasicJsonType>

 static  void  to_json(BasicJsonType&j,const T&value){

//這將調用BasicJsonType ::
json_serializer :: to_json(j,value);

//如果BasicJsonType ::
json_serializer == bad_serializer …糟糕!

j =值;

}template < typename

BasicJsonType>

 static  void  to_json(const BasicJsonType&j,T&value){

//這將調用BasicJsonType ::
json_serializer :: from_json(j,value);

//如果BasicJsonType ::
json_serializer == bad_serializer …糟糕!

值= j。模板 獲取 (); //哎呀!

}

};

專門進行枚舉轉換

默認情況下,枚舉值以整數形式序列化為JSON。在某些情況下,這可能會導致不良行為。如果在將數據序列化為JSON之后對枚舉進行了修改或重新排序,則較晚的反序列化JSON數據可能是未定義的或與原始預期值不同的枚舉值。

可以更精確地指定給定枚舉如何映射到JSON和從JSON映射,如下所示:

//示例枚舉類型聲明

枚舉 TaskState {

TS_STOPPED,

TS_RUNNING,

TS_COMPLETED,

TS_INVALID = -1,

};

//將TaskState值作為字符串

NLOHMANN_JSON_SERIALIZE_ENUM 映射到JSON(TaskState,{

{TS_INVALID,nullptr },

{TS_STOPPED,“已停止” },

{TS_RUNNING,“正在運行” },

{TS_COMPLETED,“已完成”),

})

的NLOHMANN_JSON_SERIALIZE_ENUM()宏聲明一組to_json()/ from_json()功能型TaskState,同時避免重復和樣板序列化代碼。

用法:

//以字符串形式枚舉JSON

json j = TS_STOPPED;

斷言(j == “ stopped ”);

//枚舉的json字符串

json j3 = “正在運行”;

斷言(j3.get
()== TS_RUNNING);

//要枚舉的未定義json值(其中,上面的第一個地圖項是默認值)

json jPi = 3.14 ;

斷言(jPi.get
()== TS_INVALID);

就像上面的任意類型轉換一樣,

NLOHMANN_JSON_SERIALIZE_ENUM() 必須在枚舉類型的名稱空間(可以是全局名稱空間)中聲明,否則庫將無法找到,并且將默認為整數序列化。
使用轉換的任何地方都必須可用(例如,必須包含適當的標題)。

其要點:

使用時get<ENUM_TYPE>(),未定義的JSON值將默認為地圖中指定的第一對。仔細選擇該默認對。
如果在地圖中多次指定枚舉或JSON值,則在與JSON進行相互轉換時,將從地圖頂部的第一個匹配項返回。

二進制格式(BSON,CBOR,MessagePack和UBJSON)

盡管JSON是一種無處不在的數據格式,但不是一種非常緊湊的格式,適合通過網絡進行數據交換。因此,該庫支持 BSON(二進制JSON),CBOR(簡明二進制對象表示形式),MessagePack和UBJSON(通用二進制JSON規范),以將JSON值有效地編碼為字節向量并對該向量進行解碼。

//創建一個JSON值

json j = R“( {” compact“:true,” schema“:0} )” _json;

//序列化為BSON

std :: vector v_bson =
json :: to_bson(j);

// 0x1B,0x00、0x00、0x00、0x08、0x63、0x6F,0x6D,0x70、0x61、0x63、0x74、0x00、0x01、0x10、0x73、0x63、0x68、0x65、0x6D,0x61、0x00、0x00 0x00、0x00、0x00

//往返

json j_from_bson = json :: from_bson(v_bson);

//序列化為CBOR

std :: vector v_cbor =
json :: to_cbor(j);

// 0xA2、0x67、0x63、0x6F,0x6D,0x70、0x61、0x63、0x74、0xF5、0x66、0x73、0x63、0x68、0x65、0x6D,0x61、0x00

//往返

json j_from_cbor = json :: from_cbor(v_cbor);

//序列化為MessagePack

std :: vector v_msgpack
= json :: to_msgpack(j);

// 0x82、0xA7、0x63、0x6F,0x6D,0x70、0x61、0x63、0x74、0xC3、0xA6、0x73、0x63、0x68、0x65、0x6D,0x61、0x00

//往返

json j_from_msgpack = json :: from_msgpack(v_msgpack);

//序列化為UBJSON

std :: vector v_ubjson =
json :: to_ubjson(j);

// 0x7B,0x69、0x07、0x63、0x6F,0x6D,0x70、0x61、0x63、0x74、0x54、0x69、0x06、0x73、0x63、0x68、0x65、0x6D,0x61、0x69、0x00、0x7D

//往返

json j_from_ubjson = json :: from_ubjson(v_ubjson);

該庫還支持BSON,CBOR(字節字符串)和MessagePack(bin,ext,fixext)的二進制類型。默認存儲std::vectorstd::uint8_t為在庫外部進行處理。

// CBOR字節串與有效載荷為0xCAFE

的std ::矢量<性病:: uint8_t > V = {的0x42, 0xCA, 0xFE的 };

//讀取值

json j = json :: from_cbor(v);

// JSON值的類型為binary

j.is_binary(); //正確

//獲取對存儲的二進制值的引用

auto&binary =
j.get_binary();

//二進制值沒有子類型(CBOR沒有二進制子類型)

binary.has_subtype(); //錯誤

//訪問std :: vector
成員函數

binary.size(); // 2

binary [ 0 ]; // 0xCA

binary [ 1 ]; // 0xFE

//將子類型設置為0x10

二進制。set_subtype( 0x10);

//序列化為MessagePack

auto cbor = json ::
to_msgpack(j); // 0xD5(fixext2),0x10、0xCA,0xFE

支持的編譯器

盡管已經是2020年,但對C ++ 11的支持仍然很少。當前,已知以下編譯器可以工作:

GCC 4.8-10.1(可能以后)
鐺3.4-10.0(可能以后)
Apple Clang 9.1-12.0(可能更高)
英特爾C ++編譯器17.0.2(可能更高)
Microsoft Visual C ++ 2015 /構建工具14.0.25123.0(以及更高版本)
Microsoft Visual C ++ 2017 /生成工具15.5.180.51428(以及更高版本)
Microsoft Visual C ++ 2019 /生成工具16.3.1 + 1def00d3d(以及更高版本)

很樂意了解其編譯器/版本。

請注意:

GCC 4.8有一個錯誤57824):多行原始字符串不能作為宏的參數。不要使用此編譯器直接在宏中使用多行原始字符串。
Android默認使用非常老的編譯器和C ++庫。要解決此問題,請將以下內容添加到中Application.mk。這將切換到LLVM C ++庫,Clang編譯器,并啟用C ++ 11和其默認禁用的功能。

·
APP_STL := c++_shared

·
NDK_TOOLCHAIN_VERSION := clang3.6

·
APP_CPPFLAGS += -frtti -fexceptions

該代碼可使用Android NDK,修訂版9-11(以及更高版本)和CrystaX的Android NDK版本10 成功編譯。

對于在MinGW或Android SDK上運行的GCC ‘to_string’
is not a member of ‘std’,可能會發生錯誤(或類似的for strtod或strtof)。注意,這不是代碼問題,而是編譯器本身的問題。在Android上,請參見上文以使用較新的環境進行構建。對于MinGW,請參考此站點和此討論以獲取有關如何修復此錯誤的信息。對于Android NDK的使用APP_STL := gnustl_static,請參考此討論。
#error指令拒絕不支持的GCC和Clang版本。可以通過定義關閉JSON_SKIP_UNSUPPORTED_COMPILER_CHECK。請注意,在這種情況下,不希望獲得任何支持。

Travis,AppVeyor,GitHub Actions和CircleCI當前在持續集成中使用編譯器。

總結

以上是生活随笔為你收集整理的Json文件解析(下的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。