
Pustaka JSON Link berkinerja tinggi, tanpa alokasi, Pustaka C++ JSON mendukung:
Perpustakaan mendukung mode parsing lain yang dapat dicampur juga.
json_array_iterator atau json_array_range .json_value yang memungkinkan iterasi/penguraian dokumen yang lambatBeberapa fitur penting lainnya adalah:
boost::multiprecision::cpp_int atau GNU BigNum/Rational mpq_tPerpustakaan menggunakan lisensi BSL
Ketika struktur dokumen JSON diketahui, parsingnya seperti berikut:
MyThing thing = daw::json::from_json<MyThing>( json_string );atau untuk dokumen array yang root dokumennya berupa array, terdapat metode pembantu untuk memudahkannya, dan dapat diurai seperti berikut:
std::vector<MyThing> things = daw::json::from_json_array<MyThing>( json_string2 ); Jika struktur dokumen JSON tidak diketahui, seseorang dapat membuat json_value yang bertindak sebagai tampilan dan memungkinkan iterasi dan penguraian tarik sesuai permintaan. Berikut ini contoh pembukaan json_value dari data JSON:
json_value val = daw::json::json_value( json_string ); Metode from_json dan to_json memungkinkan akses sebagian besar kebutuhan parsing dan serialisasi.
Parser berbasis acara (SAX) dapat dipanggil melalui daw::json::json_event_parser . Dibutuhkan dua argumen, dokumen json dan event handler. Pengendali acara dapat ikut serta dalam acara dengan memiliki salah satu anggota berikut:
Pemetaan kelas Anda ke dokumen JSON dilakukan dengan mengkhususkan sifat daw::json::json_data_contract . Suatu kelas yang dipetakan tidak perlu dipetakan lagi jika merupakan anggota dari kelas lain yang dipetakan. Ada dua bagian pada sifat json_data_contract , yang pertama adalah alias tipe bernama type yang memetakan anggota JSON ke konstruktor kelas kita. Hal ini mengatasi kebutuhan akses pribadi ke kelas, dengan asumsi bahwa data yang akan kita serialkan juga diperlukan untuk membangun kelas. Misalnya:
struct Thing {
int a;
int b;
}; Konstruksi untuk Thing memerlukan 2 bilangan bulat dan jika kita memiliki JSON berikut:
{
"a" : 42 ,
"b" : 1234
}Kita bisa melakukan pemetaan seperti berikut:
namespace daw ::json {
template <>
struct json_data_contract <Thing> {
static constexpr char const a[] = " a " ;
static constexpr char const b[] = " b " ;
using type = json_member_list<
json_number<a, int >,
json_number<b, int >
>;
};
} Ini mengatakan bahwa kelas JSON, dalam dokumen, akan memiliki setidaknya dua anggota "a", dan "b" yang akan berupa angka bilangan bulat. Mereka akan diteruskan ke konstruktor Thing ketika daw::json::from_json<Thing>( json_doc ); dipanggil, atau kelas lain memiliki pemetaan anggota json_class<MemberName, Thing> . Di atas adalah metode pemetaan C++17 untuk nama, ini juga berfungsi di versi C++ mendatang. Namun, di C++20 dan yang lebih baru, nama dapat dimasukkan ke dalam pemetaan misalnya json_number<"a", int> . Di atas adalah semua yang diperlukan untuk mengurai JSON, untuk membuat serial fungsi anggota statis diperlukan dalam sifat tersebut. Mengambil contoh sebelumnya dan memperluasnya, kita dapat membuat serial Thing dengan:
namespace daw ::json {
template <>
struct json_data_contract <Thing> {
static constexpr char const a[] = " a " ;
static constexpr char const b[] = " b " ;
using type = json_member_list<
json_number<a, int >,
json_number<b, int >
>;
};
static auto to_json_data ( Thing const & v ) {
return std::forward_as_tuple ( v. a , v. b );
}
} Urutan anggota yang dikembalikan sebagai Tupel harus cocok dengan pemetaan dalam tipe alias type . Hal ini memungkinkan untuk meneruskan hasil metode pengakses juga, jika anggota datanya bukan publik. Selain itu, kelas Thing harus dapat dibangun dari int, int . Pustaka mendukung konstruktor reguler dan init agregat ( Thing{ int, int } dan Thing( int, int ) ) di C++17.
to_json_data tidak harus mengembalikan tupel referensi ke anggota objek yang ada, namun dapat mengembalikan nilai terhitung juga. Ini tidak mengizinkan nilai masuk karena sering kali bersifat sementara, dan dapat mengakibatkan proses debug jarak jauh. Perpustakaan akan static_assert dalam hal ini dan menyarankan untuk menyertakan <daw/daw_tuple_forward.h> dan memanggil daw::forward_nonrvalue_as_tuple( ... ) yang menyimpan sementara dan meneruskan jenis referensi lainnya. Parser bekerja dengan membangun setiap argumen yang ada dalam panggilan ke konstruktor kelas. Pengurai argumen individual dapat disesuaikan dengan keadaan data tertentu (misalnya floating point dan bilangan integral). Kemudian dengan sifat tipe kita yang mendefinisikan argumen yang diperlukan untuk membangun kelas C++ dan urutannya, kita dapat melihat setiap anggota di JSON. Sekarang kita membuat nilai dengan hasil setiap parser; mirip dengan T{ parse<0, json_string<"name">>( data ), parse<1, json_number<"age", unsigned>>( data ), parse<json_number<2, "number>>( data )} . Untuk setiap anggota, aliran data akan dipindahkan ke depan sampai kita menemukan anggota yang perlu kita parsing, menyimpan lokasi yang diinginkan untuk diurai nanti. Proses ini memungkinkan kita untuk mengurai kelas lain sebagai anggota juga melalui json_class<"member_name", Type> tipe pemetaan. Sehingga setiap sifat pemetaan hanya harus berhubungan dengan anggota spesifiknya dan bukan detailnya. 
Dalam konteks yang tidak disebutkan namanya, seperti nilai akar, elemen array, beberapa tipe nilai kunci, dan daftar elemen varian yang namanya no_name , seseorang dapat menggunakan beberapa tipe data C++ asli alih-alih tipe pemetaan JSON. Ini termasuk, integer, floating point, bool, std::string, std::string_view, container asosiatif, container sequence, tipe Nullable/Optional like dan kelas yang dipetakan sebelumnya.
Misalnya, untuk memetakan array string.
template <>
struct daw ::json::json_data_contract<MyType> {
using type = json_member_list<json_array< " member_name " , std::string>>;
}; Seseorang dapat menggunakan vcpkg untuk mengambil rilis terbaru, portnya disebut daw-json-link
find_package ( daw-json-link )
#...
target_link_libraries ( MyTarget daw::daw-json-link ) Pustaka hanya berupa header dan dapat dikloning, bersama dengan dua dependensinya, diikuti dengan menambahkan subfolder include/ masing-masing ke jalur penyertaan kompiler
Untuk menggunakan daw_json_link di proyek cmake Anda, menambahkan perintah berikut akan memungkinkannya untuk menariknya bersama dengan dependensinya:
include ( FetchContent )
FetchContent_Declare(
daw_json_link
GIT_REPOSITORY https://github.com/beached/daw_json_link
GIT_TAG release
)
FetchContent_MakeAvailable(daw_json_link)
#...
target_link_libraries ( MyTarget daw::daw-json-link )Pada sistem dengan bash, serupa pada sistem lain juga, berikut ini dapat diinstal untuk sistem
git clone https://github.com/beached/daw_json_link
cd daw_json_link
mkdir build
cd build
cmake ..
cmake --install . Ini akan memungkinkan instalasi cmake find_package atau menggunakannya sebagai header biasa selama folder include awalan instalasi disertakan dalam jalur penyertaan kompiler
Berikut ini akan membangun dan menjalankan pengujian.
git clone https://github.com/beached/daw_json_link
cd daw_json_link
mkdir build
cd build
cmake -DDAW_ENABLE_TESTING=On ..
cmake --build .
ctest . Setelah pembangunan di sana, masing-masing contoh dapat diuji juga. city_test_bin memerlukan jalur ke file JSON kota.
./tests/city_test_bin ../test_data/cities.jsonUrutan anggota dalam struktur data secara umum harus sesuai dengan data JSON, jika memungkinkan. Parser akan lebih cepat jika tidak perlu menelusuri kembali nilai. Nilai opsional, jika tidak ada dalam data JSON, juga dapat memperlambat penguraian. Jika memungkinkan, kirimkan sebagai nol. Parser tidak mengalokasikan. Tipe data yang diuraikan mungkin dan ini memungkinkan seseorang untuk menggunakan pengalokasi khusus atau campuran karena struktur datanya akan melakukan alokasi. Default untuk array adalah menggunakan std::vector dan jika ini tidak diinginkan, Anda harus menyediakan tipenya.

Library saat ini tidak melakukan unescape/escape nama anggota saat membuat serial, diharapkan valid dan tidak lolos. Ini mungkin merupakan tambahan opsional di masa mendatang, karena memerlukan biaya.
Ada sedikit perbedaan antara C++17 dan C++20 di mana C++20 mengizinkan beberapa kode yang tidak tersedia di C++17.
namespace daw ::json {
template <>
struct json_data_contract <MyType> {
static constexpr char const member_name[] = " memberName " ;
using type = json_member_list<json_number<member_name>>;
};
}Kedua versi C++ mendukung metode ini untuk memberi nama anggota.
Saat dikompilasi dalam kompiler C++20, selain meneruskan char const * seperti pada C++17, nama anggota dapat ditentukan sebagai string literal secara langsung. Dukungan kompiler C++20 masih sangat awal dan inilah yang terbaik. Ada masalah umum dengan g++9.x dalam mode C++20, dan hanya diuji dengan g++10/11. Inilah naga
namespace daw ::json {
template <>
struct json_data_contract <MyType> {
using type = json_member_list<json_number< " member_name " >>;
};
} Setelah tipe data dipetakan dengan json_data_contract , perpustakaan menyediakan metode untuk mengurai JSON ke tipe data tersebut
MyClass my_class = from_json<MyClass>( json_str );Alternatifnya, jika masukannya dipercaya, versi yang kurang diperiksa bisa lebih cepat
MyClass my_class = from_json<MyClass, options::parse_flags<options::CheckedParseMode::no>>( json_str ); Dokumen JSON dengan root array menggunakan fungsi from_json_array untuk menguraikannya
std::vector<MyClass> my_data = from_json_array<MyClass>( json_str );Alternatifnya, jika masukannya dipercaya, versi yang kurang diperiksa bisa lebih cepat
std::vector<MyClass> my_data = from_json_array<MyClass, std::vector<MyClass>, options::parse_flags<options::CheckedParseMode::no>>( json_str );json_array_iterator Jika Anda ingin bekerja dari data array JSON, Anda bisa mendapatkan iterator dan menggunakan algoritma std untuk Iterasi array dalam data JSON dapat dilakukan melalui json_array_iterator
using iterator_t = json_array_iterator<MyClass>;
auto pos = std::find( iterator_t ( json_str ), iterator_t ( ), MyClass( ... ) );Alternatifnya, jika masukannya dipercaya, Anda dapat memanggil versi yang kurang diperiksa
using iterator_t = daw::json::json_array_iterator<MyClass, options::CheckedParseMode::no>;
auto pos = std::find( iterator_t ( json_str ), iterator_t ( ), MyClass( ... ) );json_value Untuk api seperti DOM, sering digunakan untuk hal-hal seperti GUI dan menyediakan kode ketika pemetaan tidak memadai, dapat menggunakan json_value . Ini digunakan di alat json_to_cpp.
auto jv = daw::json::json_value( json_doc );Seseorang dapat menggunakan Jalur JSON untuk mengekstrak bilangan bulat
int foo = as< int >( jv[ " path.to.int " ] ); Di sini, "path.to.int" adalah Jalur JSON yang mewakili pengeboran ke dalam kelas JSON seperti
{
"path" : {
"to" : {
"int" : 5
}
}
} Seseorang juga dapat memilih melalui sintaks seperti array di jalur JSON juga, "path[5]" akan memilih elemen/anggota ke-5 dari "path" . Jika Anda ingin membuat serial ke JSON. Sintaks JSON Path juga berfungsi dengan from_json , from_json_array , dan json_array_iterator .
to_jsonstd::string my_json_data = to_json( MyClass{} ); Atau membuat serial array, koleksi, rentang, atau tampilan sesuatu. Hanya membutuhkan std::begin(...) dan std::end(...) agar berfungsi untuk tipe tersebut. Hal ini memungkinkan serialisasi ketika tipenya bukan kumpulan hal yang dapat dibangun.
std::vector<MyClass> arry = ...;
std::string my_json_data = to_json_array( arry ); Kesalahan penguraian default adalah memunculkan daw::json::json_exception yang menyertakan informasi tentang alasan dan lokasi kegagalan.
Jika pengecualian dinonaktifkan, perpustakaan akan memanggil std::terminate setelah kesalahan parse secara default.
Sementara, penanganan kesalahan secara default adalah melemparkan daw::json::json_exception pada kesalahan, atau memanggil std::terminate jika pengecualian dinonaktifkan. Seseorang dapat mengubah perilaku ini dengan menyetel penunjuk fungsi daw::json::daw_json_error_handler . Satu-satunya persyaratan adalah fungsi tersebut tidak kembali. Contoh yang memanfaatkan ini ada di error_handling_bench_test.cpp
Pemeriksaan kesalahan dapat dimodifikasi berdasarkan parse. from_json , from_json_array , json_value , json_array_iterator , dan semuanya mendukung opsi penguraian. panggilan dapat diberikan Opsi Parser. Opsi yang tersedia didokumentasikan dalam item buku masak parser_policies.
daw::json::json_exception memiliki fungsi anggota std::string_view reason( ) const mirip dengan std::exception 's what( ) tetapi mengembalikan std::string dengan lebih banyak konteks daripada what( ) yang dilakukannya. Jika Anda ingin menonaktifkan pengecualian di lingkungan yang memilikinya, Anda dapat menentukan DAW_JSON_DONT_USE_EXCEPTIONS untuk menonaktifkan pelemparan pengecualian oleh perpustakaan atau menyetel penangan, ini tidak lagi disarankan karena penangan dapat disetel ke salah satu dari dua default daw::json::default_error_handling_throwing atau daw::json::default_error_handling_terminating .
Hal ini dapat dicapai dengan menulis spesialisasi json_data_contract di namespace daw::json . Misalnya:
# include < daw/json/daw_json_link.h >
# include < string >
# include < string_view >
# include < vector >
struct TestClass {
int i = 0 ;
double d = 0.0 ;
bool b = false ;
std::string s{};
std::vector< int > y{};
TestClass ( int Int, double Double, bool Bool, std::string S,
std::vector< int > Y)
: i(Int), d(Double), b(Bool), s(std::move( S ) ), y(std::move( Y )) {}
};
namespace daw ::json {
template <>
struct json_data_contract <TestClass> {
using type =
json_member_list<
json_number< " i " , int >,
json_number< " d " >,
json_bool< " b " >,
json_string< " s " >,
json_array< " y " , int >
>;
};
} // namespace daw::json
int main () {
std::string_view test_001_t_json_data = R"( {
"i":5,
"d":2.2e4,
"b":false,
"s":"hello world",
"y":[1,2,3,4]
} )" ;
std::string_view json_array_data = R"( [{
"i":5,
"d":2.2e4,
"b":false,
"s":"hello world",
"y":[1,2,3,4]
},{
"i":4,
"d":122e4,
"b":true,
"s":"goodbye world",
"y":[4,3,1,4]
}] )" ;
TestClass test_class = daw::json::from_json<TestClass>(test_001_t_json_data);
std::vector<TestClass> arry_of_test_class =
daw::json::from_json_array<TestClass>(test_001_t_json_data);
}Lihat di Compiler Explorer
Konstruktor agregat dan pengguna didukung. Deskripsi memberikan nilai yang diperlukan untuk membuat tipe dan urutan Anda. Urutan yang ditentukan adalah urutan penempatannya ke dalam konstruktor. Ada poin penyesuaian untuk memberikan cara membangun tipe Anda juga. Kelas seperti:
# include < daw/json/daw_json_link.h >
struct AggClass {
int a{};
double b{};
};
namespace daw ::json {
template <>
struct json_data_contract <AggClass> {
using type = json_member_list<
json_number< " a " , int >,
json_number< " b " >
>;
};
}Bekerja juga. Sama tetapi C++17
# include < daw/json/daw_json_link.h >
struct AggClass {
int a{};
double b{};
};
namespace daw ::json {
template <>
struct json_data_contract <AggClass> {
static inline constexpr char const a[] = " a " ;
static inline constexpr char const b[] = " b " ;
using type = json_member_list<
json_number<a, int >,
json_number<b>
>;
};
} Deskripsi kelas bersifat rekursif dengan subanggotanya. Dengan menggunakan AggClass sebelumnya seseorang dapat memasukkannya sebagai anggota kelas lain
// See above for AggClass
struct MyClass {
AggClass other;
std::string_view some_name;
};
namespace daw ::json {
template <>
struct json_data_contract <MyClass> {
using type = json_member_list<
json_class< " other " , AggClass>,
json_string< " id " , std::string_view>
>;
};
} Gambar di atas memetakan kelas MyClass yang memiliki kelas lain yang dijelaskan AggClass. Selain itu, Anda dapat melihat bahwa nama anggota kelas C++ tidak harus cocok dengan nama JSON yang dipetakan dan string dapat menggunakan std::string_view sebagai tipe hasil. Ini merupakan peningkatan kinerja yang penting jika Anda dapat menjamin buffer yang berisi file JSON akan tetap ada selama kelas tersebut ada.
Iterasi pada array JSON. Input iterator daw::json::json_array_iterator<JsonElement> memungkinkan seseorang untuk melakukan iterator pada array elemen JSON. Secara teknis ini merupakan iterator masukan tetapi dapat disimpan dan digunakan kembali seperti iterator maju. Itu tidak mengembalikan referensi tetapi nilai.
# include < daw/json/daw_json_link.h >
# include < daw/json/daw_json_iterator.h >
# include < iostream >
struct AggClass {
int a{};
double b{};
};
namespace daw ::json {
template <>
struct json_data_contract <AggClass> {
using type = json_member_list<
json_number< " a " , int >,
json_number< " b " >
>;
};
} // namespace daw::json
int main () {
std::string json_array_data = R"( [
{"a":5,"b":2.2},
{"a":5,"b":3.14},
{"a":5,"b":0.122e44},
{"a":5334,"b":34342.2}
] )" ;
using iterator_t = daw::json::json_array_iterator<AggClass>;
auto pos =
std::find_if (
iterator_t (json_array_data),
iterator_t (),
[](AggClass const &element) {
return element. b > 1000.0 ;
}
);
if (pos == iterator_t ()) {
std::cout << " Not found n " ;
} else {
std::cout << " Found n " ;
}
} Parsing dapat dimulai dari anggota atau elemen tertentu. Jalur anggota opsional ke from_json , from_json_array , json_value , json_array_iterator , dan sejenisnya dapat ditentukan. Formatnya adalah daftar nama anggota yang dipisahkan titik dan opsional indeks array seperti member0.member1 yang seperti penguraian dari:
{
"member0" : {
"member1" : {}
}
} atau member0[5].member1 yang akan mulai diuraikan pada "member1" dalam dokumen seperti:
{
"member0" : [
" a " ,
" b " ,
" c " ,
" d " ,
" e " ,
{
"member1" : " "
}
]
}atau
{
"member0" : {
"a" : " " ,
"b" : " " ,
"c" : " " ,
"d" : " " ,
"e" : " " ,
"f" : {
"member1" : " "
}
}
}Komentar didukung ketika kebijakan parser untuk komentar tersebut digunakan. Saat ini, ada dua bentuk kebijakan komentar.
// komentar baris dan gaya C /* */ komentar. { // This is a comment
"a" /*this is also a comment*/: "a's value"
}
# komentar baris { # This is a comment
"a" #this is also a comment
: "a's value"
}
Kebijakan komentar dapat diatur melalui PolicyCommentTypes . Lihat parser_policies untuk info lebih lanjut.
Untuk mengaktifkan serialisasi, seseorang harus membuat fungsi statis tambahan dalam spesialisasi json_data_contract Anda yang disebut to_json_data( Thing const & ); yang mengembalikan sejumlah anggota. Ini akan memberikan pemetaan dari tipe Anda ke argumen yang disediakan dalam deskripsi kelas. Untuk membuat serial ke string JSON, seseorang memanggil to_json( my_thing ); di mana my_thing adalah tipe terdaftar atau salah satu tipe dasar seperti Kontainer, Peta, String, bool, dan angka. Hasil dari metode statis to_json_data( Thing const & ) adalah tuple yang elemen-elemennya cocok dengan urutan alias type json_data_contract yang menyertainya. Karena cara metode ini digunakan, tuple dengan elemen rvalue akan menghasilkan bug penggunaan setelah penghancuran. Kompiler akan error jika ini terjadi. Menyertakan <daw/daw_tuple_forward.h> dan metode daw::forward_nonrvalue_as_tuple akan menyimpan nilai alih-alih meneruskannya sebagai referensi. Seringkali ini merupakan hasil perhitungan elemen tuple. Dengan menggunakan contoh di atas mari tambahkan metode to_json_data
# include < daw/json/daw_json_link.h >
# include < tuple >
struct AggClass {
int a;
double b;
};
namespace daw ::json {
template <>
struct json_data_contract <AggClass> {
using type = json_member_list<
json_number< " a " , int >,
json_number< " b " >
>;
static constexpr auto to_json_data ( AggClass const & value ) {
return std::forward_as_tuple ( value. a , value. b );
}
};
}
// ...
AggData value = // ...;
std::string test_001_t_json_data = to_json( value );
// or
std::vector<AggData> values = // ...;
std::string json_array_data = to_json_array( values ); Sebagai alternatif, seseorang dapat menghasilkan keluaran ke jenis WritableOutput apa pun, secara default ini mencakup FILE*, iostreams, container Karakter, dan penunjuk Karakter. Di json_data_constract tipe Anda. Atau jika ikut serta, seseorang bisa mendapatkan operator ostream<< untuk tipenya yang memasukkan json ke dalam aliran keluaran dengan menambahkan alias tipe bernama opt_into_iostreams tipe aliasnya tidak masalah, dan sertakan daw/json/daw_json_iostream.h . Misalnya
# include < daw/json/daw_json_link.h >
# include < daw/json/daw_json_iostream.h >
# include < tuple >
struct AggClass {
int a{};
double b{};
};
namespace daw ::json {
template <>
struct json_data_contract <AggClass> {
using opt_into_iostreams = void ;
using type = json_member_list<
json_number< " a " , int >,
json_number< " b " >
>;
static inline auto to_json_data ( AggClass const & value ) {
return std::forward_as_tuple ( value. a , value. b );
}
};
}
// ...
AggData value = // ...;
std::cout << value << ' n ' ;
// or
std::vector<AggData> values = // ...;
std::cout << values << ' n ' ;Contoh kerja dapat ditemukan di daw_json_iostream_test.cpp atau di compiler explorer
error: pointer to subobject of string literal is not allowed in a template argument constexpr char const member_name[] = " member_name " ;
// ...
json_link<member_name, Type>Ada beberapa definisi yang memengaruhi cara kerja JSON Link
DAW_JSON_DONT_USE_EXCEPTIONS - Mengontrol apakah pengecualian diperbolehkan. Jika tidak, kesalahan std::terminate() akan terjadi. Ini otomatis jika pengecualian dinonaktifkan (misalnya -fno-exceptions )DAW_ALLOW_SSE42 - Izinkan mode SSE42 eksperimental, umumnya mode constexpr lebih cepatDAW_JSON_NO_CONST_EXPR - Ini dapat digunakan untuk mengizinkan kelas tanpa memindahkan/menyalin anggota khusus untuk dibuat dari data JSON sebelum C++ 20. Mode ini tidak berfungsi dalam ekspresi konstan sebelum C++20 ketika tanda ini tidak lagi diperlukan. Kompiler lama mungkin masih berfungsi tetapi dalam pengujian beberapa menghasilkan kesalahan ICE atau kompilasi karena dukungan kereta C++17. Seringkali tidak menggunakan constexpr juga dapat membantu.
json_key_value .std::multimap<std::string, T> atau std::vector<std::pair<std::string, T>> semua anggota dipertahankan dengan yang pertama secara berurutan. Atau, tipe json_value akan memungkinkan iterasi pada anggota kelas dan penguraian lambat dari anggota kelas yang benar. Lihat Nilai-Nilai Utama Buku Masak yang menunjukkan metode ini.