构建嵌套 JSON
building a nested JSON
我需要读取/解析的一些数据文件具有 header 样式:
level0var = value0
level0var.level1field = value1
level0var.level1array[11].level2field = value2
...
换句话说,它们看起来像嵌套的 C-style 结构和数组,但其中 none 在 header 中声明:我需要在阅读时推断结构。
我的计划是使用著名的 nlohmann::json
库来存储它,因为它的灵活性允许我在解析过程中更改数据的结构,并将 header 保存在更具可读性的文件中形式。
我阅读了 lhs = rhs
中的作业,它们都是字符串。给定 json header;
来处理未知的、可变深度的结构,我想做一些类似
的事情
// std::string lhs = "level0var.level1field.level2field";
// std::string rhs = "value2";
auto current_level = header;
while ( lhs != "" ) {
auto between = lhs.substr ( 0, lhs.find_first_of ( "." ) );
lhs.erase ( 0, lhs.find_first_of ( "." ) + 1 );
if ( lhs == between ) break;
current_level [ between ] = json ( {} );
current_level = current_level [ between ];
}
current_level = rhs;
std::cout << std::setw(4) << header;
对于至少具有 1 个结构级别的每一行(暂时保留数组)。
奇怪的是,使用这个循环,最后一行returns唯一的事情是null
,而当我使用
header [ "level0var" ] [ "level1field" ] [ "level2field" ] = rhs;
std::cout << std::setw(4) << header;
它给出了预期的结果:
{
"level0var": {
"level1field": {
"level2field": "value2"
}
}
}
有没有办法迭代地构建这个层次结构(而不是作为一个整体提供)?一旦我知道如何做结构,我希望数组会很简单!
我在工作中制作的示例没有 运行 on coliru(我猜它没有 JSON 库)。
我设法用这段代码实现了我所理解的你想要的:
using namespace nlohmann;
void main()
{
json header;
std::string lhs = "level0var.level1field.level2field";
std::string rhs = "value2";
json * current_level = &header;
while (lhs != "") {
auto between = lhs.substr(0, lhs.find_first_of("."));
lhs.erase(0, lhs.find_first_of(".") + 1);
(*current_level)[between] = json({});
current_level = &((*current_level)[between]);
if (lhs == between) break;
}
*current_level = rhs;
std::cout << std::setw(4) << header;
}
一些注意事项:
虽然起初看起来很有用,但我还没有成功使用nlohmann::json_pointer
。
相反,我使用了一个“普通”的原始指针。需要一些指针语义才能引用现有的 json 结构。
我把退出循环的条件移到了循环的末尾(不然最内层就没了)
老实说,我不确定我的解决方案是最好的。在这种情况下处理原始指针是一件必须非常小心的事情。不过喜欢的可以试试
这对于 json_pointer
来说确实很简单,使用正确的 operator[]
overload and the json_pointer::get_unchecked()
函数已经为您完成了所有这些工作。
唯一的努力是将您的 .
分隔的密钥转换为它期望的 /
分隔的路径。
#include <nlohmann/json.hpp>
#include <algorithm>
#include <iostream>
#include <string>
using json = nlohmann::json;
std::string dots_to_path(std::string key)
{
std::replace(key.begin(), key.end(), '.', '/');
key.insert(0, 1, '/');
return key;
}
int main() {
json header;
std::string lhs = "level0var.level1field.level2field";
std::string rhs = "value1";
json::json_pointer key{dots_to_path(lhs)};
header[key] = rhs;
std::cout << std::setw(4) << header;
}
为了将来参考,链接代码已扩展为转换键,包括数组索引,如 level0var.level1field[1].level2field
-> level0var/level1field/1/level2field
。
在这个阶段,将原始字符串标记化并简单地为每个标记附加 json_pointer::operator/=
可能会更清晰,但由于它不在原始问题范围内,我将把它留作 reader.
我需要读取/解析的一些数据文件具有 header 样式:
level0var = value0
level0var.level1field = value1
level0var.level1array[11].level2field = value2
...
换句话说,它们看起来像嵌套的 C-style 结构和数组,但其中 none 在 header 中声明:我需要在阅读时推断结构。
我的计划是使用著名的 nlohmann::json
库来存储它,因为它的灵活性允许我在解析过程中更改数据的结构,并将 header 保存在更具可读性的文件中形式。
我阅读了 lhs = rhs
中的作业,它们都是字符串。给定 json header;
来处理未知的、可变深度的结构,我想做一些类似
// std::string lhs = "level0var.level1field.level2field";
// std::string rhs = "value2";
auto current_level = header;
while ( lhs != "" ) {
auto between = lhs.substr ( 0, lhs.find_first_of ( "." ) );
lhs.erase ( 0, lhs.find_first_of ( "." ) + 1 );
if ( lhs == between ) break;
current_level [ between ] = json ( {} );
current_level = current_level [ between ];
}
current_level = rhs;
std::cout << std::setw(4) << header;
对于至少具有 1 个结构级别的每一行(暂时保留数组)。
奇怪的是,使用这个循环,最后一行returns唯一的事情是null
,而当我使用
header [ "level0var" ] [ "level1field" ] [ "level2field" ] = rhs;
std::cout << std::setw(4) << header;
它给出了预期的结果:
{
"level0var": {
"level1field": {
"level2field": "value2"
}
}
}
有没有办法迭代地构建这个层次结构(而不是作为一个整体提供)?一旦我知道如何做结构,我希望数组会很简单!
我在工作中制作的示例没有 运行 on coliru(我猜它没有 JSON 库)。
我设法用这段代码实现了我所理解的你想要的:
using namespace nlohmann;
void main()
{
json header;
std::string lhs = "level0var.level1field.level2field";
std::string rhs = "value2";
json * current_level = &header;
while (lhs != "") {
auto between = lhs.substr(0, lhs.find_first_of("."));
lhs.erase(0, lhs.find_first_of(".") + 1);
(*current_level)[between] = json({});
current_level = &((*current_level)[between]);
if (lhs == between) break;
}
*current_level = rhs;
std::cout << std::setw(4) << header;
}
一些注意事项:
虽然起初看起来很有用,但我还没有成功使用
nlohmann::json_pointer
。
相反,我使用了一个“普通”的原始指针。需要一些指针语义才能引用现有的 json 结构。我把退出循环的条件移到了循环的末尾(不然最内层就没了)
老实说,我不确定我的解决方案是最好的。在这种情况下处理原始指针是一件必须非常小心的事情。不过喜欢的可以试试
这对于 json_pointer
来说确实很简单,使用正确的 operator[]
overload and the json_pointer::get_unchecked()
函数已经为您完成了所有这些工作。
唯一的努力是将您的 .
分隔的密钥转换为它期望的 /
分隔的路径。
#include <nlohmann/json.hpp>
#include <algorithm>
#include <iostream>
#include <string>
using json = nlohmann::json;
std::string dots_to_path(std::string key)
{
std::replace(key.begin(), key.end(), '.', '/');
key.insert(0, 1, '/');
return key;
}
int main() {
json header;
std::string lhs = "level0var.level1field.level2field";
std::string rhs = "value1";
json::json_pointer key{dots_to_path(lhs)};
header[key] = rhs;
std::cout << std::setw(4) << header;
}
为了将来参考,链接代码已扩展为转换键,包括数组索引,如 level0var.level1field[1].level2field
-> level0var/level1field/1/level2field
。
在这个阶段,将原始字符串标记化并简单地为每个标记附加 json_pointer::operator/=
可能会更清晰,但由于它不在原始问题范围内,我将把它留作 reader.