1 | // Copyright (C) 2016 The Qt Company Ltd. |
---|---|
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include <qjsondocument.h> |
5 | #include <qjsonobject.h> |
6 | #include <qjsonvalue.h> |
7 | #include <qjsonarray.h> |
8 | #include <qstringlist.h> |
9 | #include <qvariant.h> |
10 | #include <qmap.h> |
11 | #include <qhash.h> |
12 | #include <qdebug.h> |
13 | #include <qcbormap.h> |
14 | #include <qcborarray.h> |
15 | #include "qcborvalue_p.h" |
16 | #include "qjsonwriter_p.h" |
17 | #include "qjsonparser_p.h" |
18 | #include "qjson_p.h" |
19 | #include "qdatastream.h" |
20 | |
21 | QT_BEGIN_NAMESPACE |
22 | |
23 | /*! \class QJsonDocument |
24 | \inmodule QtCore |
25 | \ingroup json |
26 | \ingroup shared |
27 | \ingroup qtserialization |
28 | \reentrant |
29 | \since 5.0 |
30 | |
31 | \brief The QJsonDocument class provides a way to read and write JSON documents. |
32 | |
33 | \compares equality |
34 | |
35 | QJsonDocument is a class that wraps a complete JSON document and can read |
36 | this document from, and write it to, a UTF-8 encoded text-based |
37 | representation. |
38 | |
39 | A JSON document can be converted from its text-based representation to a QJsonDocument |
40 | using QJsonDocument::fromJson(). toJson() converts it back to text. The parser is very |
41 | fast and efficient and converts the JSON to the binary representation used by Qt. |
42 | |
43 | Validity of the parsed document can be queried with !isNull() |
44 | |
45 | A document can be queried as to whether it contains an array or an object using isArray() |
46 | and isObject(). The array or object contained in the document can be retrieved using |
47 | array() or object() and then read or manipulated. |
48 | |
49 | \sa {JSON Support in Qt}, {Saving and Loading a Game} |
50 | */ |
51 | |
52 | |
53 | class QJsonDocumentPrivate |
54 | { |
55 | Q_DISABLE_COPY_MOVE(QJsonDocumentPrivate); |
56 | public: |
57 | QJsonDocumentPrivate() = default; |
58 | QJsonDocumentPrivate(QCborValue data) : value(std::move(data)) {} |
59 | ~QJsonDocumentPrivate() |
60 | { |
61 | if (rawData) |
62 | free(ptr: rawData); |
63 | } |
64 | |
65 | QCborValue value; |
66 | char *rawData = nullptr; |
67 | uint rawDataSize = 0; |
68 | |
69 | void clearRawData() |
70 | { |
71 | if (rawData) { |
72 | free(ptr: rawData); |
73 | rawData = nullptr; |
74 | rawDataSize = 0; |
75 | } |
76 | } |
77 | }; |
78 | |
79 | /*! |
80 | * Constructs an empty and invalid document. |
81 | */ |
82 | QJsonDocument::QJsonDocument() |
83 | : d(nullptr) |
84 | { |
85 | } |
86 | |
87 | /*! |
88 | * Creates a QJsonDocument from \a object. |
89 | */ |
90 | QJsonDocument::QJsonDocument(const QJsonObject &object) |
91 | : d(nullptr) |
92 | { |
93 | setObject(object); |
94 | } |
95 | |
96 | /*! |
97 | * Constructs a QJsonDocument from \a array. |
98 | */ |
99 | QJsonDocument::QJsonDocument(const QJsonArray &array) |
100 | : d(nullptr) |
101 | { |
102 | setArray(array); |
103 | } |
104 | |
105 | /*! |
106 | \internal |
107 | */ |
108 | QJsonDocument::QJsonDocument(const QCborValue &data) |
109 | : d(std::make_unique<QJsonDocumentPrivate>(args: data)) |
110 | { |
111 | Q_ASSERT(d); |
112 | } |
113 | |
114 | /*! |
115 | Deletes the document. |
116 | |
117 | Binary data set with fromRawData is not freed. |
118 | */ |
119 | QJsonDocument::~QJsonDocument() = default; |
120 | |
121 | /*! |
122 | * Creates a copy of the \a other document. |
123 | */ |
124 | QJsonDocument::QJsonDocument(const QJsonDocument &other) |
125 | { |
126 | if (other.d) { |
127 | if (!d) |
128 | d = std::make_unique<QJsonDocumentPrivate>(); |
129 | d->value = other.d->value; |
130 | } else { |
131 | d.reset(); |
132 | } |
133 | } |
134 | |
135 | QJsonDocument::QJsonDocument(QJsonDocument &&other) noexcept |
136 | : d(std::move(other.d)) |
137 | { |
138 | } |
139 | |
140 | void QJsonDocument::swap(QJsonDocument &other) noexcept |
141 | { |
142 | qSwap(value1&: d, value2&: other.d); |
143 | } |
144 | |
145 | /*! |
146 | * Assigns the \a other document to this QJsonDocument. |
147 | * Returns a reference to this object. |
148 | */ |
149 | QJsonDocument &QJsonDocument::operator =(const QJsonDocument &other) |
150 | { |
151 | if (this != &other) { |
152 | if (other.d) { |
153 | if (!d) |
154 | d = std::make_unique<QJsonDocumentPrivate>(); |
155 | else |
156 | d->clearRawData(); |
157 | d->value = other.d->value; |
158 | } else { |
159 | d.reset(); |
160 | } |
161 | } |
162 | return *this; |
163 | } |
164 | |
165 | /*! |
166 | \fn QJsonDocument::QJsonDocument(QJsonDocument &&other) |
167 | \since 5.10 |
168 | |
169 | Move-constructs a QJsonDocument from \a other. |
170 | */ |
171 | |
172 | /*! |
173 | \fn QJsonDocument &QJsonDocument::operator =(QJsonDocument &&other) |
174 | \since 5.10 |
175 | |
176 | Move-assigns \a other to this document. |
177 | */ |
178 | |
179 | /*! |
180 | \fn void QJsonDocument::swap(QJsonDocument &other) |
181 | \since 5.10 |
182 | |
183 | Swaps the document \a other with this. This operation is very fast and never fails. |
184 | */ |
185 | |
186 | #ifndef QT_NO_VARIANT |
187 | /*! |
188 | Creates a QJsonDocument from the QVariant \a variant. |
189 | |
190 | If the \a variant contains any other type than a QVariantMap, |
191 | QVariantHash, QVariantList or QStringList, the returned document is invalid. |
192 | |
193 | \sa toVariant() |
194 | */ |
195 | QJsonDocument QJsonDocument::fromVariant(const QVariant &variant) |
196 | { |
197 | QJsonDocument doc; |
198 | |
199 | switch (variant.metaType().id()) { |
200 | case QMetaType::QVariantMap: |
201 | doc.setObject(QJsonObject::fromVariantMap(map: variant.toMap())); |
202 | break; |
203 | case QMetaType::QVariantHash: |
204 | doc.setObject(QJsonObject::fromVariantHash(map: variant.toHash())); |
205 | break; |
206 | case QMetaType::QVariantList: |
207 | doc.setArray(QJsonArray::fromVariantList(list: variant.toList())); |
208 | break; |
209 | case QMetaType::QStringList: |
210 | doc.d = std::make_unique<QJsonDocumentPrivate>(); |
211 | doc.d->value = QCborArray::fromStringList(list: variant.toStringList()); |
212 | break; |
213 | default: |
214 | break; |
215 | } |
216 | return doc; |
217 | } |
218 | |
219 | /*! |
220 | Returns a QVariant representing the Json document. |
221 | |
222 | The returned variant will be a QVariantList if the document is |
223 | a QJsonArray and a QVariantMap if the document is a QJsonObject. |
224 | |
225 | \sa fromVariant(), QJsonValue::toVariant() |
226 | */ |
227 | QVariant QJsonDocument::toVariant() const |
228 | { |
229 | if (!d) |
230 | return QVariant(); |
231 | |
232 | QCborContainerPrivate *container = QJsonPrivate::Value::container(v: d->value); |
233 | if (d->value.isArray()) |
234 | return QJsonArray(container).toVariantList(); |
235 | return QJsonObject(container).toVariantMap(); |
236 | } |
237 | #endif // !QT_NO_VARIANT |
238 | |
239 | /*! |
240 | \enum QJsonDocument::JsonFormat |
241 | \since 5.1 |
242 | |
243 | This value defines the format of the JSON byte array produced |
244 | when converting to a QJsonDocument using toJson(). |
245 | |
246 | \value Indented Defines human readable output as follows: |
247 | \snippet code/src_corelib_serialization_qjsondocument.cpp 0 |
248 | |
249 | \value Compact Defines a compact output as follows: |
250 | \snippet code/src_corelib_serialization_qjsondocument.cpp 1 |
251 | */ |
252 | |
253 | /*! |
254 | \since 5.1 |
255 | Converts the QJsonDocument to a UTF-8 encoded JSON document in the provided \a format. |
256 | |
257 | \sa fromJson(), JsonFormat |
258 | */ |
259 | #if !defined(QT_JSON_READONLY) || defined(Q_QDOC) |
260 | QByteArray QJsonDocument::toJson(JsonFormat format) const |
261 | { |
262 | QByteArray json; |
263 | if (!d) |
264 | return json; |
265 | |
266 | const QCborContainerPrivate *container = QJsonPrivate::Value::container(v: d->value); |
267 | if (d->value.isArray()) |
268 | QJsonPrivate::Writer::arrayToJson(a: container, json, indent: 0, compact: (format == Compact)); |
269 | else |
270 | QJsonPrivate::Writer::objectToJson(o: container, json, indent: 0, compact: (format == Compact)); |
271 | |
272 | return json; |
273 | } |
274 | #endif |
275 | |
276 | /*! |
277 | Parses \a json as a UTF-8 encoded JSON document, and creates a QJsonDocument |
278 | from it. |
279 | |
280 | Returns a valid (non-null) QJsonDocument if the parsing succeeds. If it fails, |
281 | the returned document will be null, and the optional \a error variable will contain |
282 | further details about the error. |
283 | |
284 | \sa toJson(), QJsonParseError, isNull() |
285 | */ |
286 | QJsonDocument QJsonDocument::fromJson(const QByteArray &json, QJsonParseError *error) |
287 | { |
288 | QJsonPrivate::Parser parser(json.constData(), json.size()); |
289 | QJsonDocument result; |
290 | const QCborValue val = parser.parse(error); |
291 | if (val.isArray() || val.isMap()) { |
292 | result.d = std::make_unique<QJsonDocumentPrivate>(); |
293 | result.d->value = val; |
294 | } |
295 | return result; |
296 | } |
297 | |
298 | /*! |
299 | Returns \c true if the document doesn't contain any data. |
300 | */ |
301 | bool QJsonDocument::isEmpty() const |
302 | { |
303 | if (!d) |
304 | return true; |
305 | |
306 | return false; |
307 | } |
308 | |
309 | /*! |
310 | Returns \c true if the document contains an array. |
311 | |
312 | \sa array(), isObject() |
313 | */ |
314 | bool QJsonDocument::isArray() const |
315 | { |
316 | if (!d) |
317 | return false; |
318 | |
319 | return d->value.isArray(); |
320 | } |
321 | |
322 | /*! |
323 | Returns \c true if the document contains an object. |
324 | |
325 | \sa object(), isArray() |
326 | */ |
327 | bool QJsonDocument::isObject() const |
328 | { |
329 | if (!d) |
330 | return false; |
331 | |
332 | return d->value.isMap(); |
333 | } |
334 | |
335 | /*! |
336 | Returns the QJsonObject contained in the document. |
337 | |
338 | Returns an empty object if the document contains an |
339 | array. |
340 | |
341 | \sa isObject(), array(), setObject() |
342 | */ |
343 | QJsonObject QJsonDocument::object() const |
344 | { |
345 | if (isObject()) { |
346 | if (auto container = QJsonPrivate::Value::container(v: d->value)) |
347 | return QJsonObject(container); |
348 | } |
349 | return QJsonObject(); |
350 | } |
351 | |
352 | /*! |
353 | Returns the QJsonArray contained in the document. |
354 | |
355 | Returns an empty array if the document contains an |
356 | object. |
357 | |
358 | \sa isArray(), object(), setArray() |
359 | */ |
360 | QJsonArray QJsonDocument::array() const |
361 | { |
362 | if (isArray()) { |
363 | if (auto container = QJsonPrivate::Value::container(v: d->value)) |
364 | return QJsonArray(container); |
365 | } |
366 | return QJsonArray(); |
367 | } |
368 | |
369 | /*! |
370 | Sets \a object as the main object of this document. |
371 | |
372 | \sa setArray(), object() |
373 | */ |
374 | void QJsonDocument::setObject(const QJsonObject &object) |
375 | { |
376 | if (!d) |
377 | d = std::make_unique<QJsonDocumentPrivate>(); |
378 | else |
379 | d->clearRawData(); |
380 | |
381 | d->value = QCborValue::fromJsonValue(v: object); |
382 | } |
383 | |
384 | /*! |
385 | Sets \a array as the main object of this document. |
386 | |
387 | \sa setObject(), array() |
388 | */ |
389 | void QJsonDocument::setArray(const QJsonArray &array) |
390 | { |
391 | if (!d) |
392 | d = std::make_unique<QJsonDocumentPrivate>(); |
393 | else |
394 | d->clearRawData(); |
395 | |
396 | d->value = QCborValue::fromJsonValue(v: array); |
397 | } |
398 | |
399 | /*! |
400 | Returns a QJsonValue representing the value for the key \a key. |
401 | |
402 | Equivalent to calling object().value(key). |
403 | |
404 | The returned QJsonValue is QJsonValue::Undefined if the key does not exist, |
405 | or if isObject() is false. |
406 | |
407 | \since 5.10 |
408 | |
409 | \sa QJsonValue, QJsonValue::isUndefined(), QJsonObject |
410 | */ |
411 | const QJsonValue QJsonDocument::operator[](const QString &key) const |
412 | { |
413 | return (*this)[QStringView(key)]; |
414 | } |
415 | |
416 | /*! |
417 | \overload |
418 | \since 5.14 |
419 | */ |
420 | const QJsonValue QJsonDocument::operator[](QStringView key) const |
421 | { |
422 | if (!isObject()) |
423 | return QJsonValue(QJsonValue::Undefined); |
424 | |
425 | return QJsonPrivate::Value::fromTrustedCbor(v: d->value.toMap().value(key)); |
426 | } |
427 | |
428 | /*! |
429 | \overload |
430 | \since 5.10 |
431 | */ |
432 | const QJsonValue QJsonDocument::operator[](QLatin1StringView key) const |
433 | { |
434 | if (!isObject()) |
435 | return QJsonValue(QJsonValue::Undefined); |
436 | |
437 | return QJsonPrivate::Value::fromTrustedCbor(v: d->value.toMap().value(key)); |
438 | } |
439 | |
440 | /*! |
441 | Returns a QJsonValue representing the value for index \a i. |
442 | |
443 | Equivalent to calling array().at(i). |
444 | |
445 | The returned QJsonValue is QJsonValue::Undefined, if \a i is out of bounds, |
446 | or if isArray() is false. |
447 | |
448 | \since 5.10 |
449 | |
450 | \sa QJsonValue, QJsonValue::isUndefined(), QJsonArray |
451 | */ |
452 | const QJsonValue QJsonDocument::operator[](qsizetype i) const |
453 | { |
454 | if (!isArray()) |
455 | return QJsonValue(QJsonValue::Undefined); |
456 | |
457 | return QJsonPrivate::Value::fromTrustedCbor(v: d->value.toArray().at(i)); |
458 | } |
459 | |
460 | /*! |
461 | \fn bool QJsonDocument::operator==(const QJsonDocument &lhs, const QJsonDocument &rhs) |
462 | |
463 | Returns \c true if the \a lhs document is equal to \a rhs document, \c false otherwise. |
464 | */ |
465 | bool comparesEqual(const QJsonDocument &lhs, const QJsonDocument &rhs) noexcept |
466 | { |
467 | if (lhs.d && rhs.d) |
468 | return lhs.d->value == rhs.d->value; |
469 | return !lhs.d == !rhs.d; |
470 | } |
471 | |
472 | /*! |
473 | \fn bool QJsonDocument::operator!=(const QJsonDocument &lhs, const QJsonDocument &rhs) |
474 | |
475 | Returns \c true if the \a lhs document is not equal to \a rhs document, \c false otherwise. |
476 | */ |
477 | |
478 | /*! |
479 | returns \c true if this document is null. |
480 | |
481 | Null documents are documents created through the default constructor. |
482 | |
483 | Documents created from UTF-8 encoded text or the binary format are |
484 | validated during parsing. If validation fails, the returned document |
485 | will also be null. |
486 | */ |
487 | bool QJsonDocument::isNull() const |
488 | { |
489 | return (d == nullptr); |
490 | } |
491 | |
492 | #if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY) |
493 | QDebug operator<<(QDebug dbg, const QJsonDocument &o) |
494 | { |
495 | QDebugStateSaver saver(dbg); |
496 | if (!o.d) { |
497 | dbg << "QJsonDocument()"; |
498 | return dbg; |
499 | } |
500 | QByteArray json; |
501 | const QCborContainerPrivate *container = QJsonPrivate::Value::container(v: o.d->value); |
502 | if (o.d->value.isArray()) |
503 | QJsonPrivate::Writer::arrayToJson(a: container, json, indent: 0, compact: true); |
504 | else |
505 | QJsonPrivate::Writer::objectToJson(o: container, json, indent: 0, compact: true); |
506 | dbg.nospace() << "QJsonDocument(" |
507 | << json.constData() // print as utf-8 string without extra quotation marks |
508 | << ')'; |
509 | return dbg; |
510 | } |
511 | #endif |
512 | |
513 | #ifndef QT_NO_DATASTREAM |
514 | QDataStream &operator<<(QDataStream &stream, const QJsonDocument &doc) |
515 | { |
516 | stream << doc.toJson(format: QJsonDocument::Compact); |
517 | return stream; |
518 | } |
519 | |
520 | QDataStream &operator>>(QDataStream &stream, QJsonDocument &doc) |
521 | { |
522 | QByteArray buffer; |
523 | stream >> buffer; |
524 | QJsonParseError parseError{}; |
525 | doc = QJsonDocument::fromJson(json: buffer, error: &parseError); |
526 | if (parseError.error && !buffer.isEmpty()) |
527 | stream.setStatus(QDataStream::ReadCorruptData); |
528 | return stream; |
529 | } |
530 | #endif |
531 | |
532 | QT_END_NAMESPACE |
533 |
Definitions
- QJsonDocumentPrivate
- QJsonDocumentPrivate
- QJsonDocumentPrivate
- QJsonDocumentPrivate
- ~QJsonDocumentPrivate
- clearRawData
- QJsonDocument
- QJsonDocument
- QJsonDocument
- QJsonDocument
- ~QJsonDocument
- QJsonDocument
- QJsonDocument
- swap
- operator =
- fromVariant
- toVariant
- toJson
- fromJson
- isEmpty
- isArray
- isObject
- object
- array
- setObject
- setArray
- operator[]
- operator[]
- operator[]
- operator[]
- comparesEqual
- isNull
- operator<<
- operator<<
Start learning QML with our Intro Training
Find out more