我编写了以下代码来表示C ++中的JSON数据。我得到一些模糊的评论,这可能不是最佳选择,如果我们决定将JSON数据直接解析到此结构中,则可能会遇到麻烦。我没有得到简短的注释,因此将在此处重现我的代码,并希望听到有什么问题。

#define BOOST_VARIANT_NO_FULL_RECURSIVE_VARIANT_SUPPORT
#include <boost/variant.hpp>
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <iomanip>
#define STR_(x) std::string(x)

struct JSONNullType {};

typedef boost::make_recursive_variant<
       std::string,
       long,
       double,
       std::map<std::string, boost::recursive_variant_>,
        std::vector<boost::recursive_variant_>,
       bool,
       JSONNullType>::type JSONValue;

typedef std::vector<JSONValue> JSONArray;
typedef std::map<std::string, JSONValue> JSONObject;


struct JSONPrintVisitor : public boost::static_visitor<void>
{
  void operator()(const JSONArray& array) const
  {
    std::cout << '[';

    if (!array.empty()) {
      boost::apply_visitor(*this, array[0]);

      std::for_each(array.begin() + 1, array.end(),
                  [this](const JSONValue& v) {
                    std::cout << ',';
                    boost::apply_visitor(*this, v);
                  });
    }

    std::cout << ']' << std::endl;
  }

  void operator()(const JSONObject& object) const
  {
    std::cout << '{';

    if (!object.empty()) {
      const auto& kv_pair = *(object.begin());
      std::cout << '"' << kv_pair.first << '"';
      std::cout << ':';
      boost::apply_visitor(*this, kv_pair.second);

      auto it = object.begin();
      std::for_each(++it, object.end(),
                  [this](const JSONObject::value_type& v) {
                    std::cout << ',';
                    std::cout << '"' << v.first << '"';
                    std::cout << ':';
                    boost::apply_visitor(*this, v.second);
                  });
    }

    std::cout << '}';
  }

  void operator() (const std::string& str) const
  {
    std::cout << '"' << str << '"';
  }

  void operator() (const JSONNullType&) const
  {
    std::cout << "null";
  }

  template <typename T>
  void operator()(const T& value) const
  {
    std::cout << std::boolalpha << value;
  }
};

int main()
{
  JSONValue vt = JSONArray();
  JSONArray *array = boost::get<JSONArray>(&vt);

  JSONValue person1 = JSONObject();
  JSONValue person2 = JSONObject();
  JSONValue person3 = JSONObject();
  JSONValue person4 = JSONObject();

  JSONObject *pp1 = boost::get<JSONObject>(&person1),
             *pp2 = boost::get<JSONObject>(&person2),
             *pp3 = boost::get<JSONObject>(&person3);

  (*pp1)["name"] = STR_("Baba O'Riley");
  (*pp1)["profession"] = STR_("farmer");
  (*pp1)["age"] = 21L;
  (*pp1)["favourite"] = STR_("Baba ganoush");
  (*pp1)["height"] = 176.1;

  (*pp2)["name"] = STR_("Stuart Little");
  (*pp2)["profession"] = STR_("good-boy mouse");
  (*pp2)["age"] = 4L;
  (*pp2)["favourite"] = STR_("Gouda");
  (*pp2)["height"] = 11.0;

  (*pp3)["name"] = STR_("Howard Roark");
  (*pp3)["profession"] = STR_("architect");
  (*pp3)["age"] = 32L;
  (*pp3)["favourite"] = STR_("Eggs benedict");
  (*pp3)["height"] = 185.0;

  array->push_back(person1);
  array->push_back(person2);
  array->push_back(person3);

  boost::apply_visitor(JSONPrintVisitor(), vt);
}

最佳答案

我的Boost Spirit解析器/生成器使用了非常相似的结构。

运作良好。

我会说


注意JSON,其将含义附加到对象中元素的顺序上;您的代表不保留该信息
注意对象中可能两次包含相同密钥的JSON(不会发生SHOULD,但某些实现可能会发生)
JSON没有“ long”或“ double”。它只有“数字”。确保您的long具有64位(uint64_t),并准备任意混合long / double(除非由于某种模式信息(例如Edm),您不知道该期待什么)
寻找导致模棱两可的构造函数的隐式转换。可能值得拥有一个强大的用户定义类型,而不是boollongdouble。考虑如果发生的话会发生什么/应该发生什么

JSON::Value v(42u);
v = 7.5f;



对于某些应用程序,一个明显的优化是引用缓存的密钥,而不是为其复制字符串。 Boost Flyweight可能很方便(尽管在我的测试中,除非禁用对象跟踪,否则在解析过程中不会获得性能;您必须非常确定输入的合理性,以允许“不断增长的”缓存,因为这可能导致DoS)。

10-07 19:37
查看更多