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 | \memberswap{document} |
183 | */ |
184 | |
185 | #ifndef QT_NO_VARIANT |
186 | /*! |
187 | Creates a QJsonDocument from the QVariant \a variant. |
188 | |
189 | If the \a variant contains any other type than a QVariantMap, |
190 | QVariantHash, QVariantList or QStringList, the returned document is invalid. |
191 | |
192 | \sa toVariant() |
193 | */ |
194 | QJsonDocument QJsonDocument::fromVariant(const QVariant &variant) |
195 | { |
196 | QJsonDocument doc; |
197 | |
198 | switch (variant.metaType().id()) { |
199 | case QMetaType::QVariantMap: |
200 | doc.setObject(QJsonObject::fromVariantMap(map: variant.toMap())); |
201 | break; |
202 | case QMetaType::QVariantHash: |
203 | doc.setObject(QJsonObject::fromVariantHash(map: variant.toHash())); |
204 | break; |
205 | case QMetaType::QVariantList: |
206 | doc.setArray(QJsonArray::fromVariantList(list: variant.toList())); |
207 | break; |
208 | case QMetaType::QStringList: |
209 | doc.d = std::make_unique<QJsonDocumentPrivate>(); |
210 | doc.d->value = QCborArray::fromStringList(list: variant.toStringList()); |
211 | break; |
212 | default: |
213 | break; |
214 | } |
215 | return doc; |
216 | } |
217 | |
218 | /*! |
219 | Returns a QVariant representing the Json document. |
220 | |
221 | The returned variant will be a QVariantList if the document is |
222 | a QJsonArray and a QVariantMap if the document is a QJsonObject. |
223 | |
224 | \sa fromVariant(), QJsonValue::toVariant() |
225 | */ |
226 | QVariant QJsonDocument::toVariant() const |
227 | { |
228 | if (!d) |
229 | return QVariant(); |
230 | |
231 | QCborContainerPrivate *container = QJsonPrivate::Value::container(v: d->value); |
232 | if (d->value.isArray()) |
233 | return QJsonArray(container).toVariantList(); |
234 | return QJsonObject(container).toVariantMap(); |
235 | } |
236 | #endif // !QT_NO_VARIANT |
237 | |
238 | /*! |
239 | \enum QJsonDocument::JsonFormat |
240 | \since 5.1 |
241 | |
242 | This value defines the format of the JSON byte array produced |
243 | when converting to a QJsonDocument using toJson(). |
244 | |
245 | \value Indented Defines human readable output as follows: |
246 | \snippet code/src_corelib_serialization_qjsondocument.cpp 0 |
247 | |
248 | \value Compact Defines a compact output as follows: |
249 | \snippet code/src_corelib_serialization_qjsondocument.cpp 1 |
250 | */ |
251 | |
252 | /*! |
253 | \since 5.1 |
254 | Converts the QJsonDocument to a UTF-8 encoded JSON document in the provided \a format. |
255 | |
256 | \sa fromJson(), JsonFormat |
257 | */ |
258 | #if !defined(QT_JSON_READONLY) || defined(Q_QDOC) |
259 | QByteArray QJsonDocument::toJson(JsonFormat format) const |
260 | { |
261 | QByteArray json; |
262 | if (!d) |
263 | return json; |
264 | |
265 | const QCborContainerPrivate *container = QJsonPrivate::Value::container(v: d->value); |
266 | if (d->value.isArray()) |
267 | QJsonPrivate::Writer::arrayToJson(a: container, json, indent: 0, compact: (format == Compact)); |
268 | else |
269 | QJsonPrivate::Writer::objectToJson(o: container, json, indent: 0, compact: (format == Compact)); |
270 | |
271 | return json; |
272 | } |
273 | #endif |
274 | |
275 | /*! |
276 | Parses \a json as a UTF-8 encoded JSON document, and creates a QJsonDocument |
277 | from it. |
278 | |
279 | Returns a valid (non-null) QJsonDocument if the parsing succeeds. If it fails, |
280 | the returned document will be null, and the optional \a error variable will contain |
281 | further details about the error. |
282 | |
283 | \sa toJson(), QJsonParseError, isNull() |
284 | */ |
285 | QJsonDocument QJsonDocument::fromJson(const QByteArray &json, QJsonParseError *error) |
286 | { |
287 | QJsonPrivate::Parser parser(json.constData(), json.size()); |
288 | QJsonDocument result; |
289 | const QCborValue val = parser.parse(error); |
290 | if (val.isArray() || val.isMap()) { |
291 | result.d = std::make_unique<QJsonDocumentPrivate>(); |
292 | result.d->value = val; |
293 | } |
294 | return result; |
295 | } |
296 | |
297 | /*! |
298 | Returns \c true if the document doesn't contain any data. |
299 | */ |
300 | bool QJsonDocument::isEmpty() const |
301 | { |
302 | if (!d) |
303 | return true; |
304 | |
305 | return false; |
306 | } |
307 | |
308 | /*! |
309 | Returns \c true if the document contains an array. |
310 | |
311 | \sa array(), isObject() |
312 | */ |
313 | bool QJsonDocument::isArray() const |
314 | { |
315 | if (!d) |
316 | return false; |
317 | |
318 | return d->value.isArray(); |
319 | } |
320 | |
321 | /*! |
322 | Returns \c true if the document contains an object. |
323 | |
324 | \sa object(), isArray() |
325 | */ |
326 | bool QJsonDocument::isObject() const |
327 | { |
328 | if (!d) |
329 | return false; |
330 | |
331 | return d->value.isMap(); |
332 | } |
333 | |
334 | /*! |
335 | Returns the QJsonObject contained in the document. |
336 | |
337 | Returns an empty object if the document contains an |
338 | array. |
339 | |
340 | \sa isObject(), array(), setObject() |
341 | */ |
342 | QJsonObject QJsonDocument::object() const |
343 | { |
344 | if (isObject()) { |
345 | if (auto container = QJsonPrivate::Value::container(v: d->value)) |
346 | return QJsonObject(container); |
347 | } |
348 | return QJsonObject(); |
349 | } |
350 | |
351 | /*! |
352 | Returns the QJsonArray contained in the document. |
353 | |
354 | Returns an empty array if the document contains an |
355 | object. |
356 | |
357 | \sa isArray(), object(), setArray() |
358 | */ |
359 | QJsonArray QJsonDocument::array() const |
360 | { |
361 | if (isArray()) { |
362 | if (auto container = QJsonPrivate::Value::container(v: d->value)) |
363 | return QJsonArray(container); |
364 | } |
365 | return QJsonArray(); |
366 | } |
367 | |
368 | /*! |
369 | Sets \a object as the main object of this document. |
370 | |
371 | \sa setArray(), object() |
372 | */ |
373 | void QJsonDocument::setObject(const QJsonObject &object) |
374 | { |
375 | if (!d) |
376 | d = std::make_unique<QJsonDocumentPrivate>(); |
377 | else |
378 | d->clearRawData(); |
379 | |
380 | d->value = QCborValue::fromJsonValue(v: object); |
381 | } |
382 | |
383 | /*! |
384 | Sets \a array as the main object of this document. |
385 | |
386 | \sa setObject(), array() |
387 | */ |
388 | void QJsonDocument::setArray(const QJsonArray &array) |
389 | { |
390 | if (!d) |
391 | d = std::make_unique<QJsonDocumentPrivate>(); |
392 | else |
393 | d->clearRawData(); |
394 | |
395 | d->value = QCborValue::fromJsonValue(v: array); |
396 | } |
397 | |
398 | /*! |
399 | Returns a QJsonValue representing the value for the key \a key. |
400 | |
401 | Equivalent to calling object().value(key). |
402 | |
403 | The returned QJsonValue is QJsonValue::Undefined if the key does not exist, |
404 | or if isObject() is false. |
405 | |
406 | \since 5.10 |
407 | |
408 | \sa QJsonValue, QJsonValue::isUndefined(), QJsonObject |
409 | */ |
410 | const QJsonValue QJsonDocument::operator[](const QString &key) const |
411 | { |
412 | return (*this)[QStringView(key)]; |
413 | } |
414 | |
415 | /*! |
416 | \overload |
417 | \since 5.14 |
418 | */ |
419 | const QJsonValue QJsonDocument::operator[](QStringView key) const |
420 | { |
421 | if (!isObject()) |
422 | return QJsonValue(QJsonValue::Undefined); |
423 | |
424 | return QJsonPrivate::Value::fromTrustedCbor(v: d->value.toMap().value(key)); |
425 | } |
426 | |
427 | /*! |
428 | \overload |
429 | \since 5.10 |
430 | */ |
431 | const QJsonValue QJsonDocument::operator[](QLatin1StringView key) const |
432 | { |
433 | if (!isObject()) |
434 | return QJsonValue(QJsonValue::Undefined); |
435 | |
436 | return QJsonPrivate::Value::fromTrustedCbor(v: d->value.toMap().value(key)); |
437 | } |
438 | |
439 | /*! |
440 | Returns a QJsonValue representing the value for index \a i. |
441 | |
442 | Equivalent to calling array().at(i). |
443 | |
444 | The returned QJsonValue is QJsonValue::Undefined, if \a i is out of bounds, |
445 | or if isArray() is false. |
446 | |
447 | \since 5.10 |
448 | |
449 | \sa QJsonValue, QJsonValue::isUndefined(), QJsonArray |
450 | */ |
451 | const QJsonValue QJsonDocument::operator[](qsizetype i) const |
452 | { |
453 | if (!isArray()) |
454 | return QJsonValue(QJsonValue::Undefined); |
455 | |
456 | return QJsonPrivate::Value::fromTrustedCbor(v: d->value.toArray().at(i)); |
457 | } |
458 | |
459 | /*! |
460 | \fn bool QJsonDocument::operator==(const QJsonDocument &lhs, const QJsonDocument &rhs) |
461 | |
462 | Returns \c true if the \a lhs document is equal to \a rhs document, \c false otherwise. |
463 | */ |
464 | bool comparesEqual(const QJsonDocument &lhs, const QJsonDocument &rhs) noexcept |
465 | { |
466 | if (lhs.d && rhs.d) |
467 | return lhs.d->value == rhs.d->value; |
468 | return !lhs.d == !rhs.d; |
469 | } |
470 | |
471 | /*! |
472 | \fn bool QJsonDocument::operator!=(const QJsonDocument &lhs, const QJsonDocument &rhs) |
473 | |
474 | Returns \c true if the \a lhs document is not equal to \a rhs document, \c false otherwise. |
475 | */ |
476 | |
477 | /*! |
478 | returns \c true if this document is null. |
479 | |
480 | Null documents are documents created through the default constructor. |
481 | |
482 | Documents created from UTF-8 encoded text or the binary format are |
483 | validated during parsing. If validation fails, the returned document |
484 | will also be null. |
485 | */ |
486 | bool QJsonDocument::isNull() const |
487 | { |
488 | return (d == nullptr); |
489 | } |
490 | |
491 | #if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY) |
492 | QDebug operator<<(QDebug dbg, const QJsonDocument &o) |
493 | { |
494 | QDebugStateSaver saver(dbg); |
495 | if (!o.d) { |
496 | dbg << "QJsonDocument()"; |
497 | return dbg; |
498 | } |
499 | QByteArray json; |
500 | const QCborContainerPrivate *container = QJsonPrivate::Value::container(v: o.d->value); |
501 | if (o.d->value.isArray()) |
502 | QJsonPrivate::Writer::arrayToJson(a: container, json, indent: 0, compact: true); |
503 | else |
504 | QJsonPrivate::Writer::objectToJson(o: container, json, indent: 0, compact: true); |
505 | dbg.nospace() << "QJsonDocument(" |
506 | << json.constData() // print as utf-8 string without extra quotation marks |
507 | << ')'; |
508 | return dbg; |
509 | } |
510 | #endif |
511 | |
512 | #ifndef QT_NO_DATASTREAM |
513 | QDataStream &operator<<(QDataStream &stream, const QJsonDocument &doc) |
514 | { |
515 | stream << doc.toJson(format: QJsonDocument::Compact); |
516 | return stream; |
517 | } |
518 | |
519 | QDataStream &operator>>(QDataStream &stream, QJsonDocument &doc) |
520 | { |
521 | QByteArray buffer; |
522 | stream >> buffer; |
523 | QJsonParseError parseError{}; |
524 | doc = QJsonDocument::fromJson(json: buffer, error: &parseError); |
525 | if (parseError.error && !buffer.isEmpty()) |
526 | stream.setStatus(QDataStream::ReadCorruptData); |
527 | return stream; |
528 | } |
529 | #endif |
530 | |
531 | QT_END_NAMESPACE |
532 |
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