开发者

C++使用nlohmann/json库解析和处理JSON数据的操作指南

目录
  • 1. nlohmann/json库介绍
    • 1.1 下载安装
    • 1.2 配置方法
  • 2. 应用场景
    • 2.1 解析HTTP响应中的JSON数据
    • 2.2 格式化JSON数据用于展示
    • 2.3 构造JSON请求数据
    • 2.4 处理文件列表等结构化数据
  • 3. 使用JsonHandler封装nlohmann/json库相关方法
    • 3.1 JsonHandler.h头文件
    • 3.2 JsonHandler.cpp实现文件
      • 3.2.1 ParseJsonResponse方法实现
      • 3.2.2 FormatJsonForhtml方法实现
      • 3.2.3 FormatJsonValue方法实现
      • 3.2.4 FormatJsonValueFormat方法实现
      • 3.2.5 GenerateJsonHtml方法实现
  • 4. MyFrame.cpp调用JsonHandler中封装的各个方法示例
    • 4.1 示例1:处理GET请求返回的JSON数据
      • 4.2 示例2:格式化显示JSON数据
      • 5. 总结

        1. nlohmann/json库介绍

        nlohmann/json 是一个用于现代C++的JSON库,由Niels Lohmann开发。它是一个单头文件库,使用C++11标准编写,具有以下特点:

        • 简洁的API:语法直观,像访问原生C++数据结构一样操作JSON
        • 类型安全:提供了类型检查和异常处理机制
        • 高性能:比许多其他JSON库更快
        • 零依赖:只需要包含一个头文件即可使用
        • 跨平台:支持Windows、linux、MACOS等操作系统

        1.1 下载安装

        nlohmann/json库可以通过多种方式获取和安装:

        通过包管理器安装

        • vcpkg: vcpkg install nlohmann-json
        • Conan: conan install nlohmann_json/3.11.2
        • apt (Ubuntu/Debian): sudo apt install nlohmann-json3-dev

        手动下载

        • 访问github仓库:https://github.com/nlohmann/json
        • 下载单头文件版本:https://github.com/nlohmann/json/releases
        • json.hpp文件复制到项目目录中

        1.2 配置方法

        在项目中使用nlohmann库非常简单:

        包含头文件

        #include <nlohmann/json.hpp>
        // 或者使用别名
        using json = nlohmann::json;
        

        CMake配置(如果通过包管理器安装):

        find_package(nlohmann_json CONFIG REQUIRED)
        target_link_libraries(main PRIVATE nlohmann_json::nlohmann_json)
        

        手动配置

        • json.hpp文件放在项目目录中
        • 在代码中包含:#include "nlohmann/json.hpp"

        在本项目中,我们直接将json.hpp文件包含在项目中,无需额外配置。

        2. 应用场景

        在本项目中,nlohmann库主要应用于以下场景:

        2.1 解析HTTP响应中的JSON数据

        当客户端向服务器发送GET或POST请求后,服务器返回的数据通常是JSON格式。我们需要使用nlohmann/json库来解析这些数据,提取有用信息。

        2.2 格式化JSON数据用于展示

        为了在WebView中更好地展示JSON数据,我们需要将其格式化为带有语法高亮的HTML格式。

        2.3 构造JSON请求数据

        在向服务器发送POST请求时,我们需要构造JSON格式的请求体数据。

        2.4 处理文件列表等结构化数据

        服务器返回的文件列表等信息通常以JSON数组形式提供,需要使用nlohmann库进行解析和处理。

        3. 使用JsonHandler封装nlohmann/json库相关方法

        为了更好地管理和重用JSON处理代码,我们创建了JsonHandler类来封装所有与nlohmann/json库相关的操作。

        3.1 JsonHandler.h头文件

        #ifndef JSONHANDLER_H
        #define JSONHANDLER_H
        
        #include <wx/string.h>
        #include <nlohmann/json.hpp>
        usjsing json = nlohmann::json;
        
        class JsonHandler {
            public:
            JsonHandler();
            ~JsonHandler();
        
            // JSON处理相关方法
            void ParseJsonResponse(const std::jsstring& response);
            wxString FormatJsonForHtml(const wxString& jsonStr, const bool& formatBit);
            wxString FormatJsonValue(const json& j);
            wxString FormatJsonValueFormat(const json& j, int indentLevel);
            wxString GenerateJsonHtml(const wxString& jsonResponse, const bool& formatBit);
        
            // 保存原始JSON数据
            void SetRawJsonData(const wxString& rawData) { m_rawJsonData = rawData; }
            wxString GetRawJsonData() const { return m_rawJsonData; }
        
            private:
            wxString m_rawJsonData;  // 保存原始JSON数据
            };
        
        #endif // JSONHANDLER_H
        

        3.2 JsonHandler.cpp实现文件

        JsonHandler.cpp文件中实现了所有JSON处理方法:

        1. ParseJsonResponse:解析JSON响应数据
        2. FormatJsonForHtml:将JSON格式化为HTML显示格式
        3. FormatJsonValue:递归生成不带缩进的JSON HTML字符串
        4. FormatJsonValueFormat:递归生成带缩进的JSON HTML字符串
        5. GenerateJsonHtml:生成完整的JSON显示HTML页面

        下面是这些方法的具体实现:

        3.2.1 ParseJsonResponse方法实现

        // 解析 JSON 响应
        void JsonHandler::ParseJsonResponse(const std::string& response) {
            // 尝试解析 JSON
            try {
                // 使用nlohmann库解析JSON字符串
                json j = json::parse(response);
                // 将 JSON 格式化为带缩进的字符串
                std::string json_str = j.dump(4);
                // 记录日志
                wxLogInfo(wxString::FromUTF8("JSON: %s"), wxString::FromUTF8(json_str.c_str()));
                // 检查是否存在 "message" 字段
                if (j.contains("message")) {
                    // 获取message字段的值
                    std::string message = j["message"];
                    // 记录解析结果到日志
                    wxLogInfo(wxString::FromUTF8("解析结果: %s"), wxString::FromUTF8(message.c_str()));
                } else {
                    // 如果缺少message字段,记录错误日志
                    wxLogInfo(wxString::FromUTF8("JSON格式错误: 缺少message字段"));
                }
        
                // 检查是否存在 "data" 数组
                if (j.contains("data") && j["data"].is_array()) {
                    // 获取data数组
                    json dataArray = j["data"];
                    // 遍历数组中的每个元素
                    for (const auto& item : dataArray) {
                        // 检查元素是否包含name和age字段且类型正确
                        if (item.contains("name") && item["name"].is_string() && item.contains("age") && item["age"].is_number()) {
                            // 提取name和age字段的值
                            std::string name = item["name"];
                            int age = item["age"];
                            // 在日志中显示name和age信息
                            wxLogMessage(wxString::FromUTF8("Name: %s, Age: %d"), wxString::FromUTF8(name.c_str()), age);
                        }
                    }
                } else {
                    // 如果缺少data数组或格式不正确,记录错误日志
                    wxLogInfo(wxString::FromUTF8("JSON格式错误: 缺少data数组或格式不正确"));
                }
            } catch (const json::parse_error& e) {
                // JSON 解析失败
                std::string parseErrorMsg = "JSON解析失败: " + std::string(e.what());
                wxLogError(wxString::FromUTF8(parseErrorMsg.c_str()));
            }
        }
        

        3.2.2 FormatJsonForHtml方法实现

        // 格式化JSON字符串用于HTML显示
        wxString JsonHandler::FormatJsonForHtml(const wxString& jsonStr, const bool& formatBit) {
            try {
                // 确保使用UTF-8编码
                std::string utf8Json = std::string(jsonStr.ToUTF8());
                // 使用nlohmann库解析JSON字符串
                json j = json::parse(utf8Json);
                wxLogError("***************************************************");
                wxLogError(j.dump());
                wxLogError("***************************************************");
        
                // 递归生成带有HTML类名的JSON字符串
                wxString formattedJson;
                if (!formatBit) {
                    // 使用不带缩进的方式格式化JSON
                    formattedJson = FormatJsonValue(j);
                } else {
                    // 使用带缩进的方式格式化JSON
                    formattedJson = FormatJsonValueFormat(j, 0);
                }
                wxLogError(wxT("格式化JSON字符串成功!"));
                // 返回格式化后的JSON字符串
                return formattedJson;
            } catch (const json::parse_error& e) {
                // 记录JSON解析错误日志
                wxLogError("JSON Parse Err: %s", e.what());
                wxLogError(wxT("格式化JSON字符串失败!"));
                // 返回原始JSON字符串
                return jsonStr;
            }
        }
        

        3.2.3 FormatJsonValue方法实现

        // 递归生成带有HTML类名的JSON字符串(不带格式化)
        wxString JsonHandler::FormatJsonValue(const json& j) {
            // 判断JSON值是否为对象类型
            if (j.is_object()) {
                // 如果是 JSON 对象
                wxString result = wxT("{");
                bool first = true;
                // 遍历对象中的每个键值对
                for (auto& [key, value] : j.items()) {
                    if (!first) {
                        // 如果不是第一个元素,添加逗号分隔符
                        result += wxT(",");
                    }
                    first = false;
        
                    // 添加键,使用特定css类名进行标记
                    result += wxString::Format(wxT("<span class='json-key'>\"%s\"</span>: "), wxString::FromUTF8(key.c_str()));
        
                    // 递归处理值
                    result += FormatJsonValue(value);
                }
                result += wxT("}");
                wxLogError("----------------------------------------------------------------------");
                wxLogError(result);
                wxLogError("----------------------------------------------------------------------");
               编程客栈 // 返回格式化后的对象字符串
                return result;
            } else if (j.is_array()) {
                // 如果是 JSON 数组
                wxString result = wxT("[");
                bool first = true;
                // 遍历数组中的每个元素
                for (auto& item : j) {
                    if (!first) {
                        // 如果不是第一个元素,添加逗号分隔符
                        result += wxT(",");
                    }
                    first = false;
        
                    // 递归处理数组项
                    result += FormatJsonValue(item);
                }
                result += wxT("]");
                // 返回格式化后的数组字符串
                return result;
            } else if (j.is_string()) {
                // 如果是 JSON 字符串
                std::string jsonString = j.get<std::string>();
        
                // 使用 wxString::FromUTF8 正确处理UTF-8编码的字符串
                wxString wxStringValue = wxString::FromUTF8(jsonString.c_str());
                wxLogMessage("字符串值: %s", wxStringValue);
        
                // 转义HTML特殊字符以防止在HTML中显示错误
                wxString escapedValue = wxStringValue;
                escapedValue.Replace("&", "&amp;");   // 转义&符号
                escapedValue.Replace("<", "&lt;");    // 转义<符号
                escapedValue.Replace(">", "&gt;");    // 转义>符号
                escapedValue.Replace("\"", "&quot;"); // 转义双引号
                escapedValue.Replace("'", "&#39;");   // 转义单引号
        
                // 使用特定CSS类名标记字符串值并返回
                return wxString::Format("<span class='json-string'>\"%s\"</span>", escapedValue);
            } else if (j.is_number_integer() || j.is_number_unsigned()) {
                // 如果是 JSON 数字(整数)
                // 使用特定CSS类名标记整数并返回
                return wxString::Format(wxT("<span class='json-number'>%lld</span>"), j.get<int64_t>());
            } else if (j.is_number_float()) {
                // 如果是 JSON 数字(浮点数)
                // 使用特定CSS类名标记浮点数并返回
                return wxString::Format(wxT("<span class='json-number'>%.6f</span>"), j.get<double>());
            } else if (j.is_boolean()) {
                // 如果是 JSON 布尔值
                // 根据布尔值返回true或false,并使用特定CSS类名标记
                return j.get<bool>(编程客栈) ? wxT("<span class='json-boolean'>true</span>") : wxT("<span class='json-boolean'>false</span>");
            } else if (j.is_null()) {
                // 如果是 JSON null
                // 使用特定CSS类名标记null值并返回
                return wxT("<span class='json-null'>null</span>");
            }
            // 对于其他类型,使用特定CSS类名标记并返回
            return wxString::Format("<span class='json-string'>%s</span>", j.dump().c_str());
        }
        

        3.2.4 FormatJsonValueFormat方法实现

        // 递归生成带有HTML类名的JSON字符串(带格式化和缩进)
        wxString JsonHandler::FormatJsonValueFormat(const json& j, int indentLevel) {
            // 生成当前层级的缩进字符串(每级2个空格)
            wxString indent(indentLevel * 2, ' ');
            // 生成内层缩进字符串(比当前层级多一级)
            wxString indentInner((indentLevel + 1) * 2, ' ');
        
            // 判断JSON值是否为对象类型
            if (j.is_object()) {
                // 如果是 JSON 对象
                if (j.empty()) {
                    // 如果对象为空,直接返回{}
                    return wxT("{}");
                }
        
                wxString result = wxT("{\n");
                bool first = true;
                // 遍历对象中的每个键值对
                for (auto& [key, value] : j.items()) {
                    if (!first) {
                        // 如果不是第一个元素,添加逗号和换行符
                        result += wxT(",\n");
                    }
                    first = false;
        
                    // 添加键和值,带缩进
                    result += indentInner + wxString::Format(
                        wxT("<span class='json-key'>\"%s\"</span>: %s"),
                        wxString::FromUTF8(key.c_str()),
                        // 递归处理值,缩进层级加1
                        FormatJsonValueFormat(value, indentLevel + 1)
                    );
                }
                // 添加换行符、缩进和结束括号
                result += wxT("\n") + indent + wxT("}");
                // 返回格式化后的对象字符串
                return result;
            } else if (j.is_array()) {
                // 如果是 JSON 数组
                if (j.empty()) {
                    // 如果数组为空,直接返回[]
                    return wxT("[]");
                }
        
                wxString result = wxT("[\n");
                bool first = true;
                // 遍历数组中的每个元素
                for (auto& item : j) {
                    if (!first) {
                        // 如果不是第一个元素,添加逗号和换行符
                        result += wxT(",\n");
                    }
                    first = false;
        
                    // 添加数组项,带缩进
                    result += indentInner + FormatJsonValueFormat(item, indentLevel + 1);
                }
                // 添加换行符、缩进和结束括号
                result += wxT("\n") + indent + wxT("]");
                // 返回格式化后的数组字符串
                return result;
            } else if (j.is_string()) {
                // 如果是 JSON 字符串
                std::string jsonString = j.get<std::string>();
        
                // 使用 wxString::FromUTF8 正确处理UTF-8编码的字符串
                wxString wxStringValue = wxString::FromUTF8(jsonString.c_str());
                wxLogMessage("字符串值: %s", wxStringValue);
        
                // 转义HTML特殊字符以防止在HTML中显示错误
                wxString escapedValue = wxStringValue;
                escapedValue.Replace("&", "&amp;");   // 转义&符号
                escapedValue.Replace("<", "&lt;");    // 转义<符号
                escapedValue.Replace(">", "&gt;");    // 转义>符号
                escapedValue.Replace("\"", "&quot;"); // 转义双引号
                escapedValue.Replace("'", "&#39;");   // 转义单引号
        
                // 使用特定CSS类名标记字符串值并返回
                return wxString::Format("<span class='json-string'>\"%s\"</span>", escapedValue);
            } else if (j.is_number_integer() || j.is_number_unsigned()) {
                // 如果是 JSON 数字(整数)
                // 使用特定CSS类名标记整数并返回
                return wxString::Format(wxT("<span class='json-number'>%lld</span>"), j.get<int64_t>());
            } else if (j.is_number_float()) {
                // 如果是 JSON 数字(浮点数)
                // 使用特定CSS类名标记浮点数并返回
                return wxString::Format(wxT("<span class='json-number'>%.6f</span>"), j.get<double>());
            } else if (j.is_boolean()) {
                // 如果是 JSON 布尔值
                // 根据布尔值返回true或false,并使用特定CSS类名标记
                return j.get<bool>() ? wxT("<span class='json-boolean'>true</span>") : wxT("<span class='json-boolean'>false</span>");
            } else if (j.is_null()) {
                // 如果是 JSON null
                // 使用特定CSS类名标记null值并返回
                return wxT("<span class='json-null'>null</span>");
            }
        
            // 对于其他类型,使用特定CSS类名标记并返回
            return wxString::Format("<span class='json-string'>%s</span>", j.dump().c_str());
        }
        

        3.2.5 GenerateJsonHtml方法实现

        // 生成 HTML 页面
        wxString JsonHandler::GenerateJsonHtml(const wxString& jsonResponse, const bool& formatBit) {
            wxLogError("jsonResponse:---------------------------------------");
            wxLogError(jsonResponse);
            wxLogError("jsonResponse:---------------------------------------");
            // 格式化JSON数据
            wxString formattedJson = FormatJsonForHtml(jsonResponse, formatBit);
        
            // 构造完整的 HTML 字符串
            wxString html = wxString::Format(
                R"(<!DOCTYPE html>
        <html>
        <head>
            <meta charset='UTF-8'>
            <title>JSON响应</title>
            <style>
                body { 
                    font-family: 'Segoe UI', Arial, sans-serif; 
                    background-color: #f5f5f5; 
                    margin: 0; 
                    padding: 20px; 
                }
                .json-container { 
                    background-color: white; 
                    border-radius: 8px; 
                    box-shadow: 0 2px 10px rgba(0,0,0,0.1); 
                    padding: 20px; 
                    overflow-x: auto; 
                }
                h1 { 
                    color: #333; 
                    border-bottom: 1px solid #eee; 
                    padding-bottom: 10px; 
                    margin-top: 0; 
                }
                pre { 
                    font-family: 'Consolas', 'Courier New', monospace;
                    font-size: 14px;
                    line-height: 1.4;
                    margin: 0;
                    white-space: pre-wrap; /* 保留空格和换行 */
                }
                .json-key { color: #e74c3c; font-weight: bold; }
                .json-string { color: #27ae60; }
                .json-number { color: #3498db; font-weight: bold; }
                .json-boolean { color: #9b59b6; font-weight: bold; }
                .json-null { color: #95a5a6; font-weight: bold; }
                .toggle { cursor: pointer; }
            </style>
            <script src="./static/highlight.min.js"></script>
            <link rel="stylesheet" href="./static/default.min.css" rel="external nofollow" >
            <script>
                document.addEventListener('DOMContentLoaded', function() {
                    hljs.highlightall();
                    const toggles = document.querySelectorAll('.toggle');
                    toggles.forEach(toggle => {
                        toggle.addEventListener('click', function() {
                            const content = this.nextElementSibling;
                            if (content.style.display === 'none') {
                                content.style.display = 'block';
                            } else {
                                content.style.display = 'none';
                            }
                        });
                    });
                });
            </script>
        </head>
        <body>
            <h1>服务器响应</h1>
            <div class='json-container'><pre>%s</pre></div>
        </body>
        </html>)",
                formattedJson
            );
        
            // 日志输出,用于调试
            wxLogInfo(wxString::FromUTF8("生成的完整HTML:\n%s"), html);
        
            // 返回生成的HTML页面
            return html;
        }
        

        4. MyFrame.cpp调用JsonHandler中封装的各个方法示例

        在主框架类MyFrame中,我们通过jsonHandler实例调用JsonHandler类中封装的方法。

        4.1 示例1:处理GET请求返回的JSON数据

        // 获取文件列表的事件处理函数
        void MyFrame::OnGetFileLists(wxCommandEvent& event) {
            // 发送GET请求获取文件列表
            std::string url = "/files";
            std::string response = httpClient.HttpGet(url);
            
            // 检查响应是否为空
            if (response.empty()) {
                // 如果返回的响应为空,可能是请求失败
                wxLogError("GET request failed or returned empty response.");
                m_textCtrl->SetValue("GET Request Failed: Empty response.");
                return;
                }
                
            // 保存原始JSON数据供后http://www.devze.com续使用
            jsonHandler.SetRawJsonData(wxString::FromUTF8(response.c_str()));
            
            // 在浏览器控件中显示格式化的JSON数据
            wxString html = jsonHandler.GenerateJsonHtml(wxString::FromUTF8(response.c_str()), false);
            m_webView->SetPage(html, "UTF-8");
            
            // 解析JSON数据并填充下拉框
            try {
                // 使用nlohmann库解析JSON字符串
                json j = json::parse(response);
                
                // 清空下拉框中的现有内容
                m_comboBox->Clear();
        
                // 检查是否存在 "data" 对象以及 "data.filelist" 数组
                if (j.contains("data") && j["data"].is_object()) {
                    // 获取data对象
                    json dataObj = j["data"];
        
                    // 检查是否存在 "filelist" 数组
                    if (dataObj.contains("filelist") && dataObj["filelist"].is_array()) {
                        // 获取文件列表数组
                        json fileArray = dataObj["filelist"];
                        // 遍历数组中的每个文件项
                        for (const auto& item : fileArray) {
                            // 检查项是否包含name字段且为字符串类型
                            if (item.contains("name") && item["name"].is_string()) {
                                // 提取文件名
                                std::string name = item["name"];
                                // 将文件名添加到下拉框中
                                m_comboBox->Append(wxString::FromUTF8(name.c_str()));
                                }
                            }
                        }
                    }
                }
            // 捕获JSON解析错误
            catch (const json::parse_error& e) {
                // JSON 解析失败
                std::string parseErrorMsg = "JSON解析失败: " + std::string(e.what());
                wxLogError(wxString::FromUTF8(parseErrorMsg.c_str()));
                }
            }
        

        4.2 示例2:格式化显示JSON数据

        // 格式化JSON显示的事件处理函数
        void MyFrame::OnFormatJson(wxCommandEvent& event) {
            // 使用格式化方式生成JSON HTML页面
            wxString html = jsonHandler.GenerateJsonHtml(jsonHandler.GetRawJsonData(), true);
            
            // 清除WebView的历史记录
            m_webView->ClearHistory();
            // 重新加载页面
            m_webView->Reload();
            // 在WebView中显示格式化的JSON数据
            m_webView->SetPage(html, "UTF-8");
            }
        

        5. 总结

        通过使用nlohmann/json库和封装的JsonHandler类,我们能够:

        1. 简化JSON数据的解析和处理过程
        2. 提供格式化的JSON数据显示功能
        3. 实现JSON数据的保存和重用
        4. 保证代码的模块化和可维护性

        nlohmann/json库的使用大大简化了C++中JSON数据的处理,其直观的API设计使得JSON操作就像访问原生数据结构一样简单。通过封装在JsonHandler类中,我们实现了代码的重用和更好的维护性。

        以上就是C++使用nlohmann/json库解析和处理JSON数据的操作指南的详细内容,更多关于C++ nlohmann/json解析和处理JSON的资料请关注编程客栈(www.devze.com)其它相关文章!

        0

        上一篇:

        下一篇:

        精彩评论

        暂无评论...
        验证码 换一张
        取 消

        最新开发

        开发排行榜