Я решил похожую проблему: искать только различия (удаленные, созданные и измененные значения) и регистрировать их. Мой рекурсивный алгоритм работает для всех структур JSON строк. В основном он использует QJsonObject.keys () для объектов и QJsonArray.size () для массивов для итерации и проверяет разницу для каждого значения (которое само по себе является JsonObject, JsonArray или JsonValue).
JsonComparer.h
#pragma once
#include <qjsondocument.h>
#include <qjsonarray.h>
#include <qjsonobject.h>
#include <qstringlist.h>
class JsonComparer {
public:
QStringList compare(const QString json1, const QString json2);
private:
void compareObjects(QStringList keyStack, const QJsonObject obj1, const QJsonObject obj2);
void compareArrays(QStringList keyStack, const QJsonArray arr1, const QJsonArray arr2);
void compareValues(QStringList keyStack, const QJsonValue val1, const QJsonValue val2);
private:
QStringList m_differences;
};
JsonComparer. cpp
#include "JsonComparer.h"
#include <qvariant.h>
#include <qdebug.h>
QStringList JsonComparer::compare(const QString json1, const QString json2) {
m_differences.clear();
QJsonObject obj1 = QJsonDocument::fromJson(json1.toUtf8()).object();
QJsonObject obj2 = QJsonDocument::fromJson(json2.toUtf8()).object();
compareObjects(*(new QStringList()), obj1, obj2);
return m_differences;
}
void JsonComparer::compareObjects(QStringList keyStack, const QJsonObject obj1, const QJsonObject obj2) {
QStringList keysObj1 = obj1.keys();
QStringList keysObj2 = obj2.keys();
for (QString key : keysObj1) {
if (!keysObj2.contains(key)) {
m_differences << keyStack.join(", ") + ", " + key + ": deleted";
}
}
for (QString key : keysObj2) {
if (!keysObj1.contains(key)) {
m_differences << keyStack.join(", ") + ", " + key + ": created";
}
}
for (QString key : keysObj1) {
if (keysObj2.contains(key)) {
keyStack.append(key);
if (obj1[key].isArray()) {
compareArrays(keyStack, obj1[key].toArray(), obj2[key].toArray());
}
else if (obj1[key].isObject()) {
compareObjects(keyStack, obj1[key].toObject(), obj2[key].toObject());
}
else {
if (obj1[key] != obj2[key]) {
compareValues(keyStack, obj1[key], obj2[key]);
}
}
keyStack.removeLast();
}
}
}
void JsonComparer::compareArrays(QStringList keyStack, const QJsonArray arr1, const QJsonArray arr2) {
quint32 minSize = qMin<int>(arr1.size(), arr2.size());
for (quint32 i = 0; i < minSize; i++) {
keyStack.append("[" + QString::number(i) + "]");
if (arr1[i].isArray()) {
compareArrays(keyStack, arr1[i].toArray(), arr2[i].toArray());
}
else if (arr1[1].isObject()) {
compareObjects(keyStack, arr1[i].toObject(), arr2[i].toObject());
}
keyStack.removeLast();
}
if (arr1.size() > arr2.size()) {
for (quint32 i = minSize; i < arr1.size(); i++) {
m_differences << keyStack.join(", ") + ", " + "[" + QString::number(i) + "]" + ": deleted";
}
}
if (arr1.size() < arr2.size()) {
for (quint32 i = minSize; i < arr2.size(); i++) {
m_differences << keyStack.join(", ") + ", " + "[" + QString::number(i) + "]" + ": created";
}
}
}
void JsonComparer::compareValues(QStringList keyStack, const QJsonValue val1, const QJsonValue val2) {
if (val1.isString()) {
m_differences << keyStack.join(", ") + ": changed from " + val1.toString() + " to " + val2.toString();
}
else if (val1.isDouble()) {
m_differences << keyStack.join(", ") + ": changed from " + QString::number(val1.toDouble()) + " to " + QString::number(val2.toDouble());
}
}
В качестве примера вывода (мне пришлось вынуть некоторые детали):
> Grills, [0]: deleted
> Grills, [1]: deleted
> LongName: changed from ... to ...
> ProductCode: changed from 321 to 474
> RequestId: changed from 34E169A7-1E4E-7695-BA5C-5C277607BA5C to 5B6088D7-AF85-EECB-4D83-61FC179BA18F
> ShortName: changed from ... to ...
> attributes, OrderId: changed from 640 to 149
> attributes, OrderKey: changed from 0006:845097930 to 0001:205422059
> attributes, PodType: changed from 8 to 0
> attributes, SaleDate: changed from 2019-01-20T13:31:04.1795784Z to 2019-01-20T13:45:46.5153031Z
> attributes, SaleType: changed from 0 to 1