【问题标题】:Serializing and deserializing JSON with Boost使用 Boost 序列化和反序列化 JSON
【发布时间】:2012-09-05 20:16:55
【问题描述】:

我是 C++ 的新手。使用booststd::Map 类型的数据进行序列化和反序列化的最简单方法是什么。我发现了一些使用 PropertyTree 的例子,但它们对我来说是模糊的。

【问题讨论】:

    标签: c++ json boost boost-propertytree


    【解决方案1】:

    请注意,property_tree 将键解释为路径,例如放置一对“a.b”=“z”将创建一个 {“a”:{“b”:“z”}} JSON,而不是一个 {“a.b”:“z”}。否则,使用property_tree 是微不足道的。这是一个小例子。

    #include <sstream>
    #include <map>
    #include <boost/property_tree/ptree.hpp>
    #include <boost/property_tree/json_parser.hpp>
    
    using boost::property_tree::ptree;
    using boost::property_tree::read_json;
    using boost::property_tree::write_json;
    
    void example() {
      // Write json.
      ptree pt;
      pt.put ("foo", "bar");
      std::ostringstream buf; 
      write_json (buf, pt, false);
      std::string json = buf.str(); // {"foo":"bar"}
    
      // Read json.
      ptree pt2;
      std::istringstream is (json);
      read_json (is, pt2);
      std::string foo = pt2.get<std::string> ("foo");
    }
    
    std::string map2json (const std::map<std::string, std::string>& map) {
      ptree pt; 
      for (auto& entry: map) 
          pt.put (entry.first, entry.second);
      std::ostringstream buf; 
      write_json (buf, pt, false); 
      return buf.str();
    }
    

    【讨论】:

    • 我试过这个(第一次或多或少地使用 Boost 1.57.0),VS 2013 给了我 C4512 警告(无法生成赋值运算符)。除了抑制警告之外,如何解决这个问题?
    • @Dabbler:我没有收到 GCC 4.9.1 (g++ -c -Wall -O2 -std=c++11 pt.cpp) 的警告。没有VS。同样来自谷歌搜索,我会说警告来自更深的地方,因为给定代码中没有定义类。因此,要回答您的问题,我认为您应该隔离警告,检查它是否是由 property_tree 中的 Boost 代码产生的,如果是,则查找相应的 Boost 问题,如果没有人这样做,则提交一个新问题。参看。 boost.org/development/bugs.html
    • 很好的答案。数组呢?
    【解决方案2】:

    Boost 版本 1.75 及更高版本现在具有强大的原生 JSON 库:

    https://www.boost.org/doc/libs/develop/libs/json/doc/html/index.html

    我不再建议使用 Boost.PropertyTree 的 JSON 算法,因为它们不完全符合规范。

    【讨论】:

      【解决方案3】:

      有些公司要求我实现比 boost 库更快的 JSON 序列化库。我做到了——它比 boost lib 快了约 10 倍。我将代码发布给任何人 使用。

      #pragma once
      #include <string>
      #include <vector>
      #include <regex>
      #include <fstream>
      
      enum class JsonNodeType { Array, Object, String };
      
      class JsonNode
      {
          JsonNodeType m_nodeType;
          
          std::vector<JsonNode*>* m_values{0};
          std::vector<std::string>* m_keys{0};
          std::string m_value{};
          inline static int m_indent;
          inline static bool m_formatOutput;
          const int m_indentInc{4};
      
      public:
      
          JsonNode(JsonNodeType type) 
          {
              m_nodeType = type;
              
              switch (m_nodeType) {
                  case JsonNodeType::Object: m_keys = new std::vector<std::string>();
                                             [[fallthrough]];
                  case JsonNodeType::Array: m_values = new std::vector<JsonNode*>();
              }
          };
      
          JsonNode(std::string value) 
          {
              m_nodeType = JsonNodeType::String;
              m_value = value;
          }
      
          ~JsonNode() 
          {
      
              if (m_values)       
                  for (JsonNode* node : *m_values)
                      delete node;
                      
              delete m_values; 
              delete m_keys; 
          }
      
          void Add(JsonNode* node) 
          {               
              assert(m_nodeType == JsonNodeType::Array);
              
              m_values->push_back(node);
          }
      
          void Add(const char* key, JsonNode* node) 
          {       
              assert(m_nodeType == JsonNodeType::Object);
      
              m_values->push_back(node);
              m_keys->push_back(key);
          }
      
          void Add(const char* key, std::string value) 
          {       
              assert(m_nodeType == JsonNodeType::Object);
      
              m_keys->push_back(key);
              m_values->push_back(new JsonNode(value));
          }
      
          void Add(std::string value) 
          {
              assert(m_nodeType == JsonNodeType::Array);
      
              m_values->push_back(new JsonNode(value));
          }
      
          void Add(int value) 
          {
              assert(m_nodeType == JsonNodeType::Array);
      
              m_values->push_back(new JsonNode(std::to_string(value)));
          }
      
          void Add(const char* key, bool value) 
          {
              assert(m_nodeType == JsonNodeType::Object);
      
              m_keys->push_back(key);
              m_values->push_back(new JsonNode(value ? "true" : "false"));
          }
      
      
          void OutputToStream(std::ostream& ofs, bool formatOutput = true) 
          {
              m_indent = 0;       
              m_formatOutput = formatOutput;
      
              OutputNodeToStream(ofs);
      
              ofs << std::endl;
          }
      
          std::string EscapeString(std::string& str) 
          {   
              std::regex html2json("\\\\|\\/|\\\"");
              std::regex newline("\n");
      
              std::string tmp = std::regex_replace(str, html2json, "\\$&");   
              return std::regex_replace(tmp, newline, "\\n");
          }
      
      private: 
      
          void OutputNodeToStream(std::ostream& ofs) 
          {
              switch (m_nodeType) {
      
                  case JsonNodeType::String:
                      ofs << "\"" << m_value << "\"";
                      break;
      
                  case JsonNodeType::Object:
                      OutputObjectToStream(ofs);
                      break;
      
                  case JsonNodeType::Array:
                      OutputArrayToStream(ofs);
                      break;
              }
      
          }
      
          void ChangeIndent(std::ostream& ofs, int indentDelta) 
          {
      
              if (!m_formatOutput)
                  return;
      
              m_indent += indentDelta;
              
              ofs << std::endl;
          }
      
          void OutputIndents(std::ostream& ofs) 
          {
      
              if (!m_formatOutput)
                  return;
      
              for (int i = 0; i < m_indent; i++)
                  ofs << " ";
          }
      
          void OutputObjectToStream(std::ostream& ofs) 
          {
      
              assert(m_nodeType == JsonNodeType::Object);
              assert(m_keys->size() == m_values->size());
      
              if (m_keys->empty()) 
              {
                  ofs << "\"\"";
                  return;
              }
      
              ofs << "{";     
      
              ChangeIndent(ofs, m_indentInc);
              
              for (int i = 0; i < m_keys->size(); i++) 
              {
                  
                  if (i > 0)
                      ofs << ",";
      
                  if (i > 0 && m_formatOutput)
                      ofs << std::endl;
      
                  
                  OutputIndents(ofs);
      
                  ofs << "\"" << m_keys->at(i) << "\": ";
      
                  m_values->at(i)->OutputNodeToStream(ofs);
              }   
              
              ChangeIndent(ofs, -m_indentInc);
              OutputIndents(ofs);
              ofs << "}";     
          }
      
          void OutputArrayToStream(std::ostream& ofs) 
          {
          
              assert(m_nodeType == JsonNodeType::Array);
      
              if (m_values->empty()) 
              {
                  ofs << "\"\"";
                  return;
              }
      
              ofs << "[";
      
              ChangeIndent(ofs, m_indentInc);
      
              for (int i = 0; i < m_values->size(); i++) 
              {
      
                  if (i > 0)
                      ofs << ",";
      
                  if(i > 0 && m_formatOutput)
                      ofs << std::endl;
      
                  OutputIndents(ofs);         
      
                  m_values->at(i)->OutputNodeToStream(ofs);
              }
              
              ChangeIndent(ofs, -m_indentInc);
              OutputIndents(ofs);
              ofs << "]";     
          }
      
      };
      
      

      使用示例

      创建 json 树:

      JsonNode* Circuit::GetMyJson()
      {
          JsonNode* node = new JsonNode(JsonNodeType::Object);
      
          JsonNode* gates = new JsonNode(JsonNodeType::Array);
      
          for (auto& [k, v] : m_gates)
              gates->Add(v.GetMyJson());
      
          node->Add("gates", gates);
      
          return node;
      }
      
      

      输出树:

      std::unique_ptr<JsonNode> node (simulation->GetMyJson());
      std::ofstream output("output.json", std::ios::out);
      node->OutputToStream(output);
      

      【讨论】:

      • 非常有趣!您是否有一些基准测试结果表明它的运行速度有多快?
      猜你喜欢
      • 2015-03-19
      • 2020-10-23
      • 1970-01-01
      • 2018-04-09
      • 1970-01-01
      • 1970-01-01
      • 2011-03-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多