我正在解析JSON
结构,其结构如下
{
"item1" : "value1"
"item2" : "value2"
// ...
"itemn" : {
"outernestedItem1" : {
"innerNestedItem1" : "valuen1"
"innerNestedItem2" : "valuen2"
}
// ....
"outernestedItemn" : {
"innerNestedItem1" : "valuen1"
"innerNestedItem2" : "valuen2"
}
}
}
外部嵌套项的数量不固定,所以我使用来自rapidjson的迭代器进行迭代,内部嵌套对象变量是固定的,所以我可以使用[]来访问它们。
const rapidjson::Value& itemn = document["itemn"];
for (rapidjson::Value::ConstMemberIterator itr = itemn.MemberBegin();
itr != itemn.MemberEnd(); ++itr)
{
rapidjson::StringBuffer sb;
rapidjson::Writer<rapidjson::StringBuffer> writer( sb );
itr->value.Accept(writer);
std::cout << sb["innerNestedItem1"].GetString();
std::cout << sb["innerNestedItem2"].GetString();
}
但sb(字符串缓冲区)不允许[],任何想法我该怎么做?
EDIT1: 我以非常低效的方式做到了,但只是共享解决方案,所以它可能有助于某人提出有效的解决方案。
const rapidjson::Value& itemn = document["itemn"];
for (rapidjson::Value::ConstMemberIterator itr = itemn.MemberBegin();
itr != itemn.MemberEnd(); ++itr)
{
rapidjson::StringBuffer sb;
rapidjson::Writer<rapidjson::StringBuffer> writer( sb );
itr->value.Accept(writer);
//changed from here onwards
rapidjson::Document for_outer_nested_item;
std::string temp = sb.GetString();
char buffer2[100000];
strcpy_s(buffer2, temp.c_str());
for_outer_nested_item.ParseInsitu(buffer2);
std::cout << executive_command["innerNestedItem1"].GetString() << std::endl;
std::cout << executive_command["innerNestedItem2"].GetString() << std::endl;
}
答案 0 :(得分:6)
首先,让我在此link
为MiloYip提供信贷第二 - 这就是我为我的项目所做的事情:
rapidjson::Document document;
// document holds a json document retrieved from a http GET request
// I did not include all of that in this example. I am only showing
// the part of iterating through a nested object and retrieving members.
std::vector<std::string> symbols;
// holds the values I retrieve from the json document
if (document.Parse<0>( symbol.c_str() ).HasParseError() )
Log() << "ERROR: encountered a JSON parsing error" << std::endl;
else {
// Get the nested object that contains the elements I want.
// In my case, the nested object in my json document was results
// and the values I was after were identified as "t"
rapidjson::Value& results = document["results"];
assert(results.IsArray());
for (rapidjson::SizeType i = 0; i < results.Size(); i++) {
// Store the value of the element in a vector.
symbols.emplace_back(results[i]["t"].GetString());
}
我认为这是一种非常干净/高效的方法。
答案 1 :(得分:4)
这是我最近的工作:
void enter(const Value &obj, size_t indent = 0) { //print JSON tree
if (obj.IsObject()) { //check if object
for (Value::ConstMemberIterator itr = obj.MemberBegin(); itr != obj.MemberEnd(); ++itr) { //iterate through object
const Value& objName = obj[itr->name.GetString()]; //make object value
for (size_t i = 0; i != indent; ++i) //indent
cout << " ";
cout << itr->name.GetString() << ": "; //key name
if (itr->value.IsNumber()) //if integer
std::cout << itr->value.GetInt() ;
else if (itr->value.IsString()) //if string
std::cout << itr->value.GetString();
else if (itr->value.IsBool()) //if bool
std::cout << itr->value.GetBool();
else if (itr->value.IsArray()){ //if array
for (SizeType i = 0; i < itr->value.Size(); i++) {
if (itr->value[i].IsNumber()) //if array value integer
std::cout << itr->value[i].GetInt() ;
else if (itr->value[i].IsString()) //if array value string
std::cout << itr->value[i].GetString() ;
else if (itr->value[i].IsBool()) //if array value bool
std::cout << itr->value[i].GetBool() ;
else if (itr->value[i].IsObject()){ //if array value object
cout << "\n ";
const Value& m = itr->value[i];
for (auto& v : m.GetObject()) { //iterate through array object
if (m[v.name.GetString()].IsString()) //if array object value is string
cout << v.name.GetString() << ": " << m[v.name.GetString()].GetString();
else //if array object value is integer
cout << v.name.GetString() << ": " << m[v.name.GetString()].GetInt();
cout << "\t"; //indent
}
}
cout << "\t"; //indent
}
}
cout << endl;
enter(objName, indent + 1); //if couldn't find in object, enter object and repeat process recursively
}
}
}
这可以处理任何类型的JSON树。您所要做的就是传递一个Value:
Value v = document.GetObject();
Value& m= v;
enter(m);
你已经完成了!
答案 2 :(得分:3)
ln -s /usr/local/bin/nodejs /usr/bin/node
从文档void parseRecursive(std::string scope
, rapidjson::Value::ConstMemberIterator object
, std::unordered_map<std::string, std::string>& values)
{
if (scope.empty())
{
scope = object->name.GetString();
}
else
{
scope = scope + "::" + object->name.GetString();
}
auto inElement = scope + "::";
if (object->value.IsObject())
{
for (auto it = object->value.MemberBegin(); it != object->value.MemberEnd(); ++it)
{
parseRecursive(scope, it, values);
}
}
else if (object->value.IsDouble())
{
values.emplace(inElement, std::to_string(object->value.GetDouble()));
}
else if (object->value.IsInt())
{
values.emplace(inElement, std::to_string(object->value.GetInt()));
}
else
{
LOGW("Unsuported: " << inElement << object->name.GetString());
}
}
rapidjson::Document document;
答案 3 :(得分:1)
a.raya203 的帖子https://stackoverflow.com/a/43120359/6155053没有为我开箱即用(不处理当前rapidjson版本实现的所有类型)例如,输出包含双打的gltfs等时会遇到错误。但是它让我在正确的轨道上理解rapidjson如何解析文档,所以我想我在这里留下我的(更新的)代码,也许它可以帮助别人...
#include <iostream>
#include <string>
class JsonNodePrinter final
{
public:
static void PrintNode(const rapidjson::Value &node, size_t indent = 0, unsigned int level = 0, const std::string& nodeName = "")
{
std::cout << GetIndentString(indent, level);
if (!nodeName.empty())
std::cout << nodeName << ": ";
if (node.IsBool())
std::cout << node.GetBool();
else if (node.IsInt())
std::cout << node.GetInt();
else if (node.IsUint())
std::cout << node.GetUint();
else if (node.IsInt64())
std::cout << node.GetInt64();
else if (node.IsUint64())
std::cout << node.GetUint64();
else if (node.IsDouble())
std::cout << node.GetDouble();
else if (node.IsString())
std::cout << node.GetString();
else if (node.IsArray())
{
if (!nodeName.empty()) std::cout << "\n" << GetIndentString(indent, level);
PrintArray(node, indent, level);
}
else if (node.IsObject())
{
if (!nodeName.empty()) std::cout << "\n" << GetIndentString(indent, level);
PrintObject(node, indent, level);
}
std::cout << "\n";
}
static void PrintObject(const rapidjson::Value &node, size_t indent = 0, unsigned int level = 0)
{
std::cout << "{\n";
for (rapidjson::Value::ConstMemberIterator childNode = node.MemberBegin(); childNode != node.MemberEnd(); ++childNode)
{
PrintNode(childNode->value, indent, level + 1, childNode->name.GetString());
}
std::cout << GetIndentString(indent, level) << "}";
}
static void PrintArray(const rapidjson::Value& node, size_t indent = 0, unsigned int level = 0)
{
std::cout << "[\n";
for (rapidjson::SizeType i = 0; i < node.Size(); ++i)
{
PrintNode(node[i], indent, level + 1);
}
std::cout << GetIndentString(indent, level) << "]";
}
static std::string GetIndentString(size_t indent = 0, unsigned int level = 0)
{
return std::move(std::string(level * indent, ' '));
}
};
像
一样使用它#include "3rdParty/rapidjson/document.h"
rapidjson::Document document;
{
document.Parse(FileHelper::ReadString(filePath)->c_str());
}
if (!document.HasParseError())
{
JsonNodePrinter::PrintNode(document, 4);
}
答案 4 :(得分:0)
我最近也在想这个,这就是我得到的:
#include "rapidjson\filereadstream.h"
#include "rapidjson\document.h"
#include "rapidjson\istreamwrapper.h"
#include <fstream>
#include <iostream>
using namespace rapidjson;
// Documentation : using file stream instead of C FILE pointers
// http://rapidjson.org/md_doc_stream.html#FileStreams
ifstream file_stream(filepath);
IStreamWrapper isw(file_stream);
Document doc;
doc.ParseStream(isw);
file_stream.close();
if(doc.HasMember(CONF_NODE)){
Value *config_node = &(doc[CONF_NODE]);
// Now I can use it like so:
std::cout << (*config_node)["My Other Json node"].GetString() << std::endl;
}
我多次使用此技巧以避免使用无法获取的长期访问请求,例如
doc["Node1"]["Node2"]["Node3"]...["NodeX"].GetType()而是依赖可用于虚拟“拆分”文档链的指针:
doc["Node1"]["Node2"]["Node3"]...["NodeX"].GetType() | | pointer1 | pointer2 (*pointer_on_Node_N)["Node N+1"] = doc["Node1"][...]["NodeN"]["Node N+1]
当我需要遍历我的文件(面向数组时)时,这特别方便。