Boost Variant: 如何建模JSON?

7

我正在尝试使用Boost Spirit解析JSON字符串,将JSON对象存储到递归数据结构中:

Value <== [null, bool, long, double, std::string, Array, Object];
Array <== [Value, Value, Value, ...];
Object <== ["name1": Value, "name2": Value, ...];

以下是我的代码:

#include <map>
#include <vector>
#include <string>
#include <boost/variant.hpp>
#include <boost/shared_array.hpp>
#include <boost/shared_ptr.hpp>

struct JsonNull {};
struct JsonValue;

typedef std::map<std::string, JsonValue *> JsonObject;
typedef std::vector<JsonValue *> JsonArray;

struct JsonValue : boost::variant<JsonNull, bool, long, double, std::string, JsonArray, JsonObject>
{
};

JsonValue aval = JsonObject();

编译时我遇到了错误:

Error C2440: 'initializing' : cannot convert from 'std::map<_Kty,_Ty>' to 'JsonValue'

此外,如何安全地将JsonValue转换为JsonObject?当我尝试这样做时:
boost::get<JsonObject>(aval) = JsonObject();

这会导致运行时异常/致命故障。

非常感谢任何帮助。

编辑:

根据 @Nicol 的建议,我编写了以下代码:

struct JsonNull {};
struct JsonValue;

typedef std::map<std::string, JsonValue *> JsonObject;
typedef std::vector<JsonValue *> JsonArray;
typedef boost::variant<
    JsonNull, bool, long, double, std::string,
    JsonObject, JsonArray,
    boost::recursive_wrapper<JsonValue>
> JsonDataValue;

struct JsonValue
{
    JsonDataValue data;
};

我可以像这样轻松地处理JsonObject和JsonArray:

JsonValue *pJsonVal = new JsonValue();

boost::get<JsonObject>(pCurrVal->data).insert(
    std::pair<std::string, JsonValue *>("key", pJsonVal)
);

boost::get<JsonArray>(pCurrVal->data).push_back(pJsonVal);

我发这篇文章是为了让大家都受益。

1个回答

6

您需要使用递归封装器(不应该从boost::variant继承):

struct JsonValue;

typedef boost::variant</*types*/, boost::recursive_wrapper<JsonValue> > JsonDataValue;

struct JsonValue
{
    JsonDataValue value;
};

为了让Boost.Spirit接受JsonValue,您需要编写其中一个Fusion适配器来将原始变量类型转换为结构体。

此外,如何安全地将JsonValue强制转换为JsonObject? 当我尝试执行以下操作时:

这不是变量的工作方式。如果您想将它们设置为值,请像设置任何其他值一样进行设置:

JsonValue val;
val.value = JsonValue();

谢谢Nicol的及时回答!正如您所看到的,我有JsonArray和JsonObject类型,请问在按照您的路径进行操作时,我该如何利用它们?能否请您详细讨论一下?谢谢! - Viet
@Protege:就像 Boost 的大多数部分一样,Variant 有非常好的文档。你应该阅读它。这将节省我们双方很多时间。 - Nicol Bolas
我多次阅读了Variant,但无法理解。我试图将std::map和std::vector插入到JsonValue中。无论如何,还是谢谢。 - Viet
放心,我找到答案了!感谢你的提示! - Viet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接