@@ -11,224 +11,240 @@ class QJsonUtils
1111{
1212public:
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
8554private:
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