|
|
|
|
|
#include "nmDataJsonTools.h"
|
|
|
|
|
|
#include <QVariant>
|
|
|
|
|
|
#include <QVariantList> // 确保包含这些,以防万一
|
|
|
|
|
|
#include <QVariantMap>
|
|
|
|
|
|
#include <QDebug> // 用于调试输出
|
|
|
|
|
|
|
|
|
|
|
|
// RapidJSON 内部使用 char*,这里需要转换为 std::string
|
|
|
|
|
|
#include <string>
|
|
|
|
|
|
#include <QFile>
|
|
|
|
|
|
#include <QTextStream>
|
|
|
|
|
|
#include <QString>
|
|
|
|
|
|
|
|
|
|
|
|
#include "rapidjson/document.h"
|
|
|
|
|
|
#include "rapidjson/writer.h"
|
|
|
|
|
|
#include "rapidjson/prettywriter.h" // For pretty printing JSON
|
|
|
|
|
|
#include "rapidjson/stringbuffer.h"
|
|
|
|
|
|
|
|
|
|
|
|
using namespace rapidjson;
|
|
|
|
|
|
|
|
|
|
|
|
// 辅助函数:将 QVariant 递归转换为 rapidjson::Value
|
|
|
|
|
|
// 这是最重要的部分,因为它将处理 QVariant 中的嵌套结构
|
|
|
|
|
|
rapidjson::Value QVariantToRapidjsonValue(const QVariant& qv, rapidjson::Document::AllocatorType& allocator) {
|
|
|
|
|
|
if (qv.type() == QVariant::Int) {
|
|
|
|
|
|
return rapidjson::Value(qv.toInt());
|
|
|
|
|
|
} else if (qv.type() == QVariant::Double) {
|
|
|
|
|
|
return rapidjson::Value(qv.toDouble());
|
|
|
|
|
|
} else if (qv.type() == QVariant::String) {
|
|
|
|
|
|
return rapidjson::Value(qv.toString().toStdString().c_str(), allocator);
|
|
|
|
|
|
} else if (qv.type() == QVariant::Bool) {
|
|
|
|
|
|
return rapidjson::Value(qv.toBool());
|
|
|
|
|
|
} else if (qv.type() == QVariant::List) {
|
|
|
|
|
|
rapidjson::Value arr(rapidjson::kArrayType);
|
|
|
|
|
|
QVariantList list = qv.toList();
|
|
|
|
|
|
for (int i = 0; i < list.size(); ++i) {
|
|
|
|
|
|
arr.PushBack(QVariantToRapidjsonValue(list.at(i), allocator), allocator);
|
|
|
|
|
|
}
|
|
|
|
|
|
return arr;
|
|
|
|
|
|
} else if (qv.type() == QVariant::Map) {
|
|
|
|
|
|
rapidjson::Value obj(rapidjson::kObjectType);
|
|
|
|
|
|
QVariantMap map = qv.toMap();
|
|
|
|
|
|
// Qt4 QMapIterator
|
|
|
|
|
|
QMapIterator<QString, QVariant> i(map);
|
|
|
|
|
|
while (i.hasNext()) {
|
|
|
|
|
|
i.next();
|
|
|
|
|
|
rapidjson::Value key(i.key().toStdString().c_str(), allocator);
|
|
|
|
|
|
obj.AddMember(key, QVariantToRapidjsonValue(i.value(), allocator), allocator);
|
|
|
|
|
|
}
|
|
|
|
|
|
return obj;
|
|
|
|
|
|
} else if (qv.isNull() || qv.type() == QVariant::Invalid) {
|
|
|
|
|
|
return rapidjson::Value(rapidjson::kNullType);
|
|
|
|
|
|
}
|
|
|
|
|
|
// 默认情况或不支持的类型
|
|
|
|
|
|
qDebug() << "Warning: Unsupported QVariant type in QVariantToRapidjsonValue: " << qv.type();
|
|
|
|
|
|
return rapidjson::Value(rapidjson::kNullType);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 写入json
|
|
|
|
|
|
void nmDataJsonTools::jsonAdd(rapidjson::Document& document,
|
|
|
|
|
|
QVariant value, QVector<QVariant> path) {
|
|
|
|
|
|
Document::AllocatorType& allocator = document.GetAllocator();
|
|
|
|
|
|
Value* current = &document;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < path.size(); ++i) {
|
|
|
|
|
|
QVariant key_var = path.at(i);
|
|
|
|
|
|
|
|
|
|
|
|
// 如果是最后一层路径,设置值
|
|
|
|
|
|
if (i == path.size() - 1) {
|
|
|
|
|
|
if (key_var.type() == QVariant::String) {
|
|
|
|
|
|
std::string key_str = key_var.toString().toStdString();
|
|
|
|
|
|
const char* key_c_str = key_str.c_str();
|
|
|
|
|
|
|
|
|
|
|
|
// 确保当前节点是对象,以便添加成员
|
|
|
|
|
|
if (!current->IsObject()) {
|
|
|
|
|
|
current->SetObject(); // 这一步至关重要,如果 current 不是对象,就把它变成对象
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 将 QVariant 转换为 rapidjson::Value
|
|
|
|
|
|
rapidjson::Value val_to_add = QVariantToRapidjsonValue(value, allocator);
|
|
|
|
|
|
|
|
|
|
|
|
if (current->HasMember(key_c_str)) {
|
|
|
|
|
|
// 如果存在,替换值
|
|
|
|
|
|
(*current)[key_c_str].CopyFrom(val_to_add, allocator);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 如果不存在,添加新成员
|
|
|
|
|
|
current->AddMember(rapidjson::Value(key_c_str, allocator), val_to_add, allocator);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (key_var.type() == QVariant::Int) { // 最后一层路径是数组索引
|
|
|
|
|
|
int index = key_var.toInt();
|
|
|
|
|
|
if (!current->IsArray()) {
|
|
|
|
|
|
current->SetArray(); // 如果当前不是数组,就把它变成数组
|
|
|
|
|
|
}
|
|
|
|
|
|
// 确保数组大小足够
|
|
|
|
|
|
while (current->Size() <= index) {
|
|
|
|
|
|
current->PushBack(rapidjson::Value(rapidjson::kNullType), allocator); // 用 null 填充
|
|
|
|
|
|
}
|
|
|
|
|
|
// 将 QVariant 转换为 rapidjson::Value
|
|
|
|
|
|
rapidjson::Value val_to_add = QVariantToRapidjsonValue(value, allocator);
|
|
|
|
|
|
(*current)[index].CopyFrom(val_to_add, allocator);
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
qDebug() << "Error: Invalid path component type at end of path (expected string or int).";
|
|
|
|
|
|
}
|
|
|
|
|
|
return; // 最后一层路径处理完毕
|
|
|
|
|
|
}
|
|
|
|
|
|
// 处理中间路径节点
|
|
|
|
|
|
if (key_var.type() == QVariant::String) {
|
|
|
|
|
|
std::string key_str = key_var.toString().toStdString();
|
|
|
|
|
|
const char* key_c_str = key_str.c_str();
|
|
|
|
|
|
|
|
|
|
|
|
if (!current->IsObject()) {
|
|
|
|
|
|
current->SetObject(); // 确保当前节点是对象
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!current->HasMember(key_c_str)) {
|
|
|
|
|
|
// 如果中间路径节点不存在,则创建新的空对象
|
|
|
|
|
|
current->AddMember(rapidjson::Value(key_c_str, allocator), rapidjson::Value(rapidjson::kObjectType).Move(), allocator);
|
|
|
|
|
|
}
|
|
|
|
|
|
current = &((*current)[key_c_str]); // 移动到下一级
|
|
|
|
|
|
} else if (key_var.type() == QVariant::Int) {
|
|
|
|
|
|
int index = key_var.toInt();
|
|
|
|
|
|
if (!current->IsArray()) {
|
|
|
|
|
|
current->SetArray(); // 确保当前节点是数组
|
|
|
|
|
|
}
|
|
|
|
|
|
// 确保数组大小足够
|
|
|
|
|
|
while (current->Size() <= index) {
|
|
|
|
|
|
current->PushBack(rapidjson::Value(rapidjson::kNullType), allocator); // 用 null 填充
|
|
|
|
|
|
}
|
|
|
|
|
|
// 检查目标索引处是否是对象或数组。如果不是,就把它变成对象
|
|
|
|
|
|
if (!(*current)[index].IsObject() && !(*current)[index].IsArray()) {
|
|
|
|
|
|
(*current)[index].SetObject(); // 默认创建对象,如果需要数组则再处理
|
|
|
|
|
|
}
|
|
|
|
|
|
current = &((*current)[index]); // 移动到下一级
|
|
|
|
|
|
} else {
|
|
|
|
|
|
qDebug() << "Error: Invalid path component type in jsonAdd (expected string or int).";
|
|
|
|
|
|
return; // 路径不合法,提前退出
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 辅助函数:将 rapidjson::Value 递归转换为 QVariant
|
|
|
|
|
|
QVariant RapidjsonValueToQVariant(const rapidjson::Value& rv) {
|
|
|
|
|
|
if (rv.IsInt()) {
|
|
|
|
|
|
return QVariant(rv.GetInt());
|
|
|
|
|
|
} else if (rv.IsDouble()) {
|
|
|
|
|
|
return QVariant(rv.GetDouble());
|
|
|
|
|
|
} else if (rv.IsString()) {
|
|
|
|
|
|
return QVariant(rv.GetString());
|
|
|
|
|
|
} else if (rv.IsBool()) {
|
|
|
|
|
|
return QVariant(rv.GetBool());
|
|
|
|
|
|
} else if (rv.IsArray()) {
|
|
|
|
|
|
QVariantList list;
|
|
|
|
|
|
for (rapidjson::SizeType i = 0; i < rv.Size(); ++i) {
|
|
|
|
|
|
list.append(RapidjsonValueToQVariant(rv[i]));
|
|
|
|
|
|
}
|
|
|
|
|
|
return list;
|
|
|
|
|
|
} else if (rv.IsObject()) {
|
|
|
|
|
|
QVariantMap map;
|
|
|
|
|
|
for (rapidjson::Value::ConstMemberIterator itr = rv.MemberBegin(); itr != rv.MemberEnd(); ++itr) {
|
|
|
|
|
|
map.insert(itr->name.GetString(), RapidjsonValueToQVariant(itr->value));
|
|
|
|
|
|
}
|
|
|
|
|
|
return map;
|
|
|
|
|
|
} else if (rv.IsNull()) {
|
|
|
|
|
|
return QVariant(); // QVariant() 表示null
|
|
|
|
|
|
}
|
|
|
|
|
|
// 未知类型或默认处理
|
|
|
|
|
|
qDebug() << "Warning: Unsupported rapidjson::Value type in RapidjsonValueToQVariant: " << rv.GetType();
|
|
|
|
|
|
return QVariant();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 读json
|
|
|
|
|
|
void nmDataJsonTools::jsonRead(rapidjson::Document &document, QVariant &value, QVector<QVariant> path) {
|
|
|
|
|
|
const rapidjson::Value* current = &document;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < path.size(); ++i) {
|
|
|
|
|
|
QVariant key_var = path.at(i);
|
|
|
|
|
|
|
|
|
|
|
|
if (key_var.type() == QVariant::String) {
|
|
|
|
|
|
std::string key_str = key_var.toString().toStdString();
|
|
|
|
|
|
const char* key_c_str = key_str.c_str();
|
|
|
|
|
|
|
|
|
|
|
|
if (current->IsObject() && current->HasMember(key_c_str)) {
|
|
|
|
|
|
current = &((*current)[key_c_str]);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
value = QVariant(); // 路径不存在
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if (key_var.type() == QVariant::Int) {
|
|
|
|
|
|
int index = key_var.toInt();
|
|
|
|
|
|
if (current->IsArray() && index >= 0 && index < current->Size()) {
|
|
|
|
|
|
current = &((*current)[index]);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
value = QVariant(); // 索引无效
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
value = QVariant(); // 无效路径组件
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 到达路径的末端,将当前值赋给value
|
|
|
|
|
|
value = RapidjsonValueToQVariant(*current);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 将 RapidJSON Document 写入文件
|
|
|
|
|
|
bool nmDataJsonTools::WriteDomToFile(const rapidjson::Document& doc, const QString& filePath)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 将 RapidJSON Document 转换为字符串
|
|
|
|
|
|
rapidjson::StringBuffer buffer;
|
|
|
|
|
|
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer); // 使用 PrettyWriter 进行美化输出
|
|
|
|
|
|
doc.Accept(writer);
|
|
|
|
|
|
|
|
|
|
|
|
// 将字符串写入文件
|
|
|
|
|
|
QFile file(filePath);
|
|
|
|
|
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
|
|
|
|
|
qDebug() << "Error: Could not open file for writing:" << filePath;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QTextStream out(&file);
|
|
|
|
|
|
out << buffer.GetString();
|
|
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 从文件读取 JSON 并解析到 RapidJSON Document
|
|
|
|
|
|
bool nmDataJsonTools::ReadDomFromFile(const QString& filePath, rapidjson::Document& doc)
|
|
|
|
|
|
{
|
|
|
|
|
|
QFile file(filePath);
|
|
|
|
|
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
|
|
|
|
|
qDebug() << "Error: Could not open file for reading:" << filePath;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QTextStream in(&file);
|
|
|
|
|
|
QString jsonString = in.readAll();
|
|
|
|
|
|
file.close();
|
|
|
|
|
|
|
|
|
|
|
|
// 将 QString 转换为 std::string
|
|
|
|
|
|
QByteArray byteArray = jsonString.toUtf8();
|
|
|
|
|
|
std::string stdJsonString = byteArray.constData();
|
|
|
|
|
|
|
|
|
|
|
|
// 解析 JSON 字符串到 RapidJSON Document
|
|
|
|
|
|
doc.Parse(stdJsonString.c_str());
|
|
|
|
|
|
|
|
|
|
|
|
if (doc.HasParseError()) {
|
|
|
|
|
|
qDebug() << "Error parsing JSON from file:" << filePath << "Error:" << doc.GetParseError();
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|