{"id":20006851,"url":"https://github.com/misteo/meojson","last_synced_at":"2025-04-05T07:02:57.377Z","repository":{"id":44789330,"uuid":"279249878","full_name":"MistEO/meojson","owner":"MistEO","description":"✨ Next-gen C++ JSON/JSON5 Serialization Engine | Zero Dependency | Header-Only | Unleash JSON Potential","archived":false,"fork":false,"pushed_at":"2025-02-16T08:03:29.000Z","size":1689,"stargazers_count":113,"open_issues_count":8,"forks_count":22,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-03-29T06:05:04.264Z","etag":null,"topics":["cpp","json","json5","parser","serialization"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MistEO.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-07-13T08:58:10.000Z","updated_at":"2025-03-18T22:19:51.000Z","dependencies_parsed_at":"2023-12-26T03:32:42.946Z","dependency_job_id":"377d94fd-e64b-41ea-a2bf-d5850b841f0d","html_url":"https://github.com/MistEO/meojson","commit_stats":null,"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MistEO%2Fmeojson","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MistEO%2Fmeojson/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MistEO%2Fmeojson/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MistEO%2Fmeojson/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MistEO","download_url":"https://codeload.github.com/MistEO/meojson/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247299831,"owners_count":20916190,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","json","json5","parser","serialization"],"created_at":"2024-11-13T06:13:57.466Z","updated_at":"2025-04-05T07:02:57.339Z","avatar_url":"https://github.com/MistEO.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# meojson\n\n✨下一代 C++ Json/Json5 序列化引擎 | 零依赖 | Header Only | 释放你的 JSON 潜能\n\n✨ Next-gen C++ JSON/JSON5 Serialization Engine | Zero Dependency | Header-Only | Unleash JSON Potential\n\n\u003c/div\u003e\n\n[English](./README_en.md)\n\n## 使用说明\n\n- 在您的项目中包含头文件即可使用  \n\n```c++\n#include \"json.hpp\"\n```\n\n- 若您需要解析 Json5, 则请包含 `json5.hpp` 头文件\n\n```c++\n#include \"json5.hpp\"\n```\n\n- **meojson** 仅依赖 STL, 但需要 c++17 标准\n\n## 序列化\n\n以下是一些基本特性：\n\n```c++\njson::value j;\nj[\"pi\"] = 3.14;\nj[\"happy\"] = true;\nj[\"answer\"][\"everything\"] = 42;\nj[\"object\"] = { {\"currency\", \"USD\"}, {\"value\", 42.99} };\n```\n\n以及一些有趣的特性：\n\n```c++\nstd::set\u003cint\u003e set { 1, 2, 3 };\nj[\"set\"] = set;\n\n// 什么鬼类型！\nstd::unordered_map\u003cstd::string, std::list\u003cstd::map\u003cstd::string, std::deque\u003cint\u003e\u003e\u003e\u003e map {\n    { \"key_1\", { { { \"inner_key_1\", { 7, 8, 9 } } }, { { \"inner_key_2\", { 10 } } } } },\n};\nj[\"map\"] = map;\n\n// output:\n// {\"answer\":{\"everything\":42},\"happy\":true,\"map\":{\"key_1\":[{\"inner_key_1\":[7,8,9]},{\"inner_key_2\":[10]}]},\"object\":{\"currency\":\"USD\",\"value\":42.990000},\"pi\":3.140000,\"set\":[1,2,3]}\nstd::cout \u003c\u003c j \u003c\u003c std::endl;\n```\n\n别眨眼，我们又转回来了！\n\n```c++\ndouble pi = (double)j[\"pi\"];\nint answer = (int)j[\"answer\"][\"everything\"];\n\nstd::set\u003cint\u003e new_set = (std::set\u003cint\u003e)j[\"set\"];\n// 又是这个鬼类型\nauto new_map = (std::unordered_map\u003cstd::string, std::list\u003cstd::map\u003cstd::string, std::deque\u003cint\u003e\u003e\u003e\u003e)j[\"map\"];\n```\n\n然而对于运行时的 JSON，最好先检查它是否可以转换。\n\n```c++\nif (j[\"happy\"].is\u003cstd::vector\u003cint\u003e\u003e()) {\n    std::vector\u003cint\u003e vec = (std::vector\u003cint\u003e)j[\"happy\"];\n}\nelse {\n    std::cout \u003c\u003c \"天啊, j[\\\"happy\\\"] 不是一个数组！\" \u003c\u003c std::endl;\n    std::cout \u003c\u003c \"还好我检查了，不然就炸了！\" \u003c\u003c std::endl;\n}\n```\n\n我猜你已经明白了，是的，**meojson** 不仅仅是一个 JSON 库，还是一个序列化库！\n\n```c++\nstruct MyStruct\n{\n    int x = 0;\n    std::vector\u003cdouble\u003e vec;\n    // 怎么总是你！\n    std::unordered_map\u003cstd::string, std::list\u003cstd::map\u003cstd::string, std::deque\u003cint\u003e\u003e\u003e\u003e map;\n\n    // 让我们加点魔法\n    MEO_JSONIZATION(x, vec, map);\n};\n\nMyStruct mine;\nmine.vec.emplace_back(0.5);\nmine.map = { { \"key_1\", { { { \"inner_key_1\", { 7, 8, 9 } } }, { { \"inner_key_2\", { 10 } } } } } };\n\n// 是的，它是那么直观和流畅！\njson::value j_mine = mine;\n\n// output: {\"map\":{\"key_1\":[{\"inner_key_1\":[7,8,9]},{\"inner_key_2\":[10]}]},\"vec\":[0.500000],\"x\":0}\nstd::cout \u003c\u003c j_mine \u003c\u003c std::endl;\n\n// 恰恰，我们也可以把它转回来！\nMyStruct new_mine = (MyStruct)j_mine;\n```\n\n嵌套调用也是易如反掌！\n\n```c++\nstruct Outter\n{\n    int outter_a = 10;\n    std::vector\u003cMyStruct\u003e my_vec;\n\n    MEO_JSONIZATION(outter_a, my_vec);\n};\n\nOutter outter;\noutter.my_vec.emplace_back(mine);\n\njson::value j_outter = outter;\n\n// output:\n// {\"my_vec\":[{\"map\":{\"key_1\":[{\"inner_key_1\":[7,8,9]},{\"inner_key_2\":[10]}]},\"vec\":[0.500000],\"x\":0}],\"outter_a\":10}\nstd::cout \u003c\u003c j_outter.to_string() \u003c\u003c std::endl;\n\n// 同样的反序列化\nOutter new_o = (Outter)j_outter;\n```\n\n对于可选字段，我们可以在其中添加 `MEO_OPT`，这样在转换时，如果此字段在 JSON 中不存在，它将被跳过。\n\n```c++\nstruct OptionalFields\n{\n    int a = 0;\n    double b = 0;\n    std::vector\u003cint\u003e c;\n\n    MEO_JSONIZATION(a, MEO_OPT b, MEO_OPT c);\n};\n\njson::value ja = {\n    { \"a\", 100 },\n};\nif (ja.is\u003cOptionalFields\u003e()) {\n    OptionalFields var = (OptionalFields)ja;\n    // output: 100\n    std::cout \u003c\u003c var.a \u003c\u003c std::endl;\n}\n```\n\n对于第三方不可侵入的类型，则需要实现 `to_json`, `check_json`, `from_json`\n\n```c++\nstruct ThirdPartyStruct\n{\n    int a = 100;\n};\n\nnamespace json::ext\n{\ntemplate \u003c\u003e\nclass jsonization\u003cThirdPartyStruct\u003e\n{\npublic:\n    json::value to_json(const ThirdPartyStruct\u0026 t) const { return t.a; }\n    bool check_json(const json::value\u0026 j) const { return j.is_number(); }\n    bool from_json(const json::value\u0026 j, ThirdPartyStruct\u0026 out) const\n    {\n        out.a = j.as_integer();\n        return true;\n    }\n};\n} // namespace json::ext\n\n// 然后可以将其用作 JSON\nThirdPartyStruct third;\njson::value jthird = third;\nThirdPartyStruct new_third = (ThirdPartyStruct)jthird;\n\n// 或者添加到结构中\nstruct Outter2\n{\n    int outter_a = 10;\n    ThirdPartyStruct third;\n\n    MEO_JSONIZATION(outter_a, my_vec, third);\n};\n```\n\n如果你不喜欢愚蠢的侵入式函数，也可以使用 `json::serialize` 和 `json::deserialize` 进行更优雅的转换:\n\n```c++\nstruct Serializer\n{\n    json::value operator()(const ThirdPartyStruct\u0026 t) const { return t.a; }\n};\nstruct Deserializer\n{\n    bool operator()(const json::value\u0026 j, ThirdPartyStruct\u0026 t) const\n    {\n        if (!j.is_number()) return false;\n        t.a = j.as_integer();\n        return true;\n    }\n};\n\nstd::map\u003cstd::string, ThirdPartyStruct\u003e third;\nthird[\"key\"] = { 100 };\njson::value jthird = json::serialize(third, Serializer {});\n\nstd::cout \u003c\u003c jthird \u003c\u003c std::endl;\n\nstd::map\u003cstd::string, ThirdPartyStruct\u003e new_third;\nbool ret = json::deserialize(jthird, new_third, Deserializer {});\n```\n\n还有一些琐碎的特性：\n\n```c++\n// 通过 `emplace` 向数组或对象添加元素\nj[\"set\"].emplace(10);\nj[\"object\"].emplace(\"key3\", \"value3\");\n\n// 合并两个数组\nj[\"set\"] += json::array { 11, 12 };\n\n// 合并两个对象\nj[\"object\"] |= {\n    { \"key4\", 4 },\n    { \"key5\", false },\n};\n\n// 转为字符串\nstd::string oneline = j.dumps();\nstd::string format = j.dumps(4);\n\n// 保存到文件\nstd::ofstream ofs(\"meo.json\");\nofs \u003c\u003c j;\nofs.close();\n```\n\n## 解析\n\n现在让我们谈谈解析\n\n```c++\nstd::string content = R\"(\n{\n    \"repo\": \"meojson\",\n    \"author\": {\n        \"MistEO\": \"https://github.com/MistEO\",\n        \"ChingCdesu\": \"https://github.com/ChingCdesu\"\n    },\n    \"list\": [ 1, 2, 3 ],\n    \"str\": \"abc\\n123\",\n    \"num\": 3.1416,\n    \"A_obj\": {\n        \"B_arr\": [\n            { \"C_str\": \"i am a distraction\" },\n            { \"C_str\": \"you found me!\" }\n        ]\n    },\n    \"my_type\": { \"i\": 99 }\n})\";\n\n// 它是一个 std::optional\u003cjson::value\u003e\nauto ret = json::parse(content);\n\nif (!ret) {\n    std::cerr \u003c\u003c \"解析失败\" \u003c\u003c std::endl;\n    return;\n}\njson::value\u0026 value = *ret;\n\n// Output: meojson\nstd::cout \u003c\u003c (std::string)value[\"repo\"] \u003c\u003c std::endl;\n\n/* Output:\n    ChingCdesu's homepage: https://github.com/ChingCdesu\n    MistEO's homepage: https://github.com/MistEO\n*/\nfor (auto\u0026\u0026 [name, homepage] : (json::object)value[\"author\"]) {\n    std::cout \u003c\u003c name \u003c\u003c \"'s homepage: \" \u003c\u003c (std::string)homepage \u003c\u003c std::endl;\n}\n// num = 3.141600\ndouble num = (double)value[\"num\"];\n\n// get_value = \"default_value\"\nstd::string get_value = value.get(\"maybe_exists\", \"default_value\");\nstd::cout \u003c\u003c get_value \u003c\u003c std::endl;\n```\n\n和大多数解析库一样，很无聊，你肯定不想看这个。  \n所以让我给你看点有趣的东西：\n\n```c++\n// 多么神奇的 `get`，你可以连续传参 key 或 pos！\n// nested_get = you found me!\nstd::string nested_get = value.get(\"A_obj\", \"B_arr\", 1, \"C_str\", \"default_value\");\n\n// `find` 可以帮助你找到并检查类型是否正确\n// 如果没有 `num`，则 opt_n 将为 std::nullopt\nauto opt_n = value.find\u003cdouble\u003e(\"num\");\nif (opt_n) {\n    // Output: 3.141600\n    std::cout \u003c\u003c *opt_n \u003c\u003c std::endl;\n}\n\n// 如你所想，`get` and `find` 也可以用于自定义类型\nstruct MyType\n{\n    int i = 0;\n\n    MEO_JSONIZATION(i);\n};\nMyType get_custom_value = value.get(\"my_type\", MyType {});\nauto find_custom_opt = value.find\u003cMyType\u003e(\"my_type\");\n```\n\n还有一些你在序列化中已经见过的技巧\n\n```c++\nbool is_vec = value[\"list\"].is\u003cstd::vector\u003cint\u003e\u003e();\nstd::vector\u003cint\u003e to_vec = value[\"list\"].as_collection\u003cint\u003e();\n// Output: 1, 2, 3\nfor (auto\u0026\u0026 i : to_vec) {\n    std::cout \u003c\u003c i \u003c\u003c std::endl;\n}\n\nstd::list\u003cint\u003e to_list = value[\"list\"].as_collection\u003cint, std::list\u003e();\nto_list = (std::list\u003cint\u003e)value[\"list\"]; // 和上面相同\nauto to_map = value[\"author\"].as\u003cstd::map\u003cstd::string, std::string\u003e\u003e();\nauto to_hashmap = value[\"author\"].as_map\u003cstd::string, std::unordered_map\u003e();\n```\n\n以及不知道有啥用的字面语法\n\n```c++\n// Output: \"literals\"\nusing namespace json::literals;\nauto val = \"{\\\"hi\\\":\\\"literals\\\"}\"_json;\nstd::cout \u003c\u003c val[\"hi\"] \u003c\u003c std::endl;\n```\n\n但好消息是，我们也可以解析 JSON5！\n\n```c++\nstd::string_view content5 = R\"(\n// 这是一个 Json5 内容\n{\n  名字: \"MistEO\",                  /* 键的引号可以省略 */\n  😊: '😄',                       // 表情符可以用作键\n  thanks: 'ありがとう',             /* 单引号也可以用作字符串 */\n  \\u006Bey: ['value',],            // 正常字符和转义可以混合使用\n  inf: +Infinity, nan: NaN,        // 数字可以以 '+' 开头\n  fractional: .3, integer: 42.,    // 允许以小数点开头或结尾\n  byte_max: 0xff,                  // 支持十六进制数\n  light_speed: +3e8,               // 以及科学计数法\n})\";\n\nauto ret = json::parse5(content5);\nif (!ret) {\n    std::cerr \u003c\u003c \"解析失败\" \u003c\u003c std::endl;\n    return;\n}\njson::value\u0026 value = *ret;\n\n// Output: MistEO\nstd::cout \u003c\u003c value[\"名字\"] \u003c\u003c std::endl;\n// str = \"value\"\nstd::string str = (std::string)value[\"key\"][0];\n```\n\n## 调试\n\n如果您正在使用 Visual Studio，并希望 `json::value` 在调试器中显示的更为直观，请为您的解决方案/项目添加 `tools/meojson.natvis`，详见 [将 .natvis 文件添加到 C++ 项目](https://learn.microsoft.com/zh-cn/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2022#add-a-natvis-file-to-a-c-project)。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmisteo%2Fmeojson","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmisteo%2Fmeojson","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmisteo%2Fmeojson/lists"}