Skip to content

Commit 8b417dc

Browse files
committed
Correct JSON processing
1 parent 1be02b8 commit 8b417dc

File tree

4 files changed

+190
-171
lines changed

4 files changed

+190
-171
lines changed

include/utils/jsonschema/QJsonUtils.h

Lines changed: 162 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -11,224 +11,240 @@ class QJsonUtils
1111
{
1212
public:
1313

14-
static bool modify(QJsonValue& value, QStringList path, const QJsonValue& newValue = QJsonValue::Null, QString propertyName = "")
14+
static void modify(QJsonValue& value, QStringList path, const QJsonValue& newValue = QJsonValue::Null, const QString& propertyName = "")
1515
{
16-
QJsonObject result;
17-
bool propertyUpdated {false};
16+
QJsonValue result;
17+
1818
if (!path.isEmpty())
1919
{
20-
2120
if (path.first() == "[root]")
2221
{
2322
path.removeFirst();
2423
}
25-
// Clean up leading periods in path elements
26-
for (auto& current : path) {
27-
if (current.startsWith("."))
24+
25+
for (QString& pathItem : path)
26+
{
27+
if (pathItem.startsWith("."))
2828
{
29-
current.remove(0, 1);
29+
pathItem = pathItem.mid(1);
3030
}
3131
}
3232

33-
if (! (value.toObject().isEmpty() && value.toArray().isEmpty()) )
33+
if (!value.toObject().isEmpty() || !value.toArray().isEmpty())
3434
{
35-
modifyValue(value, result, path, newValue, propertyName, propertyUpdated);
35+
modifyValue(value, result, path, newValue);
3636
}
3737
else if (newValue != QJsonValue::Null && !propertyName.isEmpty())
3838
{
39-
result[propertyName] = newValue;
40-
propertyUpdated = true;
39+
QJsonObject temp;
40+
temp[propertyName] = newValue;
41+
result = temp;
4142
}
4243
}
44+
4345
value = result;
44-
return propertyUpdated;
4546
}
4647

47-
static QJsonValue create(QJsonValue schema, bool ignoreRequired = false)
48-
{
49-
return createValue(schema, ignoreRequired);
50-
}
5148

52-
static QString getDefaultValue(const QJsonValue & value)
49+
static QJsonValue create(const QJsonValue& schema, bool ignoreRequired = false)
5350
{
54-
QString ret;
55-
switch (value.type())
56-
{
57-
case QJsonValue::Array:
58-
{
59-
for (const QJsonValueRef v : value.toArray())
60-
{
61-
ret = getDefaultValue(v);
62-
if (!ret.isEmpty())
63-
break;
64-
}
65-
break;
66-
}
67-
case QJsonValue::Object:
68-
{
69-
ret = getDefaultValue(value.toObject().value("default"));
70-
}
71-
break;
72-
case QJsonValue::Bool:
73-
return value.toBool() ? "True" : "False";
74-
case QJsonValue::Double:
75-
return QString::number(value.toDouble());
76-
case QJsonValue::String:
77-
return value.toString();
78-
case QJsonValue::Null:
79-
case QJsonValue::Undefined:
80-
break;
81-
}
82-
return ret;
51+
return createValue(schema, ignoreRequired);
8352
}
8453

8554
private:
8655

87-
static QJsonValue createValue(QJsonValue schema, bool ignoreRequired)
56+
static QJsonValue createValue(const QJsonValue& schema, bool ignoreRequired)
8857
{
89-
QJsonObject result;
90-
QJsonObject obj = schema.toObject();
58+
QJsonObject composedObject;
59+
QJsonObject const obj = schema.toObject();
9160

92-
if (obj.find("type") != obj.end() && obj.find("type").value().isString())
61+
// Handle top-level schema with "type"
62+
auto typeIt = obj.constFind("type");
63+
if (typeIt != obj.constEnd() && typeIt->isString())
9364
{
94-
QJsonValue ret = QJsonValue::Null;
65+
QString const typeStr = typeIt->toString();
66+
bool const isRequired = obj.value("required").toBool() || ignoreRequired;
67+
QJsonValue finalValue = QJsonValue::Null;
9568

96-
if (obj.find("type").value().toString() == "object" && ( obj.find("required").value().toBool() || ignoreRequired ) )
97-
ret = createValue(obj["properties"], ignoreRequired);
98-
else if (obj.find("type").value().toString() == "array" && ( obj.find("required").value().toBool() || ignoreRequired ) )
69+
if (typeStr == "object" && isRequired)
9970
{
100-
QJsonArray array;
101-
102-
if (obj.find("default") != obj.end())
103-
ret = obj.find("default").value();
71+
finalValue = createValue(obj.value("properties"), ignoreRequired);
72+
}
73+
else if (typeStr == "array" && isRequired)
74+
{
75+
if (obj.contains("default"))
76+
{
77+
finalValue = obj.value("default");
78+
}
10479
else
10580
{
106-
ret = createValue(obj["items"], ignoreRequired);
81+
QJsonArray array;
82+
QJsonValue const itemValue = createValue(obj.value("items"), ignoreRequired);
83+
84+
if (!itemValue.toObject().isEmpty())
85+
{
86+
array.append(itemValue);
87+
}
10788

108-
if (!ret.toObject().isEmpty())
109-
array.append(ret);
110-
ret = array;
89+
finalValue = array;
90+
}
91+
}
92+
else if (isRequired)
93+
{
94+
if (obj.contains("default"))
95+
{
96+
finalValue = obj.value("default");
11197
}
11298
}
113-
else if ( obj.find("required").value().toBool() || ignoreRequired )
114-
if (obj.find("default") != obj.end())
115-
ret = obj.find("default").value();
11699

117-
return ret;
100+
return finalValue;
118101
}
119-
else
102+
103+
// If no top-level type, iterate through members
104+
for (QJsonObject::const_iterator it = obj.constBegin(); it != obj.constEnd(); ++it)
120105
{
121-
for (QJsonObject::const_iterator i = obj.begin(); i != obj.end(); ++i)
122-
{
123-
QString attribute = i.key();
124-
const QJsonValue & attributeValue = *i;
125-
QJsonValue subValue = obj[attribute];
106+
QString const attribute = it.key();
107+
const QJsonValue& attributeValue = it.value();
108+
QJsonObject const attrObj = attributeValue.toObject();
126109

127-
if (attributeValue.toObject().find("type") != attributeValue.toObject().end())
110+
auto attrTypeIt = attrObj.constFind("type");
111+
QString const attrType = (attrTypeIt != attrObj.constEnd()) ? attrTypeIt->toString() : QString();
112+
bool const attrIsRequired = attrObj.value("required").toBool() || ignoreRequired;
113+
114+
if (!attrType.isEmpty())
115+
{
116+
if (attrType == "object" && attrIsRequired)
128117
{
129-
if (attributeValue.toObject().find("type").value().toString() == "object" && ( attributeValue.toObject().find("required").value().toBool() || ignoreRequired ) )
118+
if (obj.contains("properties"))
130119
{
131-
if (obj.contains("properties"))
132-
result[attribute] = createValue(obj["properties"], ignoreRequired);
133-
else
134-
result[attribute] = createValue(subValue, ignoreRequired);
120+
composedObject.insert(attribute, createValue(obj.value("properties"), ignoreRequired));
135121
}
136-
else if (attributeValue.toObject().find("type").value().toString() == "array" && ( attributeValue.toObject().find("required").value().toBool() || ignoreRequired ) )
122+
else
123+
{
124+
composedObject.insert(attribute, createValue(attributeValue, ignoreRequired));
125+
}
126+
}
127+
else if (attrType == "array" && attrIsRequired)
128+
{
129+
if (attrObj.contains("default"))
130+
{
131+
composedObject.insert(attribute, attrObj.value("default"));
132+
}
133+
else
137134
{
138135
QJsonArray array;
136+
QJsonValue const itemsValue = createValue(attrObj.value("items"), ignoreRequired);
139137

140-
if (attributeValue.toObject().find("default") != attributeValue.toObject().end())
141-
result[attribute] = attributeValue.toObject().find("default").value();
142-
else
138+
if (!itemsValue.toObject().isEmpty())
143139
{
144-
QJsonValue retEmpty;
145-
retEmpty = createValue(attributeValue.toObject()["items"], ignoreRequired);
146-
147-
if (!retEmpty.toObject().isEmpty())
148-
array.append(retEmpty);
149-
result[attribute] = array;
140+
array.append(itemsValue);
150141
}
142+
143+
composedObject.insert(attribute, array);
144+
}
145+
}
146+
else if (attrIsRequired)
147+
{
148+
if (attrObj.contains("default"))
149+
{
150+
composedObject.insert(attribute, attrObj.value("default"));
151151
}
152-
else if ( attributeValue.toObject().find("required").value().toBool() || ignoreRequired )
152+
else
153153
{
154-
if (attributeValue.toObject().find("default") != attributeValue.toObject().end())
155-
result[attribute] = attributeValue.toObject().find("default").value();
156-
else
157-
result[attribute] = QJsonValue::Null;
154+
composedObject.insert(attribute, QJsonValue::Null);
158155
}
159156
}
160157
}
161158
}
162159

163-
return result;
160+
return composedObject;
164161
}
165162

166-
static void modifyValue(QJsonValue source, QJsonValue target, QStringList path, const QJsonValue& newValue, QString& property, bool& propertyUpdated)
163+
static void modifyValue(const QJsonValue& source, QJsonValue& target, QStringList path, const QJsonValue& newValue)
167164
{
168-
// Ensure the path is not empty
169-
if (path.isEmpty()) {
170-
propertyUpdated = false;
171-
return;
172-
}
165+
// Handle case where the source is an object
166+
if (source.isObject())
167+
{
168+
QJsonObject sourceObj = source.toObject();
169+
QJsonObject targetObj = target.isObject() ? target.toObject() : QJsonObject();
173170

174-
QString current = path.takeFirst();
171+
bool foundKey = false;
175172

176-
// Handle object case
177-
if (source.isObject()) {
178-
QJsonObject obj = source.toObject();
173+
for (auto it = sourceObj.begin(); it != sourceObj.end(); ++it)
174+
{
175+
const QString& key = it.key();
176+
const QJsonValue& subValue = it.value();
179177

180-
if (!obj.contains(current)) {
181-
// Create missing key if necessary
182-
if (path.isEmpty()) {
183-
obj[current] = newValue;
184-
propertyUpdated = true;
185-
} else {
186-
QJsonValue emptyObj((QJsonObject())); // create an empty object
187-
modifyValue(emptyObj, obj[current], path, newValue, property, propertyUpdated);
178+
if (!path.isEmpty() && key == path.first())
179+
{
180+
path.takeFirst(); //Remove first item of path
181+
QJsonValue subTarget;
182+
modifyValue(subValue, subTarget, path, newValue);
183+
targetObj.insert(key, subTarget);
184+
foundKey = true;
185+
}
186+
else
187+
{
188+
targetObj.insert(key, subValue);
188189
}
189-
} else {
190-
QJsonValue existingValue = obj[current];
191-
modifyValue(existingValue, obj[current], path, newValue, property, propertyUpdated);
192190
}
193191

194-
target = obj; // Reassign modified object to target
192+
// If key wasn't found and path is now size 1, create the key and insert newValue
193+
if (!path.isEmpty() && path.size() == 1 && !foundKey)
194+
{
195+
targetObj.insert(path.first(), newValue);
196+
path.clear();
197+
}
198+
199+
target = targetObj;
195200
}
196-
// Handle array case
197-
else if (source.isArray()) {
198-
QJsonArray arr = source.toArray();
199-
bool isIndex;
200-
int index = current.toInt(&isIndex);
201-
202-
if (isIndex && index >= 0 && index < arr.size()) {
203-
// If the path is empty, modify the element at the index
204-
if (path.isEmpty()) {
205-
arr[index] = newValue;
206-
propertyUpdated = true;
207-
} else {
208-
QJsonValue arrayElement = arr[index];
209-
modifyValue(arrayElement, arr[index], path, newValue, property, propertyUpdated);
201+
202+
// Handle case where the source is an array
203+
else if (source.isArray())
204+
{
205+
QJsonArray sourceArray = source.toArray();
206+
QJsonArray targetArray = target.isArray() ? target.toArray() : QJsonArray();
207+
208+
int index = -1;
209+
if (!path.isEmpty() && path.first().startsWith("[") && path.first().endsWith("]"))
210+
{
211+
index = path.first().mid(1, path.first().size() - 2).toInt();
212+
path.removeFirst();
213+
}
214+
215+
for (int i = 0; i < sourceArray.size(); ++i)
216+
{
217+
QJsonValue const element = sourceArray[i];
218+
QJsonValue modifiedElement = element;
219+
220+
if (i == index)
221+
{
222+
modifyValue(element, modifiedElement, path, newValue);
210223
}
224+
225+
targetArray.append(modifiedElement);
211226
}
212-
else {
213-
// Expand array if index is out of bounds
214-
while (arr.size() <= index)
215-
arr.append(QJsonValue());
216227

217-
QJsonValue arrayElement = arr[index];
218-
modifyValue(arrayElement, arr[index], path, newValue, property, propertyUpdated);
228+
// If we're appending a new value outside bounds (e.g., into an empty array)
229+
if (sourceArray.isEmpty() && index == 0 && newValue != QJsonValue::Null)
230+
{
231+
targetArray.append(newValue);
219232
}
220233

221-
target = arr; // Reassign modified array to target
234+
target = targetArray;
222235
}
223-
// Handle unsupported cases (e.g., primitive values)
224-
else {
225-
if (path.isEmpty()) {
226-
QJsonObject obj;
227-
obj[current] = newValue;
228-
target = obj;
229-
propertyUpdated = true;
236+
237+
// Handle primitive values
238+
else
239+
{
240+
if (path.isEmpty() && newValue != QJsonValue::Null)
241+
{
242+
target = newValue;
243+
}
244+
else
245+
{
246+
target = source;
230247
}
231248
}
232249
}
233-
234250
};

0 commit comments

Comments
 (0)