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// Qt-Security score:critical reason:data-parser
4
5#include <qplatformdefs.h>
6#include <qdom.h>
7#include "private/qxmlutils_p.h"
8
9#if QT_CONFIG(dom)
10
11#include "qdom_p.h"
12#include "qdomhelpers_p.h"
13
14#include <qatomic.h>
15#include <qbuffer.h>
16#include <qiodevice.h>
17#if QT_CONFIG(regularexpression)
18#include <qregularexpression.h>
19#endif
20#include <qtextstream.h>
21#include <qvariant.h>
22#include <qshareddata.h>
23#include <qdebug.h>
24#include <qxmlstream.h>
25#include <private/qduplicatetracker_p.h>
26#include <private/qstringiterator_p.h>
27#include <qvarlengtharray.h>
28
29#include <stdio.h>
30#include <limits>
31#include <memory>
32
33QT_BEGIN_NAMESPACE
34
35using namespace Qt::StringLiterals;
36
37/*
38 ### old todo comments -- I don't know if they still apply...
39
40 If the document dies, remove all pointers to it from children
41 which can not be deleted at this time.
42
43 If a node dies and has direct children which can not be deleted,
44 then remove the pointer to the parent.
45
46 createElement and friends create double reference counts.
47*/
48
49/* ##### new TODOs:
50
51 Remove empty methods in the *Private classes
52
53 Make a lot of the (mostly empty) methods in the public classes inline.
54 Specially constructors assignment operators and comparison operators are candidates.
55*/
56
57/*
58 Reference counting:
59
60 Some simple rules:
61 1) If an intern object returns a pointer to another intern object
62 then the reference count of the returned object is not increased.
63 2) If an extern object is created and gets a pointer to some intern
64 object, then the extern object increases the intern objects reference count.
65 3) If an extern object is deleted, then it decreases the reference count
66 on its associated intern object and deletes it if nobody else hold references
67 on the intern object.
68*/
69
70
71/*
72 Helper to split a qualified name in the prefix and local name.
73*/
74static void qt_split_namespace(QString& prefix, QString& name, const QString& qName, bool hasURI)
75{
76 qsizetype i = qName.indexOf(ch: u':');
77 if (i == -1) {
78 if (hasURI)
79 prefix = u""_s;
80 else
81 prefix.clear();
82 name = qName;
83 } else {
84 prefix = qName.left(n: i);
85 name = qName.mid(position: i + 1);
86 }
87}
88
89/**************************************************************
90 *
91 * Functions for verifying legal data
92 *
93 **************************************************************/
94QDomImplementation::InvalidDataPolicy QDomImplementationPrivate::invalidDataPolicy
95 = QDomImplementation::AcceptInvalidChars;
96
97// [5] Name ::= (Letter | '_' | ':') (NameChar)*
98
99static QString fixedXmlName(const QString &_name, bool *ok, bool namespaces = false)
100{
101 QString name, prefix;
102 if (namespaces)
103 qt_split_namespace(prefix, name, qName: _name, hasURI: true);
104 else
105 name = _name;
106
107 if (name.isEmpty()) {
108 *ok = false;
109 return QString();
110 }
111
112 if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::AcceptInvalidChars) {
113 *ok = true;
114 return _name;
115 }
116
117 QString result;
118 bool firstChar = true;
119 for (int i = 0; i < name.size(); ++i) {
120 QChar c = name.at(i);
121 if (firstChar) {
122 if (QXmlUtils::isLetter(c) || c.unicode() == '_' || c.unicode() == ':') {
123 result.append(c);
124 firstChar = false;
125 } else if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) {
126 *ok = false;
127 return QString();
128 }
129 } else {
130 if (QXmlUtils::isNameChar(c))
131 result.append(c);
132 else if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) {
133 *ok = false;
134 return QString();
135 }
136 }
137 }
138
139 if (result.isEmpty()) {
140 *ok = false;
141 return QString();
142 }
143
144 *ok = true;
145 if (namespaces && !prefix.isEmpty())
146 return prefix + u':' + result;
147 return result;
148}
149
150// [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
151// '<', '&' and "]]>" will be escaped when writing
152
153static QString fixedCharData(const QString &data, bool *ok)
154{
155 if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::AcceptInvalidChars) {
156 *ok = true;
157 return data;
158 }
159
160 QString result;
161 QStringIterator it(data);
162 while (it.hasNext()) {
163 const char32_t c = it.next(invalidAs: QChar::Null);
164 if (QXmlUtils::isChar(c)) {
165 result.append(v: QChar::fromUcs4(c));
166 } else if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) {
167 *ok = false;
168 return QString();
169 }
170 }
171
172 *ok = true;
173 return result;
174}
175
176// [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
177// can't escape "--", since entities are not recognised within comments
178
179static QString fixedComment(const QString &data, bool *ok)
180{
181 if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::AcceptInvalidChars) {
182 *ok = true;
183 return data;
184 }
185
186 QString fixedData = fixedCharData(data, ok);
187 if (!*ok)
188 return QString();
189
190 for (;;) {
191 qsizetype idx = fixedData.indexOf(s: "--"_L1);
192 if (idx == -1)
193 break;
194 if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) {
195 *ok = false;
196 return QString();
197 }
198 fixedData.remove(i: idx, len: 2);
199 }
200
201 *ok = true;
202 return fixedData;
203}
204
205// [20] CData ::= (Char* - (Char* ']]>' Char*))
206// can't escape "]]>", since entities are not recognised within comments
207
208static QString fixedCDataSection(const QString &data, bool *ok)
209{
210 if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::AcceptInvalidChars) {
211 *ok = true;
212 return data;
213 }
214
215 QString fixedData = fixedCharData(data, ok);
216 if (!*ok)
217 return QString();
218
219 for (;;) {
220 qsizetype idx = fixedData.indexOf(s: "]]>"_L1);
221 if (idx == -1)
222 break;
223 if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) {
224 *ok = false;
225 return QString();
226 }
227 fixedData.remove(i: idx, len: 3);
228 }
229
230 *ok = true;
231 return fixedData;
232}
233
234// [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
235
236static QString fixedPIData(const QString &data, bool *ok)
237{
238 if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::AcceptInvalidChars) {
239 *ok = true;
240 return data;
241 }
242
243 QString fixedData = fixedCharData(data, ok);
244 if (!*ok)
245 return QString();
246
247 for (;;) {
248 qsizetype idx = fixedData.indexOf(s: "?>"_L1);
249 if (idx == -1)
250 break;
251 if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) {
252 *ok = false;
253 return QString();
254 }
255 fixedData.remove(i: idx, len: 2);
256 }
257
258 *ok = true;
259 return fixedData;
260}
261
262// [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
263// The correct quote will be chosen when writing
264
265static QString fixedPubidLiteral(const QString &data, bool *ok)
266{
267 if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::AcceptInvalidChars) {
268 *ok = true;
269 return data;
270 }
271
272 QString result;
273
274 if (QXmlUtils::isPublicID(candidate: data))
275 result = data;
276 else if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) {
277 *ok = false;
278 return QString();
279 }
280
281 if (result.indexOf(ch: u'\'') != -1 && result.indexOf(ch: u'"') != -1) {
282 if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) {
283 *ok = false;
284 return QString();
285 } else {
286 result.remove(c: u'\'');
287 }
288 }
289
290 *ok = true;
291 return result;
292}
293
294// [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
295// The correct quote will be chosen when writing
296
297static QString fixedSystemLiteral(const QString &data, bool *ok)
298{
299 if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::AcceptInvalidChars) {
300 *ok = true;
301 return data;
302 }
303
304 QString result = data;
305
306 if (result.indexOf(ch: u'\'') != -1 && result.indexOf(ch: u'"') != -1) {
307 if (QDomImplementationPrivate::invalidDataPolicy == QDomImplementation::ReturnNullNode) {
308 *ok = false;
309 return QString();
310 } else {
311 result.remove(c: u'\'');
312 }
313 }
314
315 *ok = true;
316 return result;
317}
318
319/**************************************************************
320 *
321 * QDomImplementationPrivate
322 *
323 **************************************************************/
324
325QDomImplementationPrivate* QDomImplementationPrivate::clone()
326{
327 return new QDomImplementationPrivate;
328}
329
330/**************************************************************
331 *
332 * QDomImplementation
333 *
334 **************************************************************/
335
336/*!
337 \class QDomImplementation
338 \reentrant
339 \brief The QDomImplementation class provides information about the
340 features of the DOM implementation.
341
342 \inmodule QtXml
343 \ingroup xml-tools
344
345 This class describes the features that are supported by the DOM
346 implementation. Currently the XML subset of DOM Level 1 and DOM
347 Level 2 Core are supported.
348
349 Normally you will use the function QDomDocument::implementation()
350 to get the implementation object.
351
352 You can create a new document type with createDocumentType() and a
353 new document with createDocument().
354
355 For further information about the Document Object Model see
356 \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and
357 \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}. For a more
358 general introduction of the DOM implementation see the QDomDocument
359 documentation.
360
361 The QDom classes have a few issues of nonconformance with the XML
362 specifications that cannot be fixed in Qt 4 without breaking backward
363 compatibility. The Qt XML Patterns module and the QXmlStreamReader and
364 QXmlStreamWriter classes have a higher degree of a conformance.
365
366 \sa hasFeature()
367*/
368
369/*!
370 Constructs a QDomImplementation object.
371*/
372QDomImplementation::QDomImplementation()
373{
374 impl = nullptr;
375}
376
377/*!
378 Constructs a copy of \a implementation.
379*/
380QDomImplementation::QDomImplementation(const QDomImplementation &implementation)
381 : impl(implementation.impl)
382{
383 if (impl)
384 impl->ref.ref();
385}
386
387QDomImplementation::QDomImplementation(QDomImplementationPrivate *pimpl)
388 : impl(pimpl)
389{
390 // We want to be co-owners, so increase the reference count
391 if (impl)
392 impl->ref.ref();
393}
394
395/*!
396 Assigns \a other to this DOM implementation.
397*/
398QDomImplementation& QDomImplementation::operator=(const QDomImplementation &other)
399{
400 if (other.impl)
401 other.impl->ref.ref();
402 if (impl && !impl->ref.deref())
403 delete impl;
404 impl = other.impl;
405 return *this;
406}
407
408/*!
409 Returns \c true if \a other and this DOM implementation object were
410 created from the same QDomDocument; otherwise returns \c false.
411*/
412bool QDomImplementation::operator==(const QDomImplementation &other) const
413{
414 return impl == other.impl;
415}
416
417/*!
418 Returns \c true if \a other and this DOM implementation object were
419 created from different QDomDocuments; otherwise returns \c false.
420*/
421bool QDomImplementation::operator!=(const QDomImplementation &other) const
422{
423 return !operator==(other);
424}
425
426/*!
427 Destroys the object and frees its resources.
428*/
429QDomImplementation::~QDomImplementation()
430{
431 if (impl && !impl->ref.deref())
432 delete impl;
433}
434
435/*!
436 The function returns \c true if QDom implements the requested \a
437 version of a \a feature; otherwise returns \c false.
438
439 The currently supported features and their versions:
440 \table
441 \header \li Feature \li Version
442 \row \li XML \li 1.0
443 \endtable
444*/
445bool QDomImplementation::hasFeature(const QString& feature, const QString& version) const
446{
447 if (feature == "XML"_L1) {
448 if (version.isEmpty() || version == "1.0"_L1)
449 return true;
450 }
451 // ### add DOM level 2 features
452 return false;
453}
454
455/*!
456 Creates a document type node for the name \a qName.
457
458 \a publicId specifies the public identifier of the external
459 subset. If you specify an empty string (QString()) as the \a
460 publicId, this means that the document type has no public
461 identifier.
462
463 \a systemId specifies the system identifier of the external
464 subset. If you specify an empty string as the \a systemId, this
465 means that the document type has no system identifier.
466
467 Since you cannot have a public identifier without a system
468 identifier, the public identifier is set to an empty string if
469 there is no system identifier.
470
471 DOM level 2 does not support any other document type declaration
472 features.
473
474 The only way you can use a document type that was created this
475 way, is in combination with the createDocument() function to
476 create a QDomDocument with this document type.
477
478 In the DOM specification, this is the only way to create a non-null
479 document. For historical reasons, Qt also allows to create the
480 document using the default empty constructor. The resulting document
481 is null, but becomes non-null when a factory function, for example
482 QDomDocument::createElement(), is called. The document also becomes
483 non-null when setContent() is called.
484
485 \sa createDocument()
486*/
487QDomDocumentType QDomImplementation::createDocumentType(const QString& qName, const QString& publicId, const QString& systemId)
488{
489 bool ok;
490 QString fixedName = fixedXmlName(name: qName, ok: &ok, namespaces: true);
491 if (!ok)
492 return QDomDocumentType();
493
494 QString fixedPublicId = fixedPubidLiteral(data: publicId, ok: &ok);
495 if (!ok)
496 return QDomDocumentType();
497
498 QString fixedSystemId = fixedSystemLiteral(data: systemId, ok: &ok);
499 if (!ok)
500 return QDomDocumentType();
501
502 QDomDocumentTypePrivate *dt = new QDomDocumentTypePrivate(nullptr);
503 dt->name = fixedName;
504 if (systemId.isNull()) {
505 dt->publicId.clear();
506 dt->systemId.clear();
507 } else {
508 dt->publicId = fixedPublicId;
509 dt->systemId = fixedSystemId;
510 }
511 dt->ref.deref();
512 return QDomDocumentType(dt);
513}
514
515/*!
516 Creates a DOM document with the document type \a doctype. This
517 function also adds a root element node with the qualified name \a
518 qName and the namespace URI \a nsURI.
519*/
520QDomDocument QDomImplementation::createDocument(const QString& nsURI, const QString& qName, const QDomDocumentType& doctype)
521{
522 QDomDocument doc(doctype);
523 QDomElement root = doc.createElementNS(nsURI, qName);
524 if (root.isNull())
525 return QDomDocument();
526 doc.appendChild(newChild: root);
527 return doc;
528}
529
530/*!
531 Returns \c false if the object was created by
532 QDomDocument::implementation(); otherwise returns \c true.
533*/
534bool QDomImplementation::isNull()
535{
536 return (impl == nullptr);
537}
538
539/*!
540 \enum QDomImplementation::InvalidDataPolicy
541
542 This enum specifies what should be done when a factory function
543 in QDomDocument is called with invalid data.
544 \value AcceptInvalidChars The data should be stored in the DOM object
545 anyway. In this case the resulting XML document might not be well-formed.
546 This is the default value and QDom's behavior in Qt < 4.1.
547 \value DropInvalidChars The invalid characters should be removed from
548 the data.
549 \value ReturnNullNode The factory function should return a null node.
550
551 \sa setInvalidDataPolicy(), invalidDataPolicy()
552*/
553
554/*!
555 \enum QDomNode::EncodingPolicy
556 \since 4.3
557
558 This enum specifies how QDomNode::save() determines what encoding to use
559 when serializing.
560
561 \value EncodingFromDocument The encoding is fetched from the document.
562 \value EncodingFromTextStream The encoding is fetched from the QTextStream.
563
564 \sa QDomNode::save()
565*/
566
567/*!
568 \since 4.1
569 \nonreentrant
570
571 Returns the invalid data policy, which specifies what should be done when
572 a factory function in QDomDocument is passed invalid data.
573
574 \sa setInvalidDataPolicy(), InvalidDataPolicy
575*/
576
577QDomImplementation::InvalidDataPolicy QDomImplementation::invalidDataPolicy()
578{
579 return QDomImplementationPrivate::invalidDataPolicy;
580}
581
582/*!
583 \since 4.1
584 \nonreentrant
585
586 Sets the invalid data policy, which specifies what should be done when
587 a factory function in QDomDocument is passed invalid data.
588
589 The \a policy is set for all instances of QDomDocument which already
590 exist and which will be created in the future.
591
592 \snippet code/src_xml_dom_qdom.cpp 0
593
594 \sa invalidDataPolicy(), InvalidDataPolicy
595*/
596
597void QDomImplementation::setInvalidDataPolicy(InvalidDataPolicy policy)
598{
599 QDomImplementationPrivate::invalidDataPolicy = policy;
600}
601
602/**************************************************************
603 *
604 * QDomNodeListPrivate
605 *
606 **************************************************************/
607
608QDomNodeListPrivate::QDomNodeListPrivate(QDomNodePrivate *n_impl) : ref(1)
609{
610 node_impl = n_impl;
611 if (node_impl)
612 node_impl->ref.ref();
613 timestamp = 0;
614}
615
616QDomNodeListPrivate::QDomNodeListPrivate(QDomNodePrivate *n_impl, const QString &name) :
617 ref(1)
618{
619 node_impl = n_impl;
620 if (node_impl)
621 node_impl->ref.ref();
622 tagname = name;
623 timestamp = 0;
624}
625
626QDomNodeListPrivate::QDomNodeListPrivate(QDomNodePrivate *n_impl, const QString &_nsURI, const QString &localName) :
627 ref(1)
628{
629 node_impl = n_impl;
630 if (node_impl)
631 node_impl->ref.ref();
632 tagname = localName;
633 nsURI = _nsURI;
634 timestamp = 0;
635}
636
637QDomNodeListPrivate::~QDomNodeListPrivate()
638{
639 if (node_impl && !node_impl->ref.deref())
640 delete node_impl;
641}
642
643bool QDomNodeListPrivate::operator==(const QDomNodeListPrivate &other) const noexcept
644{
645 return (node_impl == other.node_impl) && (tagname == other.tagname);
646}
647
648void QDomNodeListPrivate::createList() const
649{
650 if (!node_impl)
651 return;
652
653 list.clear();
654 const QDomDocumentPrivate *const doc = node_impl->ownerDocument();
655 if (doc && timestamp != doc->nodeListTime)
656 timestamp = doc->nodeListTime;
657 forEachNode(yield: [&](QDomNodePrivate *p){ list.append(t: p); });
658}
659
660/*! \internal
661
662 Checks if a node is valid and fulfills the requirements set during the
663 generation of this list, i.e. matching tag and matching URI.
664*/
665bool QDomNodeListPrivate::checkNode(QDomNodePrivate *p) const
666{
667 return p && p->isElement() && (nsURI.isNull()
668 ? p->nodeName() == tagname
669 : p->name == tagname && p->namespaceURI == nsURI);
670}
671
672/*! \internal
673
674 Returns the next node item in the list. If the tagname or the URI are set,
675 the function iterates through the dom tree and returns node that match them.
676 If neither tag nor URI are set, the function iterates through a single level
677 in the tree and returns all nodes.
678
679 \sa forEachNode(), findPrevInOrder()
680 */
681QDomNodePrivate *QDomNodeListPrivate::findNextInOrder(QDomNodePrivate *p) const
682{
683 if (!p)
684 return p;
685
686 if (tagname.isNull()) {
687 if (p == node_impl)
688 return p->first;
689 else if (p && p->next)
690 return p->next;
691 }
692
693 if (p == node_impl) {
694 p = p->first;
695 if (checkNode(p))
696 return p;
697 }
698 while (p && p != node_impl) {
699 if (p->first) { // go down in the tree
700 p = p->first;
701 } else if (p->next) { // traverse the tree
702 p = p->next;
703 } else { // go up in the tree
704 p = p->parent();
705 while (p && p != node_impl && !p->next)
706 p = p->parent();
707 if (p && p != node_impl)
708 p = p->next;
709 }
710 if (checkNode(p))
711 return p;
712 }
713 return node_impl;
714}
715
716/*! \internal
717
718 Similar as findNextInOrder() but iterarating in the opposite order.
719
720 \sa forEachNode(), findNextInOrder()
721 */
722QDomNodePrivate *QDomNodeListPrivate::findPrevInOrder(QDomNodePrivate *p) const
723{
724 if (!p)
725 return p;
726
727 if (tagname.isNull() && p == node_impl)
728 return p->last;
729 if (tagname.isNull())
730 return p->prev;
731
732 // We end all the way down in the tree
733 // so that is where we have to start
734 if (p == node_impl) {
735 while (p->last)
736 p = p->last;
737 if (checkNode(p))
738 return p;
739 }
740
741 while (p) {
742 if (p->prev) {// traverse the tree backwards
743 p = p->prev;
744 // go mmediately down if an item has children
745 while (p->last)
746 p = p->last;
747 } else { // go up in the tree
748 p = p->parent();
749 }
750 if (checkNode(p))
751 return p;
752 }
753 return node_impl;
754}
755
756void QDomNodeListPrivate::forEachNode(qxp::function_ref<void(QDomNodePrivate*)> yield) const
757{
758 if (!node_impl)
759 return;
760
761 QDomNodePrivate *current = findNextInOrder(p: node_impl);
762 while (current && current != node_impl) {
763 yield(current);
764 current = findNextInOrder(p: current);
765 }
766}
767
768bool QDomNodeListPrivate::maybeCreateList() const
769{
770 if (!node_impl)
771 return false;
772
773 const QDomDocumentPrivate *const doc = node_impl->ownerDocument();
774 if (!doc || timestamp != doc->nodeListTime)
775 createList();
776
777 return true;
778}
779
780QDomNodePrivate *QDomNodeListPrivate::item(int index)
781{
782 if (!maybeCreateList() || index >= list.size() || index < 0)
783 return nullptr;
784
785 return list.at(i: index);
786}
787
788int QDomNodeListPrivate::length() const
789{
790 if (!maybeCreateList())
791 return 0;
792
793 return list.size();
794}
795
796int QDomNodeListPrivate::noexceptLength() const noexcept
797{
798 int count = 0;
799 forEachNode(yield: [&](QDomNodePrivate*){ ++count; });
800 return count;
801}
802
803/**************************************************************
804 *
805 * QDomNodeList
806 *
807 **************************************************************/
808
809/*!
810 \class QDomNodeList
811 \reentrant
812 \brief The QDomNodeList class is a list of QDomNode objects.
813
814 \inmodule QtXml
815 \ingroup xml-tools
816
817 Lists can be obtained by QDomDocument::elementsByTagName() and
818 QDomNode::childNodes(). The Document Object Model (DOM) requires
819 these lists to be "live": whenever you change the underlying
820 document, the contents of the list will get updated.
821
822 You can get a particular node from the list with item(). The
823 number of items in the list is returned by length().
824
825 For further information about the Document Object Model see
826 \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and
827 \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}.
828 For a more general introduction of the DOM implementation see the
829 QDomDocument documentation.
830
831 \sa QDomNode::childNodes(), QDomDocument::elementsByTagName()
832*/
833
834/*!
835 Creates an empty node list.
836*/
837QDomNodeList::QDomNodeList()
838 : impl(nullptr)
839{
840}
841
842QDomNodeList::QDomNodeList(QDomNodeListPrivate *pimpl)
843 : impl(pimpl)
844{
845}
846
847/*!
848 Constructs a copy of \a nodeList.
849*/
850QDomNodeList::QDomNodeList(const QDomNodeList &nodeList)
851 : impl(nodeList.impl)
852{
853 if (impl)
854 impl->ref.ref();
855}
856
857/*!
858 Assigns \a other to this node list.
859*/
860QDomNodeList& QDomNodeList::operator=(const QDomNodeList &other)
861{
862 if (other.impl)
863 other.impl->ref.ref();
864 if (impl && !impl->ref.deref())
865 delete impl;
866 impl = other.impl;
867 return *this;
868}
869
870/*!
871 \fn bool QDomNodeList::operator==(const QDomNodeList &lhs, const QDomNodeList &rhs)
872
873 Returns \c true if the node lists \a lhs and \a rhs are equal;
874 otherwise returns \c false.
875*/
876bool comparesEqual(const QDomNodeList &lhs, const QDomNodeList &rhs) noexcept
877{
878 if (lhs.impl == rhs.impl)
879 return true;
880 if (!lhs.impl || !rhs.impl)
881 return false;
882 return *lhs.impl == *rhs.impl;
883}
884
885/*!
886 \fn bool QDomNodeList::operator!=(const QDomNodeList &lhs, const QDomNodeList &rhs)
887
888 Returns \c true if the node lists \a lhs and \a rhs are not equal;
889 otherwise returns \c false.
890*/
891
892/*!
893 Destroys the object and frees its resources.
894*/
895QDomNodeList::~QDomNodeList()
896{
897 if (impl && !impl->ref.deref())
898 delete impl;
899}
900
901/*!
902 Returns the node at position \a index.
903
904 If \a index is negative or if \a index >= length() then a null
905 node is returned (i.e. a node for which QDomNode::isNull() returns
906 true).
907
908 \sa length()
909*/
910QDomNode QDomNodeList::item(int index) const
911{
912 if (!impl)
913 return QDomNode();
914
915 return QDomNode(impl->item(index));
916}
917
918/*!
919 Returns the number of nodes in the list.
920*/
921int QDomNodeList::length() const
922{
923 if (!impl)
924 return 0;
925 return impl->length();
926}
927
928/*!
929 Returns the number of nodes without creating the underlying QList.
930*/
931int QDomNodeList::noexceptLength() const noexcept
932{
933 if (!impl)
934 return 0;
935 return impl->noexceptLength();
936}
937
938/*!
939 \fn bool QDomNodeList::isEmpty() const
940
941 Returns \c true if the list contains no items; otherwise returns \c false.
942 This function is provided for Qt API consistency.
943*/
944
945/*!
946 \fn int QDomNodeList::count() const
947
948 This function is provided for Qt API consistency. It is equivalent to length().
949*/
950
951/*!
952 \fn int QDomNodeList::size() const
953
954 This function is provided for Qt API consistency. It is equivalent to length().
955*/
956
957/*!
958 \fn QDomNode QDomNodeList::at(int index) const
959
960 This function is provided for Qt API consistency. It is equivalent
961 to item().
962
963 If \a index is negative or if \a index >= length() then a null
964 node is returned (i.e. a node for which QDomNode::isNull() returns
965 true).
966*/
967
968/*!
969 \typedef QDomNodeList::const_iterator
970 \typedef QDomNodeList::const_reverse_iterator
971 \since 6.9
972
973 Typedefs for an opaque class that implements a bidirectional iterator over
974 a QDomNodeList.
975
976 \note QDomNodeList does not support modifying nodes in-place, so
977 there is no mutable iterator.
978*/
979
980/*!
981 \typedef QDomNodeList::value_type
982 \typedef QDomNodeList::difference_type
983 \typedef QDomNodeList::reference
984 \typedef QDomNodeList::const_reference
985 \typedef QDomNodeList::pointer
986 \typedef QDomNodeList::const_pointer
987 \since 6.9
988
989 Provided for STL-compatibility.
990
991 \note QDomNodeList does not support modifying nodes in-place, so
992 reference and const_reference are the same type, as are pointer and
993 const_pointer.
994*/
995
996/*!
997 \fn QDomNodeList::begin() const
998 \fn QDomNodeList::end() const;
999 \fn QDomNodeList::rbegin() const
1000 \fn QDomNodeList::rend() const;
1001 \fn QDomNodeList::cbegin() const
1002 \fn QDomNodeList::cend() const;
1003 \fn QDomNodeList::crbegin() const
1004 \fn QDomNodeList::crend() const;
1005 \fn QDomNodeList::constBegin() const;
1006 \fn QDomNodeList::constEnd() const;
1007 \since 6.9
1008
1009 Returns a const_iterator or const_reverse_iterator, respectively, pointing
1010 to the first or one past the last item in the list.
1011
1012 \note QDomNodeList does not support modifying nodes in-place, so
1013 there is no mutable iterator.
1014*/
1015
1016QDomNodeList::It::It(const QDomNodeListPrivate *lp, bool start) noexcept
1017 : parent(lp)
1018{
1019 if (!lp || !lp->node_impl)
1020 current = nullptr;
1021 else if (start)
1022 current = lp->findNextInOrder(p: lp->node_impl);
1023 else
1024 current = lp->node_impl;
1025}
1026
1027QDomNodePrivate *QDomNodeList::It::findNextInOrder(const QDomNodeListPrivate *parent, QDomNodePrivate *current)
1028{
1029 return parent->findNextInOrder(p: current);
1030}
1031
1032QDomNodePrivate *QDomNodeList::It::findPrevInOrder(const QDomNodeListPrivate *parent, QDomNodePrivate *current)
1033{
1034 return parent->findPrevInOrder(p: current);
1035}
1036
1037/**************************************************************
1038 *
1039 * QDomNodePrivate
1040 *
1041 **************************************************************/
1042
1043inline void QDomNodePrivate::setOwnerDocument(QDomDocumentPrivate *doc)
1044{
1045 ownerNode = doc;
1046 hasParent = false;
1047}
1048
1049QDomNodePrivate::QDomNodePrivate(QDomDocumentPrivate *doc, QDomNodePrivate *par) : ref(1)
1050{
1051 if (par)
1052 setParent(par);
1053 else
1054 setOwnerDocument(doc);
1055 prev = nullptr;
1056 next = nullptr;
1057 first = nullptr;
1058 last = nullptr;
1059 createdWithDom1Interface = true;
1060 lineNumber = -1;
1061 columnNumber = -1;
1062}
1063
1064QDomNodePrivate::QDomNodePrivate(QDomNodePrivate *n, bool deep) : ref(1)
1065{
1066 setOwnerDocument(n->ownerDocument());
1067 prev = nullptr;
1068 next = nullptr;
1069 first = nullptr;
1070 last = nullptr;
1071
1072 name = n->name;
1073 value = n->value;
1074 prefix = n->prefix;
1075 namespaceURI = n->namespaceURI;
1076 createdWithDom1Interface = n->createdWithDom1Interface;
1077 lineNumber = -1;
1078 columnNumber = -1;
1079
1080 if (!deep)
1081 return;
1082
1083 for (QDomNodePrivate* x = n->first; x; x = x->next)
1084 appendChild(newChild: x->cloneNode(deep: true));
1085}
1086
1087QDomNodePrivate::~QDomNodePrivate()
1088{
1089 QDomNodePrivate* p = first;
1090 QDomNodePrivate* n;
1091
1092 while (p) {
1093 n = p->next;
1094 if (!p->ref.deref())
1095 delete p;
1096 else
1097 p->setNoParent();
1098 p = n;
1099 }
1100 first = nullptr;
1101 last = nullptr;
1102}
1103
1104void QDomNodePrivate::clear()
1105{
1106 QDomNodePrivate* p = first;
1107 QDomNodePrivate* n;
1108
1109 while (p) {
1110 n = p->next;
1111 if (!p->ref.deref())
1112 delete p;
1113 p = n;
1114 }
1115 first = nullptr;
1116 last = nullptr;
1117}
1118
1119QDomNodePrivate* QDomNodePrivate::namedItem(const QString &n)
1120{
1121 QDomNodePrivate* p = first;
1122 while (p) {
1123 if (p->nodeName() == n)
1124 return p;
1125 p = p->next;
1126 }
1127 return nullptr;
1128}
1129
1130
1131QDomNodePrivate* QDomNodePrivate::insertBefore(QDomNodePrivate* newChild, QDomNodePrivate* refChild)
1132{
1133 // Error check
1134 if (!newChild)
1135 return nullptr;
1136
1137 // Error check
1138 if (newChild == refChild)
1139 return nullptr;
1140
1141 // Error check
1142 if (refChild && refChild->parent() != this)
1143 return nullptr;
1144
1145 // "mark lists as dirty"
1146 QDomDocumentPrivate *const doc = ownerDocument();
1147 if (doc)
1148 doc->nodeListTime++;
1149
1150 // Special handling for inserting a fragment. We just insert
1151 // all elements of the fragment instead of the fragment itself.
1152 if (newChild->isDocumentFragment()) {
1153 // Fragment is empty ?
1154 if (newChild->first == nullptr)
1155 return newChild;
1156
1157 // New parent
1158 QDomNodePrivate* n = newChild->first;
1159 while (n) {
1160 n->setParent(this);
1161 n = n->next;
1162 }
1163
1164 // Insert at the beginning ?
1165 if (!refChild || refChild->prev == nullptr) {
1166 if (first)
1167 first->prev = newChild->last;
1168 newChild->last->next = first;
1169 if (!last)
1170 last = newChild->last;
1171 first = newChild->first;
1172 } else {
1173 // Insert in the middle
1174 newChild->last->next = refChild;
1175 newChild->first->prev = refChild->prev;
1176 refChild->prev->next = newChild->first;
1177 refChild->prev = newChild->last;
1178 }
1179
1180 // No need to increase the reference since QDomDocumentFragment
1181 // does not decrease the reference.
1182
1183 // Remove the nodes from the fragment
1184 newChild->first = nullptr;
1185 newChild->last = nullptr;
1186 return newChild;
1187 }
1188
1189 // No more errors can occur now, so we take
1190 // ownership of the node.
1191 newChild->ref.ref();
1192
1193 if (newChild->parent())
1194 newChild->parent()->removeChild(oldChild: newChild);
1195
1196 newChild->setParent(this);
1197
1198 if (!refChild) {
1199 if (first)
1200 first->prev = newChild;
1201 newChild->next = first;
1202 if (!last)
1203 last = newChild;
1204 first = newChild;
1205 return newChild;
1206 }
1207
1208 if (refChild->prev == nullptr) {
1209 if (first)
1210 first->prev = newChild;
1211 newChild->next = first;
1212 if (!last)
1213 last = newChild;
1214 first = newChild;
1215 return newChild;
1216 }
1217
1218 newChild->next = refChild;
1219 newChild->prev = refChild->prev;
1220 refChild->prev->next = newChild;
1221 refChild->prev = newChild;
1222
1223 return newChild;
1224}
1225
1226QDomNodePrivate* QDomNodePrivate::insertAfter(QDomNodePrivate* newChild, QDomNodePrivate* refChild)
1227{
1228 // Error check
1229 if (!newChild)
1230 return nullptr;
1231
1232 // Error check
1233 if (newChild == refChild)
1234 return nullptr;
1235
1236 // Error check
1237 if (refChild && refChild->parent() != this)
1238 return nullptr;
1239
1240 // "mark lists as dirty"
1241 QDomDocumentPrivate *const doc = ownerDocument();
1242 if (doc)
1243 doc->nodeListTime++;
1244
1245 // Special handling for inserting a fragment. We just insert
1246 // all elements of the fragment instead of the fragment itself.
1247 if (newChild->isDocumentFragment()) {
1248 // Fragment is empty ?
1249 if (newChild->first == nullptr)
1250 return newChild;
1251
1252 // New parent
1253 QDomNodePrivate* n = newChild->first;
1254 while (n) {
1255 n->setParent(this);
1256 n = n->next;
1257 }
1258
1259 // Insert at the end
1260 if (!refChild || refChild->next == nullptr) {
1261 if (last)
1262 last->next = newChild->first;
1263 newChild->first->prev = last;
1264 if (!first)
1265 first = newChild->first;
1266 last = newChild->last;
1267 } else { // Insert in the middle
1268 newChild->first->prev = refChild;
1269 newChild->last->next = refChild->next;
1270 refChild->next->prev = newChild->last;
1271 refChild->next = newChild->first;
1272 }
1273
1274 // No need to increase the reference since QDomDocumentFragment
1275 // does not decrease the reference.
1276
1277 // Remove the nodes from the fragment
1278 newChild->first = nullptr;
1279 newChild->last = nullptr;
1280 return newChild;
1281 }
1282
1283 // Release new node from its current parent
1284 if (newChild->parent())
1285 newChild->parent()->removeChild(oldChild: newChild);
1286
1287 // No more errors can occur now, so we take
1288 // ownership of the node
1289 newChild->ref.ref();
1290
1291 newChild->setParent(this);
1292
1293 // Insert at the end
1294 if (!refChild) {
1295 if (last)
1296 last->next = newChild;
1297 newChild->prev = last;
1298 if (!first)
1299 first = newChild;
1300 last = newChild;
1301 return newChild;
1302 }
1303
1304 if (refChild->next == nullptr) {
1305 if (last)
1306 last->next = newChild;
1307 newChild->prev = last;
1308 if (!first)
1309 first = newChild;
1310 last = newChild;
1311 return newChild;
1312 }
1313
1314 newChild->prev = refChild;
1315 newChild->next = refChild->next;
1316 refChild->next->prev = newChild;
1317 refChild->next = newChild;
1318
1319 return newChild;
1320}
1321
1322QDomNodePrivate* QDomNodePrivate::replaceChild(QDomNodePrivate* newChild, QDomNodePrivate* oldChild)
1323{
1324 if (!newChild || !oldChild)
1325 return nullptr;
1326 if (oldChild->parent() != this)
1327 return nullptr;
1328 if (newChild == oldChild)
1329 return nullptr;
1330
1331 // mark lists as dirty
1332 QDomDocumentPrivate *const doc = ownerDocument();
1333 if (doc)
1334 doc->nodeListTime++;
1335
1336 // Special handling for inserting a fragment. We just insert
1337 // all elements of the fragment instead of the fragment itself.
1338 if (newChild->isDocumentFragment()) {
1339 // Fragment is empty ?
1340 if (newChild->first == nullptr)
1341 return newChild;
1342
1343 // New parent
1344 QDomNodePrivate* n = newChild->first;
1345 while (n) {
1346 n->setParent(this);
1347 n = n->next;
1348 }
1349
1350
1351 if (oldChild->next)
1352 oldChild->next->prev = newChild->last;
1353 if (oldChild->prev)
1354 oldChild->prev->next = newChild->first;
1355
1356 newChild->last->next = oldChild->next;
1357 newChild->first->prev = oldChild->prev;
1358
1359 if (first == oldChild)
1360 first = newChild->first;
1361 if (last == oldChild)
1362 last = newChild->last;
1363
1364 oldChild->setNoParent();
1365 oldChild->next = nullptr;
1366 oldChild->prev = nullptr;
1367
1368 // No need to increase the reference since QDomDocumentFragment
1369 // does not decrease the reference.
1370
1371 // Remove the nodes from the fragment
1372 newChild->first = nullptr;
1373 newChild->last = nullptr;
1374
1375 // We are no longer interested in the old node
1376 oldChild->ref.deref();
1377
1378 return oldChild;
1379 }
1380
1381 // No more errors can occur now, so we take
1382 // ownership of the node
1383 newChild->ref.ref();
1384
1385 // Release new node from its current parent
1386 if (newChild->parent())
1387 newChild->parent()->removeChild(oldChild: newChild);
1388
1389 newChild->setParent(this);
1390
1391 if (oldChild->next)
1392 oldChild->next->prev = newChild;
1393 if (oldChild->prev)
1394 oldChild->prev->next = newChild;
1395
1396 newChild->next = oldChild->next;
1397 newChild->prev = oldChild->prev;
1398
1399 if (first == oldChild)
1400 first = newChild;
1401 if (last == oldChild)
1402 last = newChild;
1403
1404 oldChild->setNoParent();
1405 oldChild->next = nullptr;
1406 oldChild->prev = nullptr;
1407
1408 // We are no longer interested in the old node
1409 oldChild->ref.deref();
1410
1411 return oldChild;
1412}
1413
1414QDomNodePrivate* QDomNodePrivate::removeChild(QDomNodePrivate* oldChild)
1415{
1416 // Error check
1417 if (oldChild->parent() != this)
1418 return nullptr;
1419
1420 // "mark lists as dirty"
1421 QDomDocumentPrivate *const doc = ownerDocument();
1422 if (doc)
1423 doc->nodeListTime++;
1424
1425 // Perhaps oldChild was just created with "createElement" or that. In this case
1426 // its parent is QDomDocument but it is not part of the documents child list.
1427 if (oldChild->next == nullptr && oldChild->prev == nullptr && first != oldChild)
1428 return nullptr;
1429
1430 if (oldChild->next)
1431 oldChild->next->prev = oldChild->prev;
1432 if (oldChild->prev)
1433 oldChild->prev->next = oldChild->next;
1434
1435 if (last == oldChild)
1436 last = oldChild->prev;
1437 if (first == oldChild)
1438 first = oldChild->next;
1439
1440 oldChild->setNoParent();
1441 oldChild->next = nullptr;
1442 oldChild->prev = nullptr;
1443
1444 // We are no longer interested in the old node
1445 oldChild->ref.deref();
1446
1447 return oldChild;
1448}
1449
1450QDomNodePrivate* QDomNodePrivate::appendChild(QDomNodePrivate* newChild)
1451{
1452 // No reference manipulation needed. Done in insertAfter.
1453 return insertAfter(newChild, refChild: nullptr);
1454}
1455
1456QDomDocumentPrivate* QDomNodePrivate::ownerDocument()
1457{
1458 QDomNodePrivate* p = this;
1459 while (p && !p->isDocument()) {
1460 if (!p->hasParent)
1461 return static_cast<QDomDocumentPrivate *>(p->ownerNode);
1462 p = p->parent();
1463 }
1464
1465 return static_cast<QDomDocumentPrivate *>(p);
1466}
1467
1468QDomNodePrivate* QDomNodePrivate::cloneNode(bool deep)
1469{
1470 QDomNodePrivate* p = new QDomNodePrivate(this, deep);
1471 // We are not interested in this node
1472 p->ref.deref();
1473 return p;
1474}
1475
1476static void qNormalizeNode(QDomNodePrivate* n)
1477{
1478 QDomNodePrivate* p = n->first;
1479 QDomTextPrivate* t = nullptr;
1480
1481 while (p) {
1482 if (p->isText()) {
1483 if (t) {
1484 QDomNodePrivate* tmp = p->next;
1485 t->appendData(arg: p->nodeValue());
1486 n->removeChild(oldChild: p);
1487 p = tmp;
1488 } else {
1489 t = static_cast<QDomTextPrivate *>(p);
1490 p = p->next;
1491 }
1492 } else {
1493 p = p->next;
1494 t = nullptr;
1495 }
1496 }
1497}
1498void QDomNodePrivate::normalize()
1499{
1500 // ### This one has moved from QDomElementPrivate to this position. It is
1501 // not tested.
1502 qNormalizeNode(n: this);
1503}
1504
1505void QDomNodePrivate::saveSubTree(const QDomNodePrivate *n, QTextStream &s,
1506 int depth, int indent) const
1507{
1508 if (!n)
1509 return;
1510
1511 const QDomNodePrivate *root = n->first;
1512 n->save(s, depth, indent);
1513 if (root) {
1514 const int branchDepth = depth + 1;
1515 int layerDepth = 0;
1516 while (root) {
1517 root->save(s, layerDepth + branchDepth, indent);
1518 // A flattened (non-recursive) depth-first walk through the node tree.
1519 if (root->first) {
1520 layerDepth ++;
1521 root = root->first;
1522 continue;
1523 }
1524 root->afterSave(s, layerDepth + branchDepth, indent);
1525 const QDomNodePrivate *prev = root;
1526 root = root->next;
1527 // Close QDomElementPrivate groups
1528 while (!root && (layerDepth > 0)) {
1529 root = prev->parent();
1530 layerDepth --;
1531 root->afterSave(s, layerDepth + branchDepth, indent);
1532 prev = root;
1533 root = root->next;
1534 }
1535 }
1536 Q_ASSERT(layerDepth == 0);
1537 }
1538 n->afterSave(s, depth, indent);
1539}
1540
1541void QDomNodePrivate::setLocation(int lineNumber, int columnNumber)
1542{
1543 this->lineNumber = lineNumber;
1544 this->columnNumber = columnNumber;
1545}
1546
1547/**************************************************************
1548 *
1549 * QDomNode
1550 *
1551 **************************************************************/
1552
1553#define IMPL static_cast<QDomNodePrivate *>(impl)
1554
1555/*!
1556 \class QDomNode
1557 \reentrant
1558 \brief The QDomNode class is the base class for all the nodes in a DOM tree.
1559
1560 \inmodule QtXml
1561 \ingroup xml-tools
1562
1563
1564 Many functions in the DOM return a QDomNode.
1565
1566 You can find out the type of a node using isAttr(),
1567 isCDATASection(), isDocumentFragment(), isDocument(),
1568 isDocumentType(), isElement(), isEntityReference(), isText(),
1569 isEntity(), isNotation(), isProcessingInstruction(),
1570 isCharacterData() and isComment().
1571
1572 A QDomNode can be converted into one of its subclasses using
1573 toAttr(), toCDATASection(), toDocumentFragment(), toDocument(),
1574 toDocumentType(), toElement(), toEntityReference(), toText(),
1575 toEntity(), toNotation(), toProcessingInstruction(),
1576 toCharacterData() or toComment(). You can convert a node to a null
1577 node with clear().
1578
1579 Copies of the QDomNode class share their data using explicit
1580 sharing. This means that modifying one node will change all
1581 copies. This is especially useful in combination with functions
1582 which return a QDomNode, e.g. firstChild(). You can make an
1583 independent (deep) copy of the node with cloneNode().
1584
1585 A QDomNode can be null, much like \nullptr. Creating a copy
1586 of a null node results in another null node. It is not
1587 possible to modify a null node, but it is possible to assign another,
1588 possibly non-null node to it. In this case, the copy of the null node
1589 will remain null. You can check if a QDomNode is null by calling isNull().
1590 The empty constructor of a QDomNode (or any of the derived classes) creates
1591 a null node.
1592
1593 Nodes are inserted with insertBefore(), insertAfter() or
1594 appendChild(). You can replace one node with another using
1595 replaceChild() and remove a node with removeChild().
1596
1597 To traverse nodes use firstChild() to get a node's first child (if
1598 any), and nextSibling() to traverse. QDomNode also provides
1599 lastChild(), previousSibling() and parentNode(). To find the first
1600 child node with a particular node name use namedItem().
1601
1602 To find out if a node has children use hasChildNodes() and to get
1603 a list of all of a node's children use childNodes().
1604
1605 The node's name and value (the meaning of which varies depending
1606 on its type) is returned by nodeName() and nodeValue()
1607 respectively. The node's type is returned by nodeType(). The
1608 node's value can be set with setNodeValue().
1609
1610 The document to which the node belongs is returned by
1611 ownerDocument().
1612
1613 Adjacent QDomText nodes can be merged into a single node with
1614 normalize().
1615
1616 \l QDomElement nodes have attributes which can be retrieved with
1617 attributes().
1618
1619 QDomElement and QDomAttr nodes can have namespaces which can be
1620 retrieved with namespaceURI(). Their local name is retrieved with
1621 localName(), and their prefix with prefix(). The prefix can be set
1622 with setPrefix().
1623
1624 You can write the XML representation of the node to a text stream
1625 with save().
1626
1627 The following example looks for the first element in an XML document and
1628 prints the names of all the elements that are its direct children.
1629
1630 \snippet code/src_xml_dom_qdom.cpp 1
1631
1632 For further information about the Document Object Model see
1633 \l{W3C DOM Level 1}{Level 1} and
1634 \l{W3C DOM Level 2}{Level 2 Core}.
1635 For a more general introduction of the DOM implementation see the
1636 QDomDocument documentation.
1637*/
1638
1639/*!
1640 Constructs a \l{isNull()}{null} node.
1641*/
1642QDomNode::QDomNode()
1643 : impl(nullptr)
1644{
1645}
1646
1647/*!
1648 Constructs a copy of \a node.
1649
1650 The data of the copy is shared (shallow copy): modifying one node
1651 will also change the other. If you want to make a deep copy, use
1652 cloneNode().
1653*/
1654QDomNode::QDomNode(const QDomNode &node)
1655 : impl(node.impl)
1656{
1657 if (impl)
1658 impl->ref.ref();
1659}
1660
1661/*! \internal
1662 Constructs a new node for the data \a pimpl.
1663*/
1664QDomNode::QDomNode(QDomNodePrivate *pimpl)
1665 : impl(pimpl)
1666{
1667 if (impl)
1668 impl->ref.ref();
1669}
1670
1671/*!
1672 Assigns a copy of \a other to this DOM node.
1673
1674 The data of the copy is shared (shallow copy): modifying one node
1675 will also change the other. If you want to make a deep copy, use
1676 cloneNode().
1677*/
1678QDomNode& QDomNode::operator=(const QDomNode &other)
1679{
1680 if (other.impl)
1681 other.impl->ref.ref();
1682 if (impl && !impl->ref.deref())
1683 delete impl;
1684 impl = other.impl;
1685 return *this;
1686}
1687
1688/*!
1689 Returns \c true if \a other and this DOM node are equal; otherwise
1690 returns \c false.
1691
1692 Any instance of QDomNode acts as a reference to an underlying data
1693 structure in QDomDocument. The test for equality checks if the two
1694 references point to the same underlying node. For example:
1695
1696 \snippet code/src_xml_dom_qdom.cpp 2
1697
1698 The two nodes (QDomElement is a QDomNode subclass) both refer to
1699 the document's root element, and \c {element1 == element2} will
1700 return true. On the other hand:
1701
1702 \snippet code/src_xml_dom_qdom.cpp 3
1703
1704 Even though both nodes are empty elements carrying the same name,
1705 \c {element3 == element4} will return false because they refer to
1706 two different nodes in the underlying data structure.
1707*/
1708bool QDomNode::operator==(const QDomNode &other) const
1709{
1710 return impl == other.impl;
1711}
1712
1713/*!
1714 Returns \c true if \a other and this DOM node are not equal; otherwise
1715 returns \c false.
1716*/
1717bool QDomNode::operator!=(const QDomNode &other) const
1718{
1719 return !operator==(other);
1720}
1721
1722/*!
1723 Destroys the object and frees its resources.
1724*/
1725QDomNode::~QDomNode()
1726{
1727 if (impl && !impl->ref.deref())
1728 delete impl;
1729}
1730
1731/*!
1732 Returns the name of the node.
1733
1734 The meaning of the name depends on the subclass:
1735
1736 \table
1737 \header \li Name \li Meaning
1738 \row \li QDomAttr \li The name of the attribute
1739 \row \li QDomCDATASection \li The string "#cdata-section"
1740 \row \li QDomComment \li The string "#comment"
1741 \row \li QDomDocument \li The string "#document"
1742 \row \li QDomDocumentFragment \li The string "#document-fragment"
1743 \row \li QDomDocumentType \li The name of the document type
1744 \row \li QDomElement \li The tag name
1745 \row \li QDomEntity \li The name of the entity
1746 \row \li QDomEntityReference \li The name of the referenced entity
1747 \row \li QDomNotation \li The name of the notation
1748 \row \li QDomProcessingInstruction \li The target of the processing instruction
1749 \row \li QDomText \li The string "#text"
1750 \endtable
1751
1752 \b{Note:} This function does not take the presence of namespaces into account
1753 when processing the names of element and attribute nodes. As a result, the
1754 returned name can contain any namespace prefix that may be present.
1755 To obtain the node name of an element or attribute, use localName(); to
1756 obtain the namespace prefix, use namespaceURI().
1757
1758 \sa nodeValue()
1759*/
1760QString QDomNode::nodeName() const
1761{
1762 if (!impl)
1763 return QString();
1764
1765 if (!IMPL->prefix.isEmpty())
1766 return IMPL->prefix + u':' + IMPL->name;
1767 return IMPL->name;
1768}
1769
1770/*!
1771 Returns the value of the node.
1772
1773 The meaning of the value depends on the subclass:
1774 \table
1775 \header \li Name \li Meaning
1776 \row \li QDomAttr \li The attribute value
1777 \row \li QDomCDATASection \li The content of the CDATA section
1778 \row \li QDomComment \li The comment
1779 \row \li QDomProcessingInstruction \li The data of the processing instruction
1780 \row \li QDomText \li The text
1781 \endtable
1782
1783 All the other subclasses do not have a node value and will return
1784 an empty string.
1785
1786 \sa setNodeValue(), nodeName()
1787*/
1788QString QDomNode::nodeValue() const
1789{
1790 if (!impl)
1791 return QString();
1792 return IMPL->value;
1793}
1794
1795/*!
1796 Sets the node's value to \a value.
1797
1798 \sa nodeValue()
1799*/
1800void QDomNode::setNodeValue(const QString& value)
1801{
1802 if (impl)
1803 IMPL->setNodeValue(value);
1804}
1805
1806/*!
1807 \enum QDomNode::NodeType
1808
1809 This enum defines the type of the node:
1810 \value ElementNode
1811 \value AttributeNode
1812 \value TextNode
1813 \value CDATASectionNode
1814 \value EntityReferenceNode
1815 \value EntityNode
1816 \value ProcessingInstructionNode
1817 \value CommentNode
1818 \value DocumentNode
1819 \value DocumentTypeNode
1820 \value DocumentFragmentNode
1821 \value NotationNode
1822 \value BaseNode A QDomNode object, i.e. not a QDomNode subclass.
1823 \value CharacterDataNode
1824*/
1825
1826/*!
1827 Returns the type of the node.
1828
1829 \sa toAttr(), toCDATASection(), toDocumentFragment(),
1830 toDocument(), toDocumentType(), toElement(), toEntityReference(),
1831 toText(), toEntity(), toNotation(), toProcessingInstruction(),
1832 toCharacterData(), toComment()
1833*/
1834QDomNode::NodeType QDomNode::nodeType() const
1835{
1836 if (!impl)
1837 return QDomNode::BaseNode;
1838 return IMPL->nodeType();
1839}
1840
1841/*!
1842 Returns the parent node. If this node has no parent, a null node
1843 is returned (i.e. a node for which isNull() returns \c true).
1844*/
1845QDomNode QDomNode::parentNode() const
1846{
1847 if (!impl)
1848 return QDomNode();
1849 return QDomNode(IMPL->parent());
1850}
1851
1852/*!
1853 Returns a list of all direct child nodes.
1854
1855 Most often you will call this function on a QDomElement object.
1856
1857 For example, if the XML document looks like this:
1858
1859 \snippet code/src_xml_dom_qdom_snippet.cpp 4
1860
1861 Then the list of child nodes for the "body"-element will contain
1862 the node created by the &lt;h1&gt; tag and the node created by the
1863 &lt;p&gt; tag.
1864
1865 The nodes in the list are not copied; so changing the nodes in the
1866 list will also change the children of this node.
1867
1868 \sa firstChild(), lastChild()
1869*/
1870QDomNodeList QDomNode::childNodes() const
1871{
1872 if (!impl)
1873 return QDomNodeList();
1874 return QDomNodeList(new QDomNodeListPrivate(impl));
1875}
1876
1877/*!
1878 Returns the first child of the node. If there is no child node, a
1879 \l{isNull()}{null node} is returned. Changing the
1880 returned node will also change the node in the document tree.
1881
1882 \sa lastChild(), childNodes()
1883*/
1884QDomNode QDomNode::firstChild() const
1885{
1886 if (!impl)
1887 return QDomNode();
1888 return QDomNode(IMPL->first);
1889}
1890
1891/*!
1892 Returns the last child of the node. If there is no child node, a
1893 \l{isNull()}{null node} is returned. Changing the
1894 returned node will also change the node in the document tree.
1895
1896 \sa firstChild(), childNodes()
1897*/
1898QDomNode QDomNode::lastChild() const
1899{
1900 if (!impl)
1901 return QDomNode();
1902 return QDomNode(IMPL->last);
1903}
1904
1905/*!
1906 Returns the previous sibling in the document tree. Changing the
1907 returned node will also change the node in the document tree.
1908
1909 For example, if you have XML like this:
1910
1911 \snippet code/src_xml_dom_qdom_snippet.cpp 5
1912
1913 and this QDomNode represents the &lt;p&gt; tag, previousSibling()
1914 will return the node representing the &lt;h1&gt; tag.
1915
1916 \sa nextSibling()
1917*/
1918QDomNode QDomNode::previousSibling() const
1919{
1920 if (!impl)
1921 return QDomNode();
1922 return QDomNode(IMPL->prev);
1923}
1924
1925/*!
1926 Returns the next sibling in the document tree. Changing the
1927 returned node will also change the node in the document tree.
1928
1929 If you have XML like this:
1930
1931 \snippet code/src_xml_dom_qdom_snippet.cpp 6
1932
1933 and this QDomNode represents the <p> tag, nextSibling() will
1934 return the node representing the <h2> tag.
1935
1936 \sa previousSibling()
1937*/
1938QDomNode QDomNode::nextSibling() const
1939{
1940 if (!impl)
1941 return QDomNode();
1942 return QDomNode(IMPL->next);
1943}
1944
1945
1946// ###### don't think this is part of the DOM and
1947/*!
1948 Returns a named node map of all attributes. Attributes are only
1949 provided for \l{QDomElement}s.
1950
1951 Changing the attributes in the map will also change the attributes
1952 of this QDomNode.
1953*/
1954QDomNamedNodeMap QDomNode::attributes() const
1955{
1956 if (!impl || !impl->isElement())
1957 return QDomNamedNodeMap();
1958
1959 return QDomNamedNodeMap(static_cast<QDomElementPrivate *>(impl)->attributes());
1960}
1961
1962/*!
1963 Returns the document to which this node belongs.
1964*/
1965QDomDocument QDomNode::ownerDocument() const
1966{
1967 if (!impl)
1968 return QDomDocument();
1969 return QDomDocument(IMPL->ownerDocument());
1970}
1971
1972/*!
1973 Creates a deep (not shallow) copy of the QDomNode.
1974
1975 If \a deep is true, then the cloning is done recursively which
1976 means that all the node's children are deep copied too. If \a deep
1977 is false only the node itself is copied and the copy will have no
1978 child nodes.
1979*/
1980QDomNode QDomNode::cloneNode(bool deep) const
1981{
1982 if (!impl)
1983 return QDomNode();
1984 return QDomNode(IMPL->cloneNode(deep));
1985}
1986
1987/*!
1988 Calling normalize() on an element converts all its children into a
1989 standard form. This means that adjacent QDomText objects will be
1990 merged into a single text object (QDomCDATASection nodes are not
1991 merged).
1992*/
1993void QDomNode::normalize()
1994{
1995 if (!impl)
1996 return;
1997 IMPL->normalize();
1998}
1999
2000/*!
2001 Returns \c true if the DOM implementation implements the feature \a
2002 feature and this feature is supported by this node in the version
2003 \a version; otherwise returns \c false.
2004
2005 \sa QDomImplementation::hasFeature()
2006*/
2007bool QDomNode::isSupported(const QString& feature, const QString& version) const
2008{
2009 QDomImplementation i;
2010 return i.hasFeature(feature, version);
2011}
2012
2013/*!
2014 Returns the namespace URI of this node or an empty string if the
2015 node has no namespace URI.
2016
2017 Only nodes of type \l{QDomNode::NodeType}{ElementNode} or
2018 \l{QDomNode::NodeType}{AttributeNode} can have
2019 namespaces. A namespace URI must be specified at creation time and
2020 cannot be changed later.
2021
2022 \sa prefix(), localName(), QDomDocument::createElementNS(),
2023 QDomDocument::createAttributeNS()
2024*/
2025QString QDomNode::namespaceURI() const
2026{
2027 if (!impl)
2028 return QString();
2029 return IMPL->namespaceURI;
2030}
2031
2032/*!
2033 Returns the namespace prefix of the node or an empty string if the
2034 node has no namespace prefix.
2035
2036 Only nodes of type \l{QDomNode::NodeType}{ElementNode} or
2037 \l{QDomNode::NodeType}{AttributeNode} can have
2038 namespaces. A namespace prefix must be specified at creation time.
2039 If a node was created with a namespace prefix, you can change it
2040 later with setPrefix().
2041
2042 If you create an element or attribute with
2043 QDomDocument::createElement() or QDomDocument::createAttribute(),
2044 the prefix will be an empty string. If you use
2045 QDomDocument::createElementNS() or
2046 QDomDocument::createAttributeNS() instead, the prefix will not be
2047 an empty string; but it might be an empty string if the name does
2048 not have a prefix.
2049
2050 \sa setPrefix(), localName(), namespaceURI(),
2051 QDomDocument::createElementNS(),
2052 QDomDocument::createAttributeNS()
2053*/
2054QString QDomNode::prefix() const
2055{
2056 if (!impl)
2057 return QString();
2058 return IMPL->prefix;
2059}
2060
2061/*!
2062 If the node has a namespace prefix, this function changes the
2063 namespace prefix of the node to \a pre. Otherwise this function
2064 does nothing.
2065
2066 Only nodes of type \l{QDomNode::NodeType}{ElementNode} or
2067 \l{QDomNode::NodeType}{AttributeNode} can have
2068 namespaces. A namespace prefix must have be specified at creation
2069 time; it is not possible to add a namespace prefix afterwards.
2070
2071 \sa prefix(), localName(), namespaceURI(),
2072 QDomDocument::createElementNS(),
2073 QDomDocument::createAttributeNS()
2074*/
2075void QDomNode::setPrefix(const QString& pre)
2076{
2077 if (!impl || IMPL->prefix.isNull())
2078 return;
2079 if (isAttr() || isElement())
2080 IMPL->prefix = pre;
2081}
2082
2083/*!
2084 If the node uses namespaces, this function returns the local name
2085 of the node; otherwise it returns an empty string.
2086
2087 Only nodes of type \l{QDomNode::NodeType}{ElementNode} or
2088 \l{QDomNode::NodeType}{AttributeNode} can have
2089 namespaces. A namespace must have been specified at creation time;
2090 it is not possible to add a namespace afterwards.
2091
2092 \sa prefix(), namespaceURI(), QDomDocument::createElementNS(),
2093 QDomDocument::createAttributeNS()
2094*/
2095QString QDomNode::localName() const
2096{
2097 if (!impl || IMPL->createdWithDom1Interface)
2098 return QString();
2099 return IMPL->name;
2100}
2101
2102/*!
2103 Returns \c true if the node has attributes; otherwise returns \c false.
2104
2105 \sa attributes()
2106*/
2107bool QDomNode::hasAttributes() const
2108{
2109 if (!impl || !impl->isElement())
2110 return false;
2111 return static_cast<QDomElementPrivate *>(impl)->hasAttributes();
2112}
2113
2114/*!
2115 Inserts the node \a newChild before the child node \a refChild.
2116 \a refChild must be a direct child of this node. If \a refChild is
2117 \l{isNull()}{null} then \a newChild is inserted as the
2118 node's first child.
2119
2120 If \a newChild is the child of another node, it is reparented to
2121 this node. If \a newChild is a child of this node, then its
2122 position in the list of children is changed.
2123
2124 If \a newChild is a QDomDocumentFragment, then the children of the
2125 fragment are removed from the fragment and inserted before \a
2126 refChild.
2127
2128 Returns a new reference to \a newChild on success or a \l{isNull()}{null node} on failure.
2129
2130 The DOM specification disallow inserting attribute nodes, but due
2131 to historical reasons QDom accept them nevertheless.
2132
2133 \sa insertAfter(), replaceChild(), removeChild(), appendChild()
2134*/
2135QDomNode QDomNode::insertBefore(const QDomNode& newChild, const QDomNode& refChild)
2136{
2137 if (!impl)
2138 return QDomNode();
2139 return QDomNode(IMPL->insertBefore(newChild: newChild.impl, refChild: refChild.impl));
2140}
2141
2142/*!
2143 Inserts the node \a newChild after the child node \a refChild. \a
2144 refChild must be a direct child of this node. If \a refChild is
2145 \l{isNull()}{null} then \a newChild is appended as this
2146 node's last child.
2147
2148 If \a newChild is the child of another node, it is reparented to
2149 this node. If \a newChild is a child of this node, then its
2150 position in the list of children is changed.
2151
2152 If \a newChild is a QDomDocumentFragment, then the children of the
2153 fragment are removed from the fragment and inserted after \a
2154 refChild.
2155
2156 Returns a new reference to \a newChild on success or a \l{isNull()}{null node} on failure.
2157
2158 The DOM specification disallow inserting attribute nodes, but due
2159 to historical reasons QDom accept them nevertheless.
2160
2161 \sa insertBefore(), replaceChild(), removeChild(), appendChild()
2162*/
2163QDomNode QDomNode::insertAfter(const QDomNode& newChild, const QDomNode& refChild)
2164{
2165 if (!impl)
2166 return QDomNode();
2167 return QDomNode(IMPL->insertAfter(newChild: newChild.impl, refChild: refChild.impl));
2168}
2169
2170/*!
2171 Replaces \a oldChild with \a newChild. \a oldChild must be a
2172 direct child of this node.
2173
2174 If \a newChild is the child of another node, it is reparented to
2175 this node. If \a newChild is a child of this node, then its
2176 position in the list of children is changed.
2177
2178 If \a newChild is a QDomDocumentFragment, then \a oldChild is
2179 replaced by all of the children of the fragment.
2180
2181 Returns a new reference to \a oldChild on success or a \l{isNull()}{null node} on failure.
2182
2183 \sa insertBefore(), insertAfter(), removeChild(), appendChild()
2184*/
2185QDomNode QDomNode::replaceChild(const QDomNode& newChild, const QDomNode& oldChild)
2186{
2187 if (!impl || !newChild.impl || !oldChild.impl)
2188 return QDomNode();
2189 return QDomNode(IMPL->replaceChild(newChild: newChild.impl, oldChild: oldChild.impl));
2190}
2191
2192/*!
2193 Removes \a oldChild from the list of children. \a oldChild must be
2194 a direct child of this node.
2195
2196 Returns a new reference to \a oldChild on success or a \l{isNull()}{null node} on failure.
2197
2198 \sa insertBefore(), insertAfter(), replaceChild(), appendChild()
2199*/
2200QDomNode QDomNode::removeChild(const QDomNode& oldChild)
2201{
2202 if (!impl)
2203 return QDomNode();
2204
2205 if (oldChild.isNull())
2206 return QDomNode();
2207
2208 return QDomNode(IMPL->removeChild(oldChild: oldChild.impl));
2209}
2210
2211/*!
2212 Appends \a newChild as the node's last child.
2213
2214 If \a newChild is the child of another node, it is reparented to
2215 this node. If \a newChild is a child of this node, then its
2216 position in the list of children is changed.
2217
2218 If \a newChild is a QDomDocumentFragment, then the children of the
2219 fragment are removed from the fragment and appended.
2220
2221 If \a newChild is a QDomElement and this node is a QDomDocument that
2222 already has an element node as a child, \a newChild is not added as
2223 a child and a null node is returned.
2224
2225 Returns a new reference to \a newChild on success or a \l{isNull()}{null node} on failure.
2226
2227 Calling this function on a null node(created, for example, with
2228 the default constructor) does nothing and returns a \l{isNull()}{null node}.
2229
2230 The DOM specification disallow inserting attribute nodes, but for
2231 historical reasons, QDom accepts them anyway.
2232
2233 \sa insertBefore(), insertAfter(), replaceChild(), removeChild()
2234*/
2235QDomNode QDomNode::appendChild(const QDomNode& newChild)
2236{
2237 if (!impl) {
2238 qWarning(msg: "Calling appendChild() on a null node does nothing.");
2239 return QDomNode();
2240 }
2241 return QDomNode(IMPL->appendChild(newChild: newChild.impl));
2242}
2243
2244/*!
2245 Returns \c true if the node has one or more children; otherwise
2246 returns \c false.
2247*/
2248bool QDomNode::hasChildNodes() const
2249{
2250 if (!impl)
2251 return false;
2252 return IMPL->first != nullptr;
2253}
2254
2255/*!
2256 Returns \c true if this node is null (i.e. if it has no type or
2257 contents); otherwise returns \c false.
2258*/
2259bool QDomNode::isNull() const
2260{
2261 return (impl == nullptr);
2262}
2263
2264/*!
2265 Converts the node into a null node; if it was not a null node
2266 before, its type and contents are deleted.
2267
2268 \sa isNull()
2269*/
2270void QDomNode::clear()
2271{
2272 if (impl && !impl->ref.deref())
2273 delete impl;
2274 impl = nullptr;
2275}
2276
2277/*!
2278 Returns the first direct child node for which nodeName() equals \a
2279 name.
2280
2281 If no such direct child exists, a \l{isNull()}{null node}
2282 is returned.
2283
2284 \sa nodeName()
2285*/
2286QDomNode QDomNode::namedItem(const QString& name) const
2287{
2288 if (!impl)
2289 return QDomNode();
2290 return QDomNode(impl->namedItem(n: name));
2291}
2292
2293/*!
2294 Writes the XML representation of the node and all its children to
2295 the stream \a stream. This function uses \a indent as the amount of
2296 space to indent the node.
2297
2298 If the document contains invalid XML characters or characters that cannot be
2299 encoded in the given encoding, the result and behavior is undefined.
2300
2301 If \a encodingPolicy is QDomNode::EncodingFromDocument and this node is a
2302 document node, the encoding of text stream \a stream's encoding is set by
2303 treating a processing instruction by name "xml" as an XML declaration, if
2304 one exists, and otherwise defaults to UTF-8. XML declarations are not
2305 processing instructions, but this behavior exists for historical
2306 reasons. If this node is not a document node, the text stream's encoding
2307 is used.
2308
2309 If \a encodingPolicy is EncodingFromTextStream and this node is a document node, this
2310 function behaves as save(QTextStream &str, int indent) with the exception that the encoding
2311 specified in the text stream \a stream is used.
2312
2313 If the document contains invalid XML characters or characters that cannot be
2314 encoded in the given encoding, the result and behavior is undefined.
2315
2316 \since 4.2
2317 */
2318void QDomNode::save(QTextStream& stream, int indent, EncodingPolicy encodingPolicy) const
2319{
2320 if (!impl)
2321 return;
2322
2323 if (isDocument())
2324 static_cast<const QDomDocumentPrivate *>(impl)->saveDocument(stream, indent, encUsed: encodingPolicy);
2325 else
2326 IMPL->saveSubTree(IMPL, s&: stream, depth: 1, indent);
2327}
2328
2329/*!
2330 \relates QDomNode
2331
2332 Writes the XML representation of the node \a node and all its
2333 children to the stream \a str.
2334*/
2335QTextStream& operator<<(QTextStream& str, const QDomNode& node)
2336{
2337 node.save(stream&: str, indent: 1);
2338
2339 return str;
2340}
2341
2342/*!
2343 Returns \c true if the node is an attribute; otherwise returns \c false.
2344
2345 If this function returns \c true, it does not imply that this object
2346 is a QDomAttribute; you can get the QDomAttribute with
2347 toAttribute().
2348
2349 \sa toAttr()
2350*/
2351bool QDomNode::isAttr() const
2352{
2353 if (impl)
2354 return impl->isAttr();
2355 return false;
2356}
2357
2358/*!
2359 Returns \c true if the node is a CDATA section; otherwise returns
2360 false.
2361
2362 If this function returns \c true, it does not imply that this object
2363 is a QDomCDATASection; you can get the QDomCDATASection with
2364 toCDATASection().
2365
2366 \sa toCDATASection()
2367*/
2368bool QDomNode::isCDATASection() const
2369{
2370 if (impl)
2371 return impl->isCDATASection();
2372 return false;
2373}
2374
2375/*!
2376 Returns \c true if the node is a document fragment; otherwise returns
2377 false.
2378
2379 If this function returns \c true, it does not imply that this object
2380 is a QDomDocumentFragment; you can get the QDomDocumentFragment
2381 with toDocumentFragment().
2382
2383 \sa toDocumentFragment()
2384*/
2385bool QDomNode::isDocumentFragment() const
2386{
2387 if (impl)
2388 return impl->isDocumentFragment();
2389 return false;
2390}
2391
2392/*!
2393 Returns \c true if the node is a document; otherwise returns \c false.
2394
2395 If this function returns \c true, it does not imply that this object
2396 is a QDomDocument; you can get the QDomDocument with toDocument().
2397
2398 \sa toDocument()
2399*/
2400bool QDomNode::isDocument() const
2401{
2402 if (impl)
2403 return impl->isDocument();
2404 return false;
2405}
2406
2407/*!
2408 Returns \c true if the node is a document type; otherwise returns
2409 false.
2410
2411 If this function returns \c true, it does not imply that this object
2412 is a QDomDocumentType; you can get the QDomDocumentType with
2413 toDocumentType().
2414
2415 \sa toDocumentType()
2416*/
2417bool QDomNode::isDocumentType() const
2418{
2419 if (impl)
2420 return impl->isDocumentType();
2421 return false;
2422}
2423
2424/*!
2425 Returns \c true if the node is an element; otherwise returns \c false.
2426
2427 If this function returns \c true, it does not imply that this object
2428 is a QDomElement; you can get the QDomElement with toElement().
2429
2430 \sa toElement()
2431*/
2432bool QDomNode::isElement() const
2433{
2434 if (impl)
2435 return impl->isElement();
2436 return false;
2437}
2438
2439/*!
2440 Returns \c true if the node is an entity reference; otherwise returns
2441 false.
2442
2443 If this function returns \c true, it does not imply that this object
2444 is a QDomEntityReference; you can get the QDomEntityReference with
2445 toEntityReference().
2446
2447 \sa toEntityReference()
2448*/
2449bool QDomNode::isEntityReference() const
2450{
2451 if (impl)
2452 return impl->isEntityReference();
2453 return false;
2454}
2455
2456/*!
2457 Returns \c true if the node is a text node; otherwise returns \c false.
2458
2459 If this function returns \c true, it does not imply that this object
2460 is a QDomText; you can get the QDomText with toText().
2461
2462 \sa toText()
2463*/
2464bool QDomNode::isText() const
2465{
2466 if (impl)
2467 return impl->isText();
2468 return false;
2469}
2470
2471/*!
2472 Returns \c true if the node is an entity; otherwise returns \c false.
2473
2474 If this function returns \c true, it does not imply that this object
2475 is a QDomEntity; you can get the QDomEntity with toEntity().
2476
2477 \sa toEntity()
2478*/
2479bool QDomNode::isEntity() const
2480{
2481 if (impl)
2482 return impl->isEntity();
2483 return false;
2484}
2485
2486/*!
2487 Returns \c true if the node is a notation; otherwise returns \c false.
2488
2489 If this function returns \c true, it does not imply that this object
2490 is a QDomNotation; you can get the QDomNotation with toNotation().
2491
2492 \sa toNotation()
2493*/
2494bool QDomNode::isNotation() const
2495{
2496 if (impl)
2497 return impl->isNotation();
2498 return false;
2499}
2500
2501/*!
2502 Returns \c true if the node is a processing instruction; otherwise
2503 returns \c false.
2504
2505 If this function returns \c true, it does not imply that this object
2506 is a QDomProcessingInstruction; you can get the
2507 QProcessingInstruction with toProcessingInstruction().
2508
2509 \sa toProcessingInstruction()
2510*/
2511bool QDomNode::isProcessingInstruction() const
2512{
2513 if (impl)
2514 return impl->isProcessingInstruction();
2515 return false;
2516}
2517
2518/*!
2519 Returns \c true if the node is a character data node; otherwise
2520 returns \c false.
2521
2522 If this function returns \c true, it does not imply that this object
2523 is a QDomCharacterData; you can get the QDomCharacterData with
2524 toCharacterData().
2525
2526 \sa toCharacterData()
2527*/
2528bool QDomNode::isCharacterData() const
2529{
2530 if (impl)
2531 return impl->isCharacterData();
2532 return false;
2533}
2534
2535/*!
2536 Returns \c true if the node is a comment; otherwise returns \c false.
2537
2538 If this function returns \c true, it does not imply that this object
2539 is a QDomComment; you can get the QDomComment with toComment().
2540
2541 \sa toComment()
2542*/
2543bool QDomNode::isComment() const
2544{
2545 if (impl)
2546 return impl->isComment();
2547 return false;
2548}
2549
2550#undef IMPL
2551
2552/*!
2553 Returns the first child element with tag name \a tagName and namespace URI
2554 \a namespaceURI. If \a tagName is empty, returns the first child element
2555 with \a namespaceURI, and if \a namespaceURI is empty, returns the first
2556 child element with \a tagName. If the both parameters are empty, returns
2557 the first child element. Returns a null element if no such child exists.
2558
2559 \sa lastChildElement(), previousSiblingElement(), nextSiblingElement()
2560*/
2561
2562QDomElement QDomNode::firstChildElement(const QString &tagName, const QString &namespaceURI) const
2563{
2564 for (QDomNode child = firstChild(); !child.isNull(); child = child.nextSibling()) {
2565 if (child.isElement() && (namespaceURI.isEmpty() || child.namespaceURI() == namespaceURI)) {
2566 QDomElement elt = child.toElement();
2567 if (tagName.isEmpty() || elt.tagName() == tagName)
2568 return elt;
2569 }
2570 }
2571 return QDomElement();
2572}
2573
2574/*!
2575 Returns the last child element with tag name \a tagName and namespace URI
2576 \a namespaceURI. If \a tagName is empty, returns the last child element
2577 with \a namespaceURI, and if \a namespaceURI is empty, returns the last
2578 child element with \a tagName. If the both parameters are empty, returns
2579 the last child element. Returns a null element if no such child exists.
2580
2581 \sa firstChildElement(), previousSiblingElement(), nextSiblingElement()
2582*/
2583
2584QDomElement QDomNode::lastChildElement(const QString &tagName, const QString &namespaceURI) const
2585{
2586 for (QDomNode child = lastChild(); !child.isNull(); child = child.previousSibling()) {
2587 if (child.isElement() && (namespaceURI.isEmpty() || child.namespaceURI() == namespaceURI)) {
2588 QDomElement elt = child.toElement();
2589 if (tagName.isEmpty() || elt.tagName() == tagName)
2590 return elt;
2591 }
2592 }
2593 return QDomElement();
2594}
2595
2596/*!
2597 Returns the next sibling element with tag name \a tagName and namespace URI
2598 \a namespaceURI. If \a tagName is empty, returns the next sibling element
2599 with \a namespaceURI, and if \a namespaceURI is empty, returns the next
2600 sibling child element with \a tagName. If the both parameters are empty,
2601 returns the next sibling element. Returns a null element if no such sibling
2602 exists.
2603
2604 \sa firstChildElement(), previousSiblingElement(), lastChildElement()
2605*/
2606
2607QDomElement QDomNode::nextSiblingElement(const QString &tagName, const QString &namespaceURI) const
2608{
2609 for (QDomNode sib = nextSibling(); !sib.isNull(); sib = sib.nextSibling()) {
2610 if (sib.isElement() && (namespaceURI.isEmpty() || sib.namespaceURI() == namespaceURI)) {
2611 QDomElement elt = sib.toElement();
2612 if (tagName.isEmpty() || elt.tagName() == tagName)
2613 return elt;
2614 }
2615 }
2616 return QDomElement();
2617}
2618
2619/*!
2620 Returns the previous sibling element with tag name \a tagName and namespace
2621 URI \a namespaceURI. If \a tagName is empty, returns the previous sibling
2622 element with \a namespaceURI, and if \a namespaceURI is empty, returns the
2623 previous sibling element with \a tagName. If the both parameters are empty,
2624 returns the previous sibling element. Returns a null element if no such
2625 sibling exists.
2626
2627 \sa firstChildElement(), nextSiblingElement(), lastChildElement()
2628*/
2629
2630QDomElement QDomNode::previousSiblingElement(const QString &tagName, const QString &namespaceURI) const
2631{
2632 for (QDomNode sib = previousSibling(); !sib.isNull(); sib = sib.previousSibling()) {
2633 if (sib.isElement() && (namespaceURI.isEmpty() || sib.namespaceURI() == namespaceURI)) {
2634 QDomElement elt = sib.toElement();
2635 if (tagName.isEmpty() || elt.tagName() == tagName)
2636 return elt;
2637 }
2638 }
2639 return QDomElement();
2640}
2641
2642/*!
2643 \since 4.1
2644
2645 For nodes created by QDomDocument::setContent(), this function
2646 returns the line number in the XML document where the node was parsed.
2647 Otherwise, -1 is returned.
2648
2649 \sa columnNumber(), QDomDocument::setContent()
2650*/
2651int QDomNode::lineNumber() const
2652{
2653 return impl ? impl->lineNumber : -1;
2654}
2655
2656/*!
2657 \since 4.1
2658
2659 For nodes created by QDomDocument::setContent(), this function
2660 returns the column number in the XML document where the node was parsed.
2661 Otherwise, -1 is returned.
2662
2663 \sa lineNumber(), QDomDocument::setContent()
2664*/
2665int QDomNode::columnNumber() const
2666{
2667 return impl ? impl->columnNumber : -1;
2668}
2669
2670
2671/**************************************************************
2672 *
2673 * QDomNamedNodeMapPrivate
2674 *
2675 **************************************************************/
2676
2677QDomNamedNodeMapPrivate::QDomNamedNodeMapPrivate(QDomNodePrivate *pimpl)
2678 : ref(1)
2679 , parent(pimpl)
2680 , readonly(false)
2681 , appendToParent(false)
2682{
2683}
2684
2685QDomNamedNodeMapPrivate::~QDomNamedNodeMapPrivate()
2686{
2687 clearMap();
2688}
2689
2690QDomNamedNodeMapPrivate* QDomNamedNodeMapPrivate::clone(QDomNodePrivate *pimpl)
2691{
2692 std::unique_ptr<QDomNamedNodeMapPrivate> m(new QDomNamedNodeMapPrivate(pimpl));
2693 m->readonly = readonly;
2694 m->appendToParent = appendToParent;
2695
2696 auto it = map.constBegin();
2697 for (; it != map.constEnd(); ++it) {
2698 QDomNodePrivate *new_node = it.value()->cloneNode();
2699 new_node->setParent(pimpl);
2700 m->setNamedItem(new_node);
2701 }
2702
2703 // we are no longer interested in ownership
2704 m->ref.deref();
2705 return m.release();
2706}
2707
2708void QDomNamedNodeMapPrivate::clearMap()
2709{
2710 // Dereference all of our children if we took references
2711 if (!appendToParent) {
2712 auto it = map.constBegin();
2713 for (; it != map.constEnd(); ++it)
2714 if (!it.value()->ref.deref())
2715 delete it.value();
2716 }
2717 map.clear();
2718}
2719
2720QDomNodePrivate* QDomNamedNodeMapPrivate::namedItem(const QString& name) const
2721{
2722 auto it = map.find(key: name);
2723 return it == map.end() ? nullptr : it.value();
2724}
2725
2726QDomNodePrivate* QDomNamedNodeMapPrivate::namedItemNS(const QString& nsURI, const QString& localName) const
2727{
2728 auto it = map.constBegin();
2729 QDomNodePrivate *n;
2730 for (; it != map.constEnd(); ++it) {
2731 n = it.value();
2732 if (!n->prefix.isNull()) {
2733 // node has a namespace
2734 if (n->namespaceURI == nsURI && n->name == localName)
2735 return n;
2736 }
2737 }
2738 return nullptr;
2739}
2740
2741QDomNodePrivate* QDomNamedNodeMapPrivate::setNamedItem(QDomNodePrivate* arg)
2742{
2743 if (readonly || !arg)
2744 return nullptr;
2745
2746 if (appendToParent)
2747 return parent->appendChild(newChild: arg);
2748
2749 QDomNodePrivate *n = map.value(key: arg->nodeName());
2750 // We take a reference
2751 arg->ref.ref();
2752 map.insert(key: arg->nodeName(), value: arg);
2753 return n;
2754}
2755
2756QDomNodePrivate* QDomNamedNodeMapPrivate::setNamedItemNS(QDomNodePrivate* arg)
2757{
2758 if (readonly || !arg)
2759 return nullptr;
2760
2761 if (appendToParent)
2762 return parent->appendChild(newChild: arg);
2763
2764 if (!arg->prefix.isNull()) {
2765 // node has a namespace
2766 QDomNodePrivate *n = namedItemNS(nsURI: arg->namespaceURI, localName: arg->name);
2767 // We take a reference
2768 arg->ref.ref();
2769 map.insert(key: arg->nodeName(), value: arg);
2770 return n;
2771 } else {
2772 // ### check the following code if it is ok
2773 return setNamedItem(arg);
2774 }
2775}
2776
2777QDomNodePrivate* QDomNamedNodeMapPrivate::removeNamedItem(const QString& name)
2778{
2779 if (readonly)
2780 return nullptr;
2781
2782 QDomNodePrivate* p = namedItem(name);
2783 if (p == nullptr)
2784 return nullptr;
2785 if (appendToParent)
2786 return parent->removeChild(oldChild: p);
2787
2788 map.remove(key: p->nodeName());
2789 // We took a reference, so we have to free one here
2790 p->ref.deref();
2791 return p;
2792}
2793
2794QDomNodePrivate* QDomNamedNodeMapPrivate::item(int index) const
2795{
2796 if (index >= length() || index < 0)
2797 return nullptr;
2798 return std::next(x: map.begin(), n: index).value();
2799}
2800
2801int QDomNamedNodeMapPrivate::length() const
2802{
2803 return map.size();
2804}
2805
2806bool QDomNamedNodeMapPrivate::contains(const QString& name) const
2807{
2808 return map.contains(key: name);
2809}
2810
2811bool QDomNamedNodeMapPrivate::containsNS(const QString& nsURI, const QString & localName) const
2812{
2813 return namedItemNS(nsURI, localName) != nullptr;
2814}
2815
2816/**************************************************************
2817 *
2818 * QDomNamedNodeMap
2819 *
2820 **************************************************************/
2821
2822#define IMPL static_cast<QDomNamedNodeMapPrivate *>(impl)
2823
2824/*!
2825 \class QDomNamedNodeMap
2826 \reentrant
2827 \brief The QDomNamedNodeMap class contains a collection of nodes
2828 that can be accessed by name.
2829
2830 \inmodule QtXml
2831 \ingroup xml-tools
2832
2833 Note that QDomNamedNodeMap does not inherit from QDomNodeList.
2834 QDomNamedNodeMaps do not provide any specific node ordering.
2835 Although nodes in a QDomNamedNodeMap may be accessed by an ordinal
2836 index, this is simply to allow a convenient enumeration of the
2837 contents of a QDomNamedNodeMap, and does not imply that the DOM
2838 specifies an ordering of the nodes.
2839
2840 The QDomNamedNodeMap is used in three places:
2841 \list 1
2842 \li QDomDocumentType::entities() returns a map of all entities
2843 described in the DTD.
2844 \li QDomDocumentType::notations() returns a map of all notations
2845 described in the DTD.
2846 \li QDomNode::attributes() returns a map of all attributes of an
2847 element.
2848 \endlist
2849
2850 Items in the map are identified by the name which QDomNode::name()
2851 returns. Nodes are retrieved using namedItem(), namedItemNS() or
2852 item(). New nodes are inserted with setNamedItem() or
2853 setNamedItemNS() and removed with removeNamedItem() or
2854 removeNamedItemNS(). Use contains() to see if an item with the
2855 given name is in the named node map. The number of items is
2856 returned by length().
2857
2858 Terminology: in this class we use "item" and "node"
2859 interchangeably.
2860*/
2861
2862/*!
2863 Constructs an empty named node map.
2864*/
2865QDomNamedNodeMap::QDomNamedNodeMap()
2866 : impl(nullptr)
2867{
2868}
2869
2870/*!
2871 Constructs a copy of \a namedNodeMap.
2872*/
2873QDomNamedNodeMap::QDomNamedNodeMap(const QDomNamedNodeMap &namedNodeMap)
2874 : impl(namedNodeMap.impl)
2875{
2876 if (impl)
2877 impl->ref.ref();
2878}
2879
2880QDomNamedNodeMap::QDomNamedNodeMap(QDomNamedNodeMapPrivate *pimpl)
2881 : impl(pimpl)
2882{
2883 if (impl)
2884 impl->ref.ref();
2885}
2886
2887/*!
2888 Assigns \a other to this named node map.
2889*/
2890QDomNamedNodeMap& QDomNamedNodeMap::operator=(const QDomNamedNodeMap &other)
2891{
2892 if (other.impl)
2893 other.impl->ref.ref();
2894 if (impl && !impl->ref.deref())
2895 delete impl;
2896 impl = other.impl;
2897 return *this;
2898}
2899
2900/*!
2901 Returns \c true if \a other and this named node map are equal; otherwise
2902 returns \c false.
2903*/
2904bool QDomNamedNodeMap::operator==(const QDomNamedNodeMap &other) const
2905{
2906 return impl == other.impl;
2907}
2908
2909/*!
2910 Returns \c true if \a other and this named node map are not equal;
2911 otherwise returns \c false.
2912*/
2913bool QDomNamedNodeMap::operator!=(const QDomNamedNodeMap &other) const
2914{
2915 return !operator==(other);
2916}
2917
2918/*!
2919 Destroys the object and frees its resources.
2920*/
2921QDomNamedNodeMap::~QDomNamedNodeMap()
2922{
2923 if (impl && !impl->ref.deref())
2924 delete impl;
2925}
2926
2927/*!
2928 Returns the node called \a name.
2929
2930 If the named node map does not contain such a node, a
2931 \l{QDomNode::isNull()}{null node} is returned. A node's name is
2932 the name returned by QDomNode::nodeName().
2933
2934 \sa setNamedItem(), namedItemNS()
2935*/
2936QDomNode QDomNamedNodeMap::namedItem(const QString& name) const
2937{
2938 if (!impl)
2939 return QDomNode();
2940 return QDomNode(IMPL->namedItem(name));
2941}
2942
2943/*!
2944 Inserts the node \a newNode into the named node map. The name used
2945 by the map is the node name of \a newNode as returned by
2946 QDomNode::nodeName().
2947
2948 If the new node replaces an existing node, i.e. the map contains a
2949 node with the same name, the replaced node is returned.
2950
2951 \sa namedItem(), removeNamedItem(), setNamedItemNS()
2952*/
2953QDomNode QDomNamedNodeMap::setNamedItem(const QDomNode& newNode)
2954{
2955 if (!impl)
2956 return QDomNode();
2957 return QDomNode(IMPL->setNamedItem(static_cast<QDomNodePrivate *>(newNode.impl)));
2958}
2959
2960/*!
2961 Removes the node called \a name from the map.
2962
2963 The function returns the removed node or a
2964 \l{QDomNode::isNull()}{null node} if the map did not contain a
2965 node called \a name.
2966
2967 \sa setNamedItem(), namedItem(), removeNamedItemNS()
2968*/
2969QDomNode QDomNamedNodeMap::removeNamedItem(const QString& name)
2970{
2971 if (!impl)
2972 return QDomNode();
2973 return QDomNode(IMPL->removeNamedItem(name));
2974}
2975
2976/*!
2977 Retrieves the node at position \a index.
2978
2979 This can be used to iterate over the map. Note that the nodes in
2980 the map are ordered arbitrarily.
2981
2982 \sa length()
2983*/
2984QDomNode QDomNamedNodeMap::item(int index) const
2985{
2986 if (!impl)
2987 return QDomNode();
2988 return QDomNode(IMPL->item(index));
2989}
2990
2991/*!
2992 Returns the node associated with the local name \a localName and
2993 the namespace URI \a nsURI.
2994
2995 If the map does not contain such a node,
2996 a \l{QDomNode::isNull()}{null node} is returned.
2997
2998 \sa setNamedItemNS(), namedItem()
2999*/
3000QDomNode QDomNamedNodeMap::namedItemNS(const QString& nsURI, const QString& localName) const
3001{
3002 if (!impl)
3003 return QDomNode();
3004 return QDomNode(IMPL->namedItemNS(nsURI, localName));
3005}
3006
3007/*!
3008 Inserts the node \a newNode in the map. If a node with the same
3009 namespace URI and the same local name already exists in the map,
3010 it is replaced by \a newNode. If the new node replaces an existing
3011 node, the replaced node is returned.
3012
3013 \sa namedItemNS(), removeNamedItemNS(), setNamedItem()
3014*/
3015QDomNode QDomNamedNodeMap::setNamedItemNS(const QDomNode& newNode)
3016{
3017 if (!impl)
3018 return QDomNode();
3019 return QDomNode(IMPL->setNamedItemNS(static_cast<QDomNodePrivate *>(newNode.impl)));
3020}
3021
3022/*!
3023 Removes the node with the local name \a localName and the
3024 namespace URI \a nsURI from the map.
3025
3026 The function returns the removed node or a
3027 \l{QDomNode::isNull()}{null node} if the map did not contain a
3028 node with the local name \a localName and the namespace URI \a
3029 nsURI.
3030
3031 \sa setNamedItemNS(), namedItemNS(), removeNamedItem()
3032*/
3033QDomNode QDomNamedNodeMap::removeNamedItemNS(const QString& nsURI, const QString& localName)
3034{
3035 if (!impl)
3036 return QDomNode();
3037 QDomNodePrivate *n = IMPL->namedItemNS(nsURI, localName);
3038 if (!n)
3039 return QDomNode();
3040 return QDomNode(IMPL->removeNamedItem(name: n->name));
3041}
3042
3043/*!
3044 Returns the number of nodes in the map.
3045
3046 \sa item()
3047*/
3048int QDomNamedNodeMap::length() const
3049{
3050 if (!impl)
3051 return 0;
3052 return IMPL->length();
3053}
3054
3055/*!
3056 \fn bool QDomNamedNodeMap::isEmpty() const
3057
3058 Returns \c true if the map is empty; otherwise returns \c false. This function is
3059 provided for Qt API consistency.
3060*/
3061
3062/*!
3063 \fn int QDomNamedNodeMap::count() const
3064
3065 This function is provided for Qt API consistency. It is equivalent to length().
3066*/
3067
3068/*!
3069 \fn int QDomNamedNodeMap::size() const
3070
3071 This function is provided for Qt API consistency. It is equivalent to length().
3072*/
3073
3074/*!
3075 Returns \c true if the map contains a node called \a name; otherwise
3076 returns \c false.
3077
3078 \b{Note:} This function does not take the presence of namespaces into account.
3079 Use namedItemNS() to test whether the map contains a node with a specific namespace
3080 URI and name.
3081*/
3082bool QDomNamedNodeMap::contains(const QString& name) const
3083{
3084 if (!impl)
3085 return false;
3086 return IMPL->contains(name);
3087}
3088
3089#undef IMPL
3090
3091/**************************************************************
3092 *
3093 * QDomDocumentTypePrivate
3094 *
3095 **************************************************************/
3096
3097QDomDocumentTypePrivate::QDomDocumentTypePrivate(QDomDocumentPrivate* doc, QDomNodePrivate* parent)
3098 : QDomNodePrivate(doc, parent)
3099{
3100 init();
3101}
3102
3103QDomDocumentTypePrivate::QDomDocumentTypePrivate(QDomDocumentTypePrivate* n, bool deep)
3104 : QDomNodePrivate(n, deep)
3105{
3106 init();
3107 // Refill the maps with our new children
3108 QDomNodePrivate* p = first;
3109 while (p) {
3110 if (p->isEntity())
3111 // Don't use normal insert function since we would create infinite recursion
3112 entities->map.insert(key: p->nodeName(), value: p);
3113 if (p->isNotation())
3114 // Don't use normal insert function since we would create infinite recursion
3115 notations->map.insert(key: p->nodeName(), value: p);
3116 p = p->next;
3117 }
3118}
3119
3120QDomDocumentTypePrivate::~QDomDocumentTypePrivate()
3121{
3122 if (!entities->ref.deref())
3123 delete entities;
3124 if (!notations->ref.deref())
3125 delete notations;
3126}
3127
3128void QDomDocumentTypePrivate::init()
3129{
3130 entities = new QDomNamedNodeMapPrivate(this);
3131 QT_TRY {
3132 notations = new QDomNamedNodeMapPrivate(this);
3133 publicId.clear();
3134 systemId.clear();
3135 internalSubset.clear();
3136
3137 entities->setAppendToParent(true);
3138 notations->setAppendToParent(true);
3139 } QT_CATCH(...) {
3140 delete entities;
3141 QT_RETHROW;
3142 }
3143}
3144
3145QDomNodePrivate* QDomDocumentTypePrivate::cloneNode(bool deep)
3146{
3147 QDomNodePrivate* p = new QDomDocumentTypePrivate(this, deep);
3148 // We are not interested in this node
3149 p->ref.deref();
3150 return p;
3151}
3152
3153QDomNodePrivate* QDomDocumentTypePrivate::insertBefore(QDomNodePrivate* newChild, QDomNodePrivate* refChild)
3154{
3155 // Call the original implementation
3156 QDomNodePrivate* p = QDomNodePrivate::insertBefore(newChild, refChild);
3157 // Update the maps
3158 if (p && p->isEntity())
3159 entities->map.insert(key: p->nodeName(), value: p);
3160 else if (p && p->isNotation())
3161 notations->map.insert(key: p->nodeName(), value: p);
3162
3163 return p;
3164}
3165
3166QDomNodePrivate* QDomDocumentTypePrivate::insertAfter(QDomNodePrivate* newChild, QDomNodePrivate* refChild)
3167{
3168 // Call the original implementation
3169 QDomNodePrivate* p = QDomNodePrivate::insertAfter(newChild, refChild);
3170 // Update the maps
3171 if (p && p->isEntity())
3172 entities->map.insert(key: p->nodeName(), value: p);
3173 else if (p && p->isNotation())
3174 notations->map.insert(key: p->nodeName(), value: p);
3175
3176 return p;
3177}
3178
3179QDomNodePrivate* QDomDocumentTypePrivate::replaceChild(QDomNodePrivate* newChild, QDomNodePrivate* oldChild)
3180{
3181 // Call the original implementation
3182 QDomNodePrivate* p = QDomNodePrivate::replaceChild(newChild, oldChild);
3183 // Update the maps
3184 if (p) {
3185 if (oldChild && oldChild->isEntity())
3186 entities->map.remove(key: oldChild->nodeName());
3187 else if (oldChild && oldChild->isNotation())
3188 notations->map.remove(key: oldChild->nodeName());
3189
3190 if (p->isEntity())
3191 entities->map.insert(key: p->nodeName(), value: p);
3192 else if (p->isNotation())
3193 notations->map.insert(key: p->nodeName(), value: p);
3194 }
3195
3196 return p;
3197}
3198
3199QDomNodePrivate* QDomDocumentTypePrivate::removeChild(QDomNodePrivate* oldChild)
3200{
3201 // Call the original implementation
3202 QDomNodePrivate* p = QDomNodePrivate::removeChild( oldChild);
3203 // Update the maps
3204 if (p && p->isEntity())
3205 entities->map.remove(key: p->nodeName());
3206 else if (p && p->isNotation())
3207 notations->map.remove(key: p ->nodeName());
3208
3209 return p;
3210}
3211
3212QDomNodePrivate* QDomDocumentTypePrivate::appendChild(QDomNodePrivate* newChild)
3213{
3214 return insertAfter(newChild, refChild: nullptr);
3215}
3216
3217static QString quotedValue(const QString &data)
3218{
3219 QChar quote = data.indexOf(ch: u'\'') == -1 ? u'\'' : u'"';
3220 return quote + data + quote;
3221}
3222
3223void QDomDocumentTypePrivate::save(QTextStream& s, int, int indent) const
3224{
3225 if (name.isEmpty())
3226 return;
3227
3228 s << "<!DOCTYPE " << name;
3229
3230 if (!publicId.isNull()) {
3231 s << " PUBLIC " << quotedValue(data: publicId);
3232 if (!systemId.isNull()) {
3233 s << ' ' << quotedValue(data: systemId);
3234 }
3235 } else if (!systemId.isNull()) {
3236 s << " SYSTEM " << quotedValue(data: systemId);
3237 }
3238
3239 if (entities->length()>0 || notations->length()>0) {
3240 s << " [" << Qt::endl;
3241
3242 auto it2 = notations->map.constBegin();
3243 for (; it2 != notations->map.constEnd(); ++it2)
3244 it2.value()->saveSubTree(n: it2.value(), s, depth: 0, indent);
3245
3246 auto it = entities->map.constBegin();
3247 for (; it != entities->map.constEnd(); ++it)
3248 it.value()->saveSubTree(n: it.value(), s, depth: 0, indent);
3249
3250 s << ']';
3251 }
3252
3253 s << '>' << Qt::endl;
3254}
3255
3256/**************************************************************
3257 *
3258 * QDomDocumentType
3259 *
3260 **************************************************************/
3261
3262#define IMPL static_cast<QDomDocumentTypePrivate *>(impl)
3263
3264/*!
3265 \class QDomDocumentType
3266 \reentrant
3267 \brief The QDomDocumentType class is the representation of the DTD
3268 in the document tree.
3269
3270 \inmodule QtXml
3271 \ingroup xml-tools
3272
3273 The QDomDocumentType class allows read-only access to some of the
3274 data structures in the DTD: it can return a map of all entities()
3275 and notations(). In addition the function name() returns the name
3276 of the document type as specified in the &lt;!DOCTYPE name&gt;
3277 tag. This class also provides the publicId(), systemId() and
3278 internalSubset() functions.
3279
3280 \sa QDomDocument
3281*/
3282
3283/*!
3284 Creates an empty QDomDocumentType object.
3285*/
3286QDomDocumentType::QDomDocumentType() : QDomNode()
3287{
3288}
3289
3290/*!
3291 Constructs a copy of \a documentType.
3292
3293 The data of the copy is shared (shallow copy): modifying one node
3294 will also change the other. If you want to make a deep copy, use
3295 cloneNode().
3296*/
3297QDomDocumentType::QDomDocumentType(const QDomDocumentType &documentType)
3298 : QDomNode(documentType)
3299{
3300}
3301
3302QDomDocumentType::QDomDocumentType(QDomDocumentTypePrivate *pimpl)
3303 : QDomNode(pimpl)
3304{
3305}
3306
3307/*!
3308 Assigns \a other to this document type.
3309
3310 The data of the copy is shared (shallow copy): modifying one node
3311 will also change the other. If you want to make a deep copy, use
3312 cloneNode().
3313*/
3314QDomDocumentType &QDomDocumentType::operator=(const QDomDocumentType &other) = default;
3315/*!
3316 Returns the name of the document type as specified in the
3317 &lt;!DOCTYPE name&gt; tag.
3318
3319 \sa nodeName()
3320*/
3321QString QDomDocumentType::name() const
3322{
3323 if (!impl)
3324 return QString();
3325 return IMPL->nodeName();
3326}
3327
3328/*!
3329 Returns a map of all entities described in the DTD.
3330*/
3331QDomNamedNodeMap QDomDocumentType::entities() const
3332{
3333 if (!impl)
3334 return QDomNamedNodeMap();
3335 return QDomNamedNodeMap(IMPL->entities);
3336}
3337
3338/*!
3339 Returns a map of all notations described in the DTD.
3340*/
3341QDomNamedNodeMap QDomDocumentType::notations() const
3342{
3343 if (!impl)
3344 return QDomNamedNodeMap();
3345 return QDomNamedNodeMap(IMPL->notations);
3346}
3347
3348/*!
3349 Returns the public identifier of the external DTD subset or
3350 an empty string if there is no public identifier.
3351
3352 \sa systemId(), internalSubset(), QDomImplementation::createDocumentType()
3353*/
3354QString QDomDocumentType::publicId() const
3355{
3356 if (!impl)
3357 return QString();
3358 return IMPL->publicId;
3359}
3360
3361/*!
3362 Returns the system identifier of the external DTD subset or
3363 an empty string if there is no system identifier.
3364
3365 \sa publicId(), internalSubset(), QDomImplementation::createDocumentType()
3366*/
3367QString QDomDocumentType::systemId() const
3368{
3369 if (!impl)
3370 return QString();
3371 return IMPL->systemId;
3372}
3373
3374/*!
3375 Returns the internal subset of the document type or an empty
3376 string if there is no internal subset.
3377
3378 \sa publicId(), systemId()
3379*/
3380QString QDomDocumentType::internalSubset() const
3381{
3382 if (!impl)
3383 return QString();
3384 return IMPL->internalSubset;
3385}
3386
3387/*
3388 Are these needed at all? The only difference when removing these
3389 two methods in all subclasses is that we'd get a different type
3390 for null nodes.
3391*/
3392
3393/*!
3394 \fn QDomNode::NodeType QDomDocumentType::nodeType() const
3395
3396 Returns \c DocumentTypeNode.
3397
3398 \sa isDocumentType(), QDomNode::toDocumentType()
3399*/
3400
3401#undef IMPL
3402
3403/**************************************************************
3404 *
3405 * QDomDocumentFragmentPrivate
3406 *
3407 **************************************************************/
3408
3409QDomDocumentFragmentPrivate::QDomDocumentFragmentPrivate(QDomDocumentPrivate* doc, QDomNodePrivate* parent)
3410 : QDomNodePrivate(doc, parent)
3411{
3412 name = u"#document-fragment"_s;
3413}
3414
3415QDomDocumentFragmentPrivate::QDomDocumentFragmentPrivate(QDomNodePrivate* n, bool deep)
3416 : QDomNodePrivate(n, deep)
3417{
3418}
3419
3420QDomNodePrivate* QDomDocumentFragmentPrivate::cloneNode(bool deep)
3421{
3422 QDomNodePrivate* p = new QDomDocumentFragmentPrivate(this, deep);
3423 // We are not interested in this node
3424 p->ref.deref();
3425 return p;
3426}
3427
3428/**************************************************************
3429 *
3430 * QDomDocumentFragment
3431 *
3432 **************************************************************/
3433
3434/*!
3435 \class QDomDocumentFragment
3436 \reentrant
3437 \brief The QDomDocumentFragment class is a tree of QDomNodes which is not usually a complete QDomDocument.
3438
3439 \inmodule QtXml
3440 \ingroup xml-tools
3441
3442 If you want to do complex tree operations it is useful to have a
3443 lightweight class to store nodes and their relations.
3444 QDomDocumentFragment stores a subtree of a document which does not
3445 necessarily represent a well-formed XML document.
3446
3447 QDomDocumentFragment is also useful if you want to group several
3448 nodes in a list and insert them all together as children of some
3449 node. In these cases QDomDocumentFragment can be used as a
3450 temporary container for this list of children.
3451
3452 The most important feature of QDomDocumentFragment is that it is
3453 treated in a special way by QDomNode::insertAfter(),
3454 QDomNode::insertBefore(), QDomNode::replaceChild() and
3455 QDomNode::appendChild(): instead of inserting the fragment itself, all
3456 the fragment's children are inserted.
3457*/
3458
3459/*!
3460 Constructs an empty document fragment.
3461*/
3462QDomDocumentFragment::QDomDocumentFragment()
3463{
3464}
3465
3466QDomDocumentFragment::QDomDocumentFragment(QDomDocumentFragmentPrivate* n)
3467 : QDomNode(n)
3468{
3469}
3470
3471/*!
3472 Constructs a copy of \a documentFragment.
3473
3474 The data of the copy is shared (shallow copy): modifying one node
3475 will also change the other. If you want to make a deep copy, use
3476 cloneNode().
3477*/
3478QDomDocumentFragment::QDomDocumentFragment(const QDomDocumentFragment &documentFragment)
3479 : QDomNode(documentFragment)
3480{
3481}
3482
3483/*!
3484 Assigns \a other to this DOM document fragment.
3485
3486 The data of the copy is shared (shallow copy): modifying one node
3487 will also change the other. If you want to make a deep copy, use
3488 cloneNode().
3489*/
3490QDomDocumentFragment &QDomDocumentFragment::operator=(const QDomDocumentFragment &other) = default;
3491
3492/*!
3493 \fn QDomNode::NodeType QDomDocumentFragment::nodeType() const
3494
3495 Returns \c DocumentFragment.
3496
3497 \sa isDocumentFragment(), QDomNode::toDocumentFragment()
3498*/
3499
3500/**************************************************************
3501 *
3502 * QDomCharacterDataPrivate
3503 *
3504 **************************************************************/
3505
3506QDomCharacterDataPrivate::QDomCharacterDataPrivate(QDomDocumentPrivate* d, QDomNodePrivate* p,
3507 const QString& data)
3508 : QDomNodePrivate(d, p)
3509{
3510 value = data;
3511 name = u"#character-data"_s;
3512}
3513
3514QDomCharacterDataPrivate::QDomCharacterDataPrivate(QDomCharacterDataPrivate* n, bool deep)
3515 : QDomNodePrivate(n, deep)
3516{
3517}
3518
3519QDomNodePrivate* QDomCharacterDataPrivate::cloneNode(bool deep)
3520{
3521 QDomNodePrivate* p = new QDomCharacterDataPrivate(this, deep);
3522 // We are not interested in this node
3523 p->ref.deref();
3524 return p;
3525}
3526
3527int QDomCharacterDataPrivate::dataLength() const
3528{
3529 return value.size();
3530}
3531
3532QString QDomCharacterDataPrivate::substringData(unsigned long offset, unsigned long n) const
3533{
3534 return value.mid(position: offset, n);
3535}
3536
3537void QDomCharacterDataPrivate::insertData(unsigned long offset, const QString& arg)
3538{
3539 value.insert(i: offset, s: arg);
3540}
3541
3542void QDomCharacterDataPrivate::deleteData(unsigned long offset, unsigned long n)
3543{
3544 value.remove(i: offset, len: n);
3545}
3546
3547void QDomCharacterDataPrivate::replaceData(unsigned long offset, unsigned long n, const QString& arg)
3548{
3549 value.replace(i: offset, len: n, after: arg);
3550}
3551
3552void QDomCharacterDataPrivate::appendData(const QString& arg)
3553{
3554 value += arg;
3555}
3556
3557/**************************************************************
3558 *
3559 * QDomCharacterData
3560 *
3561 **************************************************************/
3562
3563#define IMPL static_cast<QDomCharacterDataPrivate *>(impl)
3564
3565/*!
3566 \class QDomCharacterData
3567 \reentrant
3568 \brief The QDomCharacterData class represents a generic string in the DOM.
3569
3570 \inmodule QtXml
3571 \ingroup xml-tools
3572
3573 Character data as used in XML specifies a generic data string.
3574 More specialized versions of this class are QDomText, QDomComment
3575 and QDomCDATASection.
3576
3577 The data string is set with setData() and retrieved with data().
3578 You can retrieve a portion of the data string using
3579 substringData(). Extra data can be appended with appendData(), or
3580 inserted with insertData(). Portions of the data string can be
3581 deleted with deleteData() or replaced with replaceData(). The
3582 length of the data string is returned by length().
3583
3584 The node type of the node containing this character data is
3585 returned by nodeType().
3586
3587 \sa QDomText, QDomComment, QDomCDATASection
3588*/
3589
3590/*!
3591 Constructs an empty character data object.
3592*/
3593QDomCharacterData::QDomCharacterData()
3594{
3595}
3596
3597/*!
3598 Constructs a copy of \a characterData.
3599
3600 The data of the copy is shared (shallow copy): modifying one node
3601 will also change the other. If you want to make a deep copy, use
3602 cloneNode().
3603*/
3604QDomCharacterData::QDomCharacterData(const QDomCharacterData &characterData)
3605 : QDomNode(characterData)
3606{
3607}
3608
3609QDomCharacterData::QDomCharacterData(QDomCharacterDataPrivate* n)
3610 : QDomNode(n)
3611{
3612}
3613
3614/*!
3615 Assigns \a other to this character data.
3616
3617 The data of the copy is shared (shallow copy): modifying one node
3618 will also change the other. If you want to make a deep copy, use
3619 cloneNode().
3620*/
3621QDomCharacterData &QDomCharacterData::operator=(const QDomCharacterData &other) = default;
3622
3623/*!
3624 Returns the string stored in this object.
3625
3626 If the node is a \l{isNull()}{null node}, it will return
3627 an empty string.
3628*/
3629QString QDomCharacterData::data() const
3630{
3631 if (!impl)
3632 return QString();
3633 return impl->nodeValue();
3634}
3635
3636/*!
3637 Sets this object's string to \a data.
3638*/
3639void QDomCharacterData::setData(const QString &data)
3640{
3641 if (impl)
3642 impl->setNodeValue(data);
3643}
3644
3645/*!
3646 Returns the length of the stored string.
3647*/
3648int QDomCharacterData::length() const
3649{
3650 if (impl)
3651 return IMPL->dataLength();
3652 return 0;
3653}
3654
3655/*!
3656 Returns the substring of length \a count from position \a offset.
3657*/
3658QString QDomCharacterData::substringData(unsigned long offset, unsigned long count)
3659{
3660 if (!impl)
3661 return QString();
3662 return IMPL->substringData(offset, n: count);
3663}
3664
3665/*!
3666 Appends the string \a arg to the stored string.
3667*/
3668void QDomCharacterData::appendData(const QString& arg)
3669{
3670 if (impl)
3671 IMPL->appendData(arg);
3672}
3673
3674/*!
3675 Inserts the string \a arg into the stored string at position \a offset.
3676*/
3677void QDomCharacterData::insertData(unsigned long offset, const QString& arg)
3678{
3679 if (impl)
3680 IMPL->insertData(offset, arg);
3681}
3682
3683/*!
3684 Deletes a substring of length \a count from position \a offset.
3685*/
3686void QDomCharacterData::deleteData(unsigned long offset, unsigned long count)
3687{
3688 if (impl)
3689 IMPL->deleteData(offset, n: count);
3690}
3691
3692/*!
3693 Replaces the substring of length \a count starting at position \a
3694 offset with the string \a arg.
3695*/
3696void QDomCharacterData::replaceData(unsigned long offset, unsigned long count, const QString& arg)
3697{
3698 if (impl)
3699 IMPL->replaceData(offset, n: count, arg);
3700}
3701
3702/*!
3703 Returns the type of node this object refers to (i.e. \c TextNode,
3704 \c CDATASectionNode, \c CommentNode or \c CharacterDataNode). For
3705 a \l{isNull()}{null node}, returns \c CharacterDataNode.
3706*/
3707QDomNode::NodeType QDomCharacterData::nodeType() const
3708{
3709 if (!impl)
3710 return CharacterDataNode;
3711 return QDomNode::nodeType();
3712}
3713
3714#undef IMPL
3715
3716/**************************************************************
3717 *
3718 * QDomAttrPrivate
3719 *
3720 **************************************************************/
3721
3722QDomAttrPrivate::QDomAttrPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent, const QString& name_)
3723 : QDomNodePrivate(d, parent)
3724{
3725 name = name_;
3726 m_specified = false;
3727}
3728
3729QDomAttrPrivate::QDomAttrPrivate(QDomDocumentPrivate* d, QDomNodePrivate* p, const QString& nsURI, const QString& qName)
3730 : QDomNodePrivate(d, p)
3731{
3732 qt_split_namespace(prefix, name, qName, hasURI: !nsURI.isNull());
3733 namespaceURI = nsURI;
3734 createdWithDom1Interface = false;
3735 m_specified = false;
3736}
3737
3738QDomAttrPrivate::QDomAttrPrivate(QDomAttrPrivate* n, bool deep)
3739 : QDomNodePrivate(n, deep)
3740{
3741 m_specified = n->specified();
3742}
3743
3744void QDomAttrPrivate::setNodeValue(const QString& v)
3745{
3746 value = v;
3747 QDomTextPrivate *t = new QDomTextPrivate(nullptr, this, v);
3748 // keep the refcount balanced: appendChild() does a ref anyway.
3749 t->ref.deref();
3750 if (first) {
3751 auto removed = removeChild(oldChild: first);
3752 if (removed && !removed->ref.loadRelaxed()) // removeChild() already deref()ed
3753 delete removed;
3754 }
3755 appendChild(newChild: t);
3756}
3757
3758QDomNodePrivate* QDomAttrPrivate::cloneNode(bool deep)
3759{
3760 QDomNodePrivate* p = new QDomAttrPrivate(this, deep);
3761 // We are not interested in this node
3762 p->ref.deref();
3763 return p;
3764}
3765
3766bool QDomAttrPrivate::specified() const
3767{
3768 return m_specified;
3769}
3770
3771/* \internal
3772 Encode & escape \a str. Yes, it makes no sense to return a QString,
3773 but is so for legacy reasons.
3774
3775 Remember that content produced should be able to roundtrip with 2.11 End-of-Line Handling
3776 and 3.3.3 Attribute-Value Normalization.
3777
3778 If \a performAVN is true, characters will be escaped to survive Attribute Value Normalization.
3779 If \a encodeEOLs is true, characters will be escaped to survive End-of-Line Handling.
3780*/
3781static QString encodeText(const QString &str,
3782 const bool encodeQuotes = true,
3783 const bool performAVN = false,
3784 const bool encodeEOLs = false)
3785{
3786 QString retval;
3787 qsizetype start = 0;
3788 auto appendToOutput = [&](qsizetype cur, const auto &replacement)
3789 {
3790 if (start < cur) {
3791 retval.reserve(asize: str.size() + replacement.size());
3792 retval.append(v: QStringView(str).first(n: cur).sliced(pos: start));
3793 }
3794 // Skip over str[cur], replaced by replacement
3795 start = cur + 1;
3796 retval.append(replacement);
3797 };
3798
3799 const qsizetype len = str.size();
3800 for (qsizetype cur = 0; cur < len; ++cur) {
3801 switch (str[cur].unicode()) {
3802 case u'<':
3803 appendToOutput(cur, "&lt;"_L1);
3804 break;
3805 case u'"':
3806 if (encodeQuotes)
3807 appendToOutput(cur, "&quot;"_L1);
3808 break;
3809 case u'&':
3810 appendToOutput(cur, "&amp;"_L1);
3811 break;
3812 case u'>':
3813 if (cur >= 2 && str[cur - 1] == u']' && str[cur - 2] == u']')
3814 appendToOutput(cur, "&gt;"_L1);
3815 break;
3816 case u'\r':
3817 if (performAVN || encodeEOLs)
3818 appendToOutput(cur, "&#xd;"_L1); // \r == 0x0d
3819 break;
3820 case u'\n':
3821 if (performAVN)
3822 appendToOutput(cur, "&#xa;"_L1); // \n == 0x0a
3823 break;
3824 case u'\t':
3825 if (performAVN)
3826 appendToOutput(cur, "&#x9;"_L1); // \t == 0x09
3827 break;
3828 default:
3829 break;
3830 }
3831 }
3832 if (start > 0) {
3833 retval.append(v: QStringView(str).first(n: len).sliced(pos: start));
3834 return retval;
3835 }
3836 return str;
3837}
3838
3839void QDomAttrPrivate::save(QTextStream& s, int, int) const
3840{
3841 if (namespaceURI.isNull()) {
3842 s << name << "=\"" << encodeText(str: value, encodeQuotes: true, performAVN: true) << '\"';
3843 } else {
3844 s << prefix << ':' << name << "=\"" << encodeText(str: value, encodeQuotes: true, performAVN: true) << '\"';
3845 /* This is a fix for 138243, as good as it gets.
3846 *
3847 * QDomElementPrivate::save() output a namespace declaration if
3848 * the element is in a namespace, no matter what. This function do as well, meaning
3849 * that we get two identical namespace declaration if we don't have the if-
3850 * statement below.
3851 *
3852 * This doesn't work when the parent element has the same prefix as us but
3853 * a different namespace. However, this can only occur by the user modifying the element,
3854 * and we don't do fixups by that anyway, and hence it's the user responsibility to not
3855 * arrive in those situations. */
3856 if (!ownerNode ||
3857 ownerNode->prefix != prefix) {
3858 s << " xmlns:" << prefix << "=\"" << encodeText(str: namespaceURI, encodeQuotes: true, performAVN: true) << '\"';
3859 }
3860 }
3861}
3862
3863/**************************************************************
3864 *
3865 * QDomAttr
3866 *
3867 **************************************************************/
3868
3869#define IMPL static_cast<QDomAttrPrivate *>(impl)
3870
3871/*!
3872 \class QDomAttr
3873 \reentrant
3874 \brief The QDomAttr class represents one attribute of a QDomElement.
3875
3876 \inmodule QtXml
3877 \ingroup xml-tools
3878
3879 For example, the following piece of XML produces an element with
3880 no children, but two attributes:
3881
3882 \snippet code/src_xml_dom_qdom_snippet.cpp 7
3883
3884 You can access the attributes of an element with code like this:
3885
3886 \snippet code/src_xml_dom_qdom.cpp 8
3887
3888 This example also shows that changing an attribute received from
3889 an element changes the attribute of the element. If you do not
3890 want to change the value of the element's attribute you must
3891 use cloneNode() to get an independent copy of the attribute.
3892
3893 QDomAttr can return the name() and value() of an attribute. An
3894 attribute's value is set with setValue(). If specified() returns
3895 true the value was set with setValue(). The node this
3896 attribute is attached to (if any) is returned by ownerElement().
3897
3898 For further information about the Document Object Model see
3899 \l{http://www.w3.org/TR/REC-DOM-Level-1/} and
3900 \l{http://www.w3.org/TR/DOM-Level-2-Core/}.
3901 For a more general introduction of the DOM implementation see the
3902 QDomDocument documentation.
3903*/
3904
3905
3906/*!
3907 Constructs an empty attribute.
3908*/
3909QDomAttr::QDomAttr()
3910{
3911}
3912
3913/*!
3914 Constructs a copy of \a attr.
3915
3916 The data of the copy is shared (shallow copy): modifying one node
3917 will also change the other. If you want to make a deep copy, use
3918 cloneNode().
3919*/
3920QDomAttr::QDomAttr(const QDomAttr &attr)
3921 : QDomNode(attr)
3922{
3923}
3924
3925QDomAttr::QDomAttr(QDomAttrPrivate* n)
3926 : QDomNode(n)
3927{
3928}
3929
3930/*!
3931 Assigns \a other to this DOM attribute.
3932
3933 The data of the copy is shared (shallow copy): modifying one node
3934 will also change the other. If you want to make a deep copy, use
3935 cloneNode().
3936*/
3937QDomAttr &QDomAttr::operator=(const QDomAttr &other) = default;
3938
3939/*!
3940 Returns the attribute's name.
3941*/
3942QString QDomAttr::name() const
3943{
3944 if (!impl)
3945 return QString();
3946 return impl->nodeName();
3947}
3948
3949/*!
3950 Returns \c true if the attribute has been set by the user with setValue().
3951 Returns \c false if the value hasn't been specified or set.
3952
3953 \sa setValue()
3954*/
3955bool QDomAttr::specified() const
3956{
3957 if (!impl)
3958 return false;
3959 return IMPL->specified();
3960}
3961
3962/*!
3963 Returns the element node this attribute is attached to or a
3964 \l{QDomNode::isNull()}{null node} if this attribute is not
3965 attached to any element.
3966*/
3967QDomElement QDomAttr::ownerElement() const
3968{
3969 Q_ASSERT(impl->parent());
3970 if (!impl->parent()->isElement())
3971 return QDomElement();
3972 return QDomElement(static_cast<QDomElementPrivate *>(impl->parent()));
3973}
3974
3975/*!
3976 Returns the value of the attribute or an empty string if the
3977 attribute has not been specified.
3978
3979 \sa specified(), setValue()
3980*/
3981QString QDomAttr::value() const
3982{
3983 if (!impl)
3984 return QString();
3985 return impl->nodeValue();
3986}
3987
3988/*!
3989 Sets the attribute's value to \a value.
3990
3991 \sa value()
3992*/
3993void QDomAttr::setValue(const QString &value)
3994{
3995 if (!impl)
3996 return;
3997 impl->setNodeValue(value);
3998 IMPL->m_specified = true;
3999}
4000
4001/*!
4002 \fn QDomNode::NodeType QDomAttr::nodeType() const
4003
4004 Returns \l{QDomNode::NodeType}{AttributeNode}.
4005*/
4006
4007#undef IMPL
4008
4009/**************************************************************
4010 *
4011 * QDomElementPrivate
4012 *
4013 **************************************************************/
4014
4015QDomElementPrivate::QDomElementPrivate(QDomDocumentPrivate* d, QDomNodePrivate* p,
4016 const QString& tagname)
4017 : QDomNodePrivate(d, p)
4018{
4019 name = tagname;
4020 m_attr = new QDomNamedNodeMapPrivate(this);
4021}
4022
4023QDomElementPrivate::QDomElementPrivate(QDomDocumentPrivate* d, QDomNodePrivate* p,
4024 const QString& nsURI, const QString& qName)
4025 : QDomNodePrivate(d, p)
4026{
4027 qt_split_namespace(prefix, name, qName, hasURI: !nsURI.isNull());
4028 namespaceURI = nsURI;
4029 createdWithDom1Interface = false;
4030 m_attr = new QDomNamedNodeMapPrivate(this);
4031}
4032
4033QDomElementPrivate::QDomElementPrivate(QDomElementPrivate* n, bool deep) :
4034 QDomNodePrivate(n, deep)
4035{
4036 m_attr = n->m_attr->clone(pimpl: this);
4037 // Reference is down to 0, so we set it to 1 here.
4038 m_attr->ref.ref();
4039}
4040
4041QDomElementPrivate::~QDomElementPrivate()
4042{
4043 if (!m_attr->ref.deref())
4044 delete m_attr;
4045}
4046
4047QDomNodePrivate* QDomElementPrivate::cloneNode(bool deep)
4048{
4049 QDomNodePrivate* p = new QDomElementPrivate(this, deep);
4050 // We are not interested in this node
4051 p->ref.deref();
4052 return p;
4053}
4054
4055QString QDomElementPrivate::attribute(const QString& name_, const QString& defValue) const
4056{
4057 QDomNodePrivate* n = m_attr->namedItem(name: name_);
4058 if (!n)
4059 return defValue;
4060
4061 return n->nodeValue();
4062}
4063
4064QString QDomElementPrivate::attributeNS(const QString& nsURI, const QString& localName, const QString& defValue) const
4065{
4066 QDomNodePrivate* n = m_attr->namedItemNS(nsURI, localName);
4067 if (!n)
4068 return defValue;
4069
4070 return n->nodeValue();
4071}
4072
4073void QDomElementPrivate::setAttribute(const QString& aname, const QString& newValue)
4074{
4075 QDomNodePrivate* n = m_attr->namedItem(name: aname);
4076 if (!n) {
4077 n = new QDomAttrPrivate(ownerDocument(), this, aname);
4078 n->setNodeValue(newValue);
4079
4080 // Referencing is done by the map, so we set the reference counter back
4081 // to 0 here. This is ok since we created the QDomAttrPrivate.
4082 n->ref.deref();
4083 m_attr->setNamedItem(n);
4084 } else {
4085 n->setNodeValue(newValue);
4086 }
4087}
4088
4089void QDomElementPrivate::setAttributeNS(const QString& nsURI, const QString& qName, const QString& newValue)
4090{
4091 QString prefix, localName;
4092 qt_split_namespace(prefix, name&: localName, qName, hasURI: true);
4093 QDomNodePrivate* n = m_attr->namedItemNS(nsURI, localName);
4094 if (!n) {
4095 n = new QDomAttrPrivate(ownerDocument(), this, nsURI, qName);
4096 n->setNodeValue(newValue);
4097
4098 // Referencing is done by the map, so we set the reference counter back
4099 // to 0 here. This is ok since we created the QDomAttrPrivate.
4100 n->ref.deref();
4101 m_attr->setNamedItem(n);
4102 } else {
4103 n->setNodeValue(newValue);
4104 n->prefix = prefix;
4105 }
4106}
4107
4108void QDomElementPrivate::removeAttribute(const QString& aname)
4109{
4110 QDomNodePrivate* p = m_attr->removeNamedItem(name: aname);
4111 if (p && p->ref.loadRelaxed() == 0)
4112 delete p;
4113}
4114
4115QDomAttrPrivate* QDomElementPrivate::attributeNode(const QString& aname)
4116{
4117 return static_cast<QDomAttrPrivate *>(m_attr->namedItem(name: aname));
4118}
4119
4120QDomAttrPrivate* QDomElementPrivate::attributeNodeNS(const QString& nsURI, const QString& localName)
4121{
4122 return static_cast<QDomAttrPrivate *>(m_attr->namedItemNS(nsURI, localName));
4123}
4124
4125QDomAttrPrivate* QDomElementPrivate::setAttributeNode(QDomAttrPrivate* newAttr)
4126{
4127 if (!newAttr)
4128 return nullptr;
4129
4130 QDomNodePrivate* foundAttr = m_attr->namedItem(name: newAttr->nodeName());
4131 if (foundAttr)
4132 m_attr->removeNamedItem(name: newAttr->nodeName());
4133
4134 // Referencing is done by the maps
4135 m_attr->setNamedItem(newAttr);
4136 newAttr->setParent(this);
4137
4138 return static_cast<QDomAttrPrivate *>(foundAttr);
4139}
4140
4141QDomAttrPrivate* QDomElementPrivate::setAttributeNodeNS(QDomAttrPrivate* newAttr)
4142{
4143 QDomNodePrivate* n = nullptr;
4144 if (!newAttr->prefix.isNull())
4145 n = m_attr->namedItemNS(nsURI: newAttr->namespaceURI, localName: newAttr->name);
4146
4147 // Referencing is done by the maps
4148 m_attr->setNamedItem(newAttr);
4149
4150 return static_cast<QDomAttrPrivate *>(n);
4151}
4152
4153QDomAttrPrivate* QDomElementPrivate::removeAttributeNode(QDomAttrPrivate* oldAttr)
4154{
4155 return static_cast<QDomAttrPrivate *>(m_attr->removeNamedItem(name: oldAttr->nodeName()));
4156}
4157
4158bool QDomElementPrivate::hasAttribute(const QString& aname)
4159{
4160 return m_attr->contains(name: aname);
4161}
4162
4163bool QDomElementPrivate::hasAttributeNS(const QString& nsURI, const QString& localName)
4164{
4165 return m_attr->containsNS(nsURI, localName);
4166}
4167
4168QString QDomElementPrivate::text()
4169{
4170 QString t(u""_s);
4171
4172 QDomNodePrivate* p = first;
4173 while (p) {
4174 if (p->isText() || p->isCDATASection())
4175 t += p->nodeValue();
4176 else if (p->isElement())
4177 t += static_cast<QDomElementPrivate *>(p)->text();
4178 p = p->next;
4179 }
4180
4181 return t;
4182}
4183
4184void QDomElementPrivate::save(QTextStream& s, int depth, int indent) const
4185{
4186 if (!(prev && prev->isText()))
4187 s << QString(indent < 1 ? 0 : depth * indent, u' ');
4188
4189 QString qName(name);
4190 QString nsDecl(u""_s);
4191 if (!namespaceURI.isNull()) {
4192 /** ###
4193 *
4194 * If we still have QDom, optimize this so that we only declare namespaces that are not
4195 * yet declared. We loose default namespace mappings, so maybe we should rather store
4196 * the information that we get from startPrefixMapping()/endPrefixMapping() and use them.
4197 * Modifications becomes more complex then, however.
4198 *
4199 * We cannot do this in a patch release because it would require too invasive changes, and
4200 * hence possibly behavioral changes.
4201 */
4202 if (prefix.isEmpty()) {
4203 nsDecl = u" xmlns"_s;
4204 } else {
4205 qName = prefix + u':' + name;
4206 nsDecl = u" xmlns:"_s + prefix;
4207 }
4208 nsDecl += u"=\""_s + encodeText(str: namespaceURI) + u'\"';
4209 }
4210 s << '<' << qName << nsDecl;
4211
4212
4213 /* Write out attributes. */
4214 if (!m_attr->map.isEmpty()) {
4215 /*
4216 * To ensure that we always output attributes in a consistent
4217 * order, sort the attributes before writing them into the
4218 * stream. (Note that the order may be different than the one
4219 * that e.g. we've read from a file, or the program order in
4220 * which these attributes have been populated. We just want to
4221 * guarantee reproducibile outputs.)
4222 */
4223 struct SavedAttribute {
4224 QString prefix;
4225 QString name;
4226 QString encodedValue;
4227 };
4228
4229 /* Gather all the attributes to save. */
4230 QVarLengthArray<SavedAttribute, 8> attributesToSave;
4231 attributesToSave.reserve(sz: m_attr->map.size());
4232
4233 QDuplicateTracker<QString> outputtedPrefixes;
4234 for (const auto &[key, value] : std::as_const(t&: m_attr->map).asKeyValueRange()) {
4235 Q_UNUSED(key); /* We extract the attribute name from the value. */
4236 bool mayNeedXmlNS = false;
4237
4238 SavedAttribute attr;
4239 attr.name = value->name;
4240 attr.encodedValue = encodeText(str: value->value, encodeQuotes: true, performAVN: true);
4241 if (!value->namespaceURI.isNull()) {
4242 attr.prefix = value->prefix;
4243 mayNeedXmlNS = true;
4244 }
4245
4246 attributesToSave.push_back(t: std::move(attr));
4247
4248 /*
4249 * This is a fix for 138243, as good as it gets.
4250 *
4251 * QDomElementPrivate::save() output a namespace
4252 * declaration if the element is in a namespace, no matter
4253 * what. This function do as well, meaning that we get two
4254 * identical namespace declaration if we don't have the if-
4255 * statement below.
4256 *
4257 * This doesn't work when the parent element has the same
4258 * prefix as us but a different namespace. However, this
4259 * can only occur by the user modifying the element, and we
4260 * don't do fixups by that anyway, and hence it's the user
4261 * responsibility to avoid those situations.
4262 */
4263
4264 if (mayNeedXmlNS
4265 && ((!value->ownerNode || value->ownerNode->prefix != value->prefix)
4266 && !outputtedPrefixes.hasSeen(s: value->prefix)))
4267 {
4268 SavedAttribute nsAttr;
4269 nsAttr.prefix = QStringLiteral("xmlns");
4270 nsAttr.name = value->prefix;
4271 nsAttr.encodedValue = encodeText(str: value->namespaceURI, encodeQuotes: true, performAVN: true);
4272 attributesToSave.push_back(t: std::move(nsAttr));
4273 }
4274 }
4275
4276 /* Sort the attributes by prefix and name. */
4277 const auto savedAttributeComparator = [](const SavedAttribute &lhs, const SavedAttribute &rhs)
4278 {
4279 const int cmp = QString::compare(s1: lhs.prefix, s2: rhs.prefix);
4280 return (cmp < 0) || ((cmp == 0) && (lhs.name < rhs.name));
4281 };
4282
4283 std::sort(first: attributesToSave.begin(), last: attributesToSave.end(), comp: savedAttributeComparator);
4284
4285 /* Actually stream the sorted attributes. */
4286 for (const auto &attr : attributesToSave) {
4287 s << ' ';
4288 if (!attr.prefix.isEmpty())
4289 s << attr.prefix << ':';
4290 s << attr.name << "=\"" << attr.encodedValue << '\"';
4291 }
4292 }
4293
4294 if (last) {
4295 // has child nodes
4296 if (first->isText())
4297 s << '>';
4298 else {
4299 s << '>';
4300
4301 /* -1 disables new lines. */
4302 if (indent != -1)
4303 s << Qt::endl;
4304 }
4305 } else {
4306 s << "/>";
4307 }
4308}
4309
4310void QDomElementPrivate::afterSave(QTextStream &s, int depth, int indent) const
4311{
4312 if (last) {
4313 QString qName(name);
4314
4315 if (!prefix.isEmpty())
4316 qName = prefix + u':' + name;
4317
4318 if (!last->isText())
4319 s << QString(indent < 1 ? 0 : depth * indent, u' ');
4320
4321 s << "</" << qName << '>';
4322 }
4323
4324 if (!(next && next->isText())) {
4325 /* -1 disables new lines. */
4326 if (indent != -1)
4327 s << Qt::endl;
4328 }
4329}
4330
4331/**************************************************************
4332 *
4333 * QDomElement
4334 *
4335 **************************************************************/
4336
4337#define IMPL static_cast<QDomElementPrivate *>(impl)
4338
4339/*!
4340 \class QDomElement
4341 \reentrant
4342 \brief The QDomElement class represents one element in the DOM tree.
4343
4344 \inmodule QtXml
4345 \ingroup xml-tools
4346
4347 Elements have a tagName() and zero or more attributes associated
4348 with them. The tag name can be changed with setTagName().
4349
4350 Element attributes are represented by QDomAttr objects that can
4351 be queried using the attribute() and attributeNode() functions.
4352 You can set attributes with the setAttribute() and
4353 setAttributeNode() functions. Attributes can be removed with
4354 removeAttribute(). There are namespace-aware equivalents to these
4355 functions, i.e. setAttributeNS(), setAttributeNodeNS() and
4356 removeAttributeNS().
4357
4358 If you want to access the text of a node use text(), e.g.
4359
4360 \snippet code/src_xml_dom_qdom_snippet.cpp 9
4361
4362 The text() function operates recursively to find the text (since
4363 not all elements contain text). If you want to find all the text
4364 in all of a node's children, iterate over the children looking for
4365 QDomText nodes, e.g.
4366
4367 \snippet code/src_xml_dom_qdom.cpp 10
4368
4369 Note that we attempt to convert each node to a text node and use
4370 text() rather than using firstChild().toText().data() or
4371 n.toText().data() directly on the node, because the node may not
4372 be a text element.
4373
4374 You can get a list of all the descendents of an element which have
4375 a specified tag name with elementsByTagName() or
4376 elementsByTagNameNS().
4377
4378 To browse the elements of a dom document use firstChildElement(), lastChildElement(),
4379 nextSiblingElement() and previousSiblingElement(). For example, to iterate over all
4380 child elements called "entry" in a root element called "database", you can use:
4381
4382 \snippet code/src_xml_dom_qdom_snippet.cpp 11
4383
4384 For further information about the Document Object Model see
4385 \l{W3C DOM Level 1}{Level 1} and
4386 \l{W3C DOM Level 2}{Level 2 Core}.
4387 For a more general introduction of the DOM implementation see the
4388 QDomDocument documentation.
4389*/
4390
4391/*!
4392 Constructs an empty element. Use the QDomDocument::createElement()
4393 function to construct elements with content.
4394*/
4395QDomElement::QDomElement()
4396 : QDomNode()
4397{
4398}
4399
4400/*!
4401 Constructs a copy of \a element.
4402
4403 The data of the copy is shared (shallow copy): modifying one node
4404 will also change the other. If you want to make a deep copy, use
4405 cloneNode().
4406*/
4407QDomElement::QDomElement(const QDomElement &element)
4408 : QDomNode(element)
4409{
4410}
4411
4412QDomElement::QDomElement(QDomElementPrivate* n)
4413 : QDomNode(n)
4414{
4415}
4416
4417/*!
4418 Assigns \a other to this DOM element.
4419
4420 The data of the copy is shared (shallow copy): modifying one node
4421 will also change the other. If you want to make a deep copy, use
4422 cloneNode().
4423*/
4424QDomElement &QDomElement::operator=(const QDomElement &other) = default;
4425
4426/*!
4427 \fn QDomNode::NodeType QDomElement::nodeType() const
4428
4429 Returns \c ElementNode.
4430*/
4431
4432/*!
4433 Sets this element's tag name to \a name.
4434
4435 \sa tagName()
4436*/
4437void QDomElement::setTagName(const QString& name)
4438{
4439 if (impl)
4440 impl->name = name;
4441}
4442
4443/*!
4444 Returns the tag name of this element. For an XML element like this:
4445
4446 \snippet code/src_xml_dom_qdom_snippet.cpp 12
4447
4448 the tagname would return "img".
4449
4450 \sa setTagName()
4451*/
4452QString QDomElement::tagName() const
4453{
4454 if (!impl)
4455 return QString();
4456 return impl->nodeName();
4457}
4458
4459
4460/*!
4461 Returns a QDomNamedNodeMap containing all this element's attributes.
4462
4463 \sa attribute(), setAttribute(), attributeNode(), setAttributeNode()
4464*/
4465QDomNamedNodeMap QDomElement::attributes() const
4466{
4467 if (!impl)
4468 return QDomNamedNodeMap();
4469 return QDomNamedNodeMap(IMPL->attributes());
4470}
4471
4472/*!
4473 Returns the attribute called \a name. If the attribute does not
4474 exist \a defValue is returned.
4475
4476 \sa setAttribute(), attributeNode(), setAttributeNode(), attributeNS()
4477*/
4478QString QDomElement::attribute(const QString& name, const QString& defValue) const
4479{
4480 if (!impl)
4481 return defValue;
4482 return IMPL->attribute(name_: name, defValue);
4483}
4484
4485/*!
4486 Adds an attribute called \a name with value \a value. If an
4487 attribute with the same name exists, its value is replaced by \a
4488 value.
4489
4490 \sa attribute(), setAttributeNode(), setAttributeNS()
4491*/
4492void QDomElement::setAttribute(const QString& name, const QString& value)
4493{
4494 if (!impl)
4495 return;
4496 IMPL->setAttribute(aname: name, newValue: value);
4497}
4498
4499/*!
4500 \fn void QDomElement::setAttribute(const QString& name, int value)
4501
4502 \overload
4503 The formatting always uses QLocale::C.
4504*/
4505
4506/*!
4507 \fn void QDomElement::setAttribute(const QString& name, uint value)
4508
4509 \overload
4510 The formatting always uses QLocale::C.
4511*/
4512
4513/*!
4514 \overload
4515
4516 The formatting always uses QLocale::C.
4517*/
4518void QDomElement::setAttribute(const QString& name, qlonglong value)
4519{
4520 if (!impl)
4521 return;
4522 QString x;
4523 x.setNum(value);
4524 IMPL->setAttribute(aname: name, newValue: x);
4525}
4526
4527/*!
4528 \overload
4529
4530 The formatting always uses QLocale::C.
4531*/
4532void QDomElement::setAttribute(const QString& name, qulonglong value)
4533{
4534 if (!impl)
4535 return;
4536 QString x;
4537 x.setNum(value);
4538 IMPL->setAttribute(aname: name, newValue: x);
4539}
4540
4541/*!
4542 \overload
4543
4544 The formatting always uses QLocale::C.
4545*/
4546void QDomElement::setAttribute(const QString& name, float value)
4547{
4548 if (!impl)
4549 return;
4550 QString x;
4551 x.setNum(n: value, f: 'g', prec: 8);
4552 IMPL->setAttribute(aname: name, newValue: x);
4553}
4554
4555/*!
4556 \overload
4557
4558 The formatting always uses QLocale::C.
4559*/
4560void QDomElement::setAttribute(const QString& name, double value)
4561{
4562 if (!impl)
4563 return;
4564 QString x;
4565 x.setNum(value, format: 'g', precision: 17);
4566 IMPL->setAttribute(aname: name, newValue: x);
4567}
4568
4569/*!
4570 Removes the attribute called name \a name from this element.
4571
4572 \sa setAttribute(), attribute(), removeAttributeNS()
4573*/
4574void QDomElement::removeAttribute(const QString& name)
4575{
4576 if (!impl)
4577 return;
4578 IMPL->removeAttribute(aname: name);
4579}
4580
4581/*!
4582 Returns the QDomAttr object that corresponds to the attribute
4583 called \a name. If no such attribute exists a
4584 \l{QDomNode::isNull()}{null attribute} is returned.
4585
4586 \sa setAttributeNode(), attribute(), setAttribute(), attributeNodeNS()
4587*/
4588QDomAttr QDomElement::attributeNode(const QString& name)
4589{
4590 if (!impl)
4591 return QDomAttr();
4592 return QDomAttr(IMPL->attributeNode(aname: name));
4593}
4594
4595/*!
4596 Adds the attribute \a newAttr to this element.
4597
4598 If the element has another attribute that has the same name as \a
4599 newAttr, this function replaces that attribute and returns it;
4600 otherwise the function returns a
4601 \l{QDomNode::isNull()}{null attribute}.
4602
4603 \sa attributeNode(), setAttribute(), setAttributeNodeNS()
4604*/
4605QDomAttr QDomElement::setAttributeNode(const QDomAttr& newAttr)
4606{
4607 if (!impl)
4608 return QDomAttr();
4609 return QDomAttr(IMPL->setAttributeNode(static_cast<QDomAttrPrivate *>(newAttr.impl)));
4610}
4611
4612/*!
4613 Removes the attribute \a oldAttr from the element and returns it.
4614
4615 \sa attributeNode(), setAttributeNode()
4616*/
4617QDomAttr QDomElement::removeAttributeNode(const QDomAttr& oldAttr)
4618{
4619 if (!impl)
4620 return QDomAttr(); // ### should this return oldAttr?
4621 return QDomAttr(IMPL->removeAttributeNode(oldAttr: static_cast<QDomAttrPrivate *>(oldAttr.impl)));
4622}
4623
4624/*!
4625 Returns a QDomNodeList containing all descendants of this element
4626 named \a tagname encountered during a preorder traversal of the
4627 element subtree with this element as its root. The order of the
4628 elements in the returned list is the order they are encountered
4629 during the preorder traversal.
4630
4631 \sa elementsByTagNameNS(), QDomDocument::elementsByTagName()
4632*/
4633QDomNodeList QDomElement::elementsByTagName(const QString& tagname) const
4634{
4635 return QDomNodeList(new QDomNodeListPrivate(impl, tagname));
4636}
4637
4638/*!
4639 Returns \c true if this element has an attribute called \a name;
4640 otherwise returns \c false.
4641
4642 \b{Note:} This function does not take the presence of namespaces
4643 into account. As a result, the specified name will be tested
4644 against fully-qualified attribute names that include any namespace
4645 prefixes that may be present.
4646
4647 Use hasAttributeNS() to explicitly test for attributes with specific
4648 namespaces and names.
4649*/
4650bool QDomElement::hasAttribute(const QString& name) const
4651{
4652 if (!impl)
4653 return false;
4654 return IMPL->hasAttribute(aname: name);
4655}
4656
4657/*!
4658 Returns the attribute with the local name \a localName and the
4659 namespace URI \a nsURI. If the attribute does not exist \a
4660 defValue is returned.
4661
4662 \sa setAttributeNS(), attributeNodeNS(), setAttributeNodeNS(), attribute()
4663*/
4664QString QDomElement::attributeNS(const QString& nsURI, const QString& localName, const QString& defValue) const
4665{
4666 if (!impl)
4667 return defValue;
4668 return IMPL->attributeNS(nsURI, localName, defValue);
4669}
4670
4671/*!
4672 Adds an attribute with the qualified name \a qName and the
4673 namespace URI \a nsURI with the value \a value. If an attribute
4674 with the same local name and namespace URI exists, its prefix is
4675 replaced by the prefix of \a qName and its value is replaced by \a
4676 value.
4677
4678 Although \a qName is the qualified name, the local name is used to
4679 decide if an existing attribute's value should be replaced.
4680
4681 \sa attributeNS(), setAttributeNodeNS(), setAttribute()
4682*/
4683void QDomElement::setAttributeNS(const QString& nsURI, const QString& qName, const QString& value)
4684{
4685 if (!impl)
4686 return;
4687 IMPL->setAttributeNS(nsURI, qName, newValue: value);
4688}
4689
4690/*!
4691 \fn void QDomElement::setAttributeNS(const QString& nsURI, const QString& qName, int value)
4692
4693 \overload
4694*/
4695
4696/*!
4697 \fn void QDomElement::setAttributeNS(const QString& nsURI, const QString& qName, uint value)
4698
4699 \overload
4700*/
4701
4702/*!
4703 \overload
4704*/
4705void QDomElement::setAttributeNS(const QString& nsURI, const QString& qName, qlonglong value)
4706{
4707 if (!impl)
4708 return;
4709 QString x;
4710 x.setNum(value);
4711 IMPL->setAttributeNS(nsURI, qName, newValue: x);
4712}
4713
4714/*!
4715 \overload
4716*/
4717void QDomElement::setAttributeNS(const QString& nsURI, const QString& qName, qulonglong value)
4718{
4719 if (!impl)
4720 return;
4721 QString x;
4722 x.setNum(value);
4723 IMPL->setAttributeNS(nsURI, qName, newValue: x);
4724}
4725
4726/*!
4727 \overload
4728*/
4729void QDomElement::setAttributeNS(const QString& nsURI, const QString& qName, double value)
4730{
4731 if (!impl)
4732 return;
4733 QString x;
4734 x.setNum(value, format: 'g', precision: 17);
4735 IMPL->setAttributeNS(nsURI, qName, newValue: x);
4736}
4737
4738/*!
4739 Removes the attribute with the local name \a localName and the
4740 namespace URI \a nsURI from this element.
4741
4742 \sa setAttributeNS(), attributeNS(), removeAttribute()
4743*/
4744void QDomElement::removeAttributeNS(const QString& nsURI, const QString& localName)
4745{
4746 if (!impl)
4747 return;
4748 QDomNodePrivate *n = IMPL->attributeNodeNS(nsURI, localName);
4749 if (!n)
4750 return;
4751 IMPL->removeAttribute(aname: n->nodeName());
4752}
4753
4754/*!
4755 Returns the QDomAttr object that corresponds to the attribute
4756 with the local name \a localName and the namespace URI \a nsURI.
4757 If no such attribute exists a \l{QDomNode::isNull()}{null
4758 attribute} is returned.
4759
4760 \sa setAttributeNode(), attribute(), setAttribute()
4761*/
4762QDomAttr QDomElement::attributeNodeNS(const QString& nsURI, const QString& localName)
4763{
4764 if (!impl)
4765 return QDomAttr();
4766 return QDomAttr(IMPL->attributeNodeNS(nsURI, localName));
4767}
4768
4769/*!
4770 Adds the attribute \a newAttr to this element.
4771
4772 If the element has another attribute that has the same local name
4773 and namespace URI as \a newAttr, this function replaces that
4774 attribute and returns it; otherwise the function returns a
4775 \l{QDomNode::isNull()}{null attribute}.
4776
4777 \sa attributeNodeNS(), setAttributeNS(), setAttributeNode()
4778*/
4779QDomAttr QDomElement::setAttributeNodeNS(const QDomAttr& newAttr)
4780{
4781 if (!impl)
4782 return QDomAttr();
4783 return QDomAttr(IMPL->setAttributeNodeNS(static_cast<QDomAttrPrivate *>(newAttr.impl)));
4784}
4785
4786/*!
4787 Returns a QDomNodeList containing all descendants of this element
4788 with local name \a localName and namespace URI \a nsURI encountered
4789 during a preorder traversal of the element subtree with this element
4790 as its root. The order of the elements in the returned list is the
4791 order they are encountered during the preorder traversal.
4792
4793 \sa elementsByTagName(), QDomDocument::elementsByTagNameNS()
4794*/
4795QDomNodeList QDomElement::elementsByTagNameNS(const QString& nsURI, const QString& localName) const
4796{
4797 return QDomNodeList(new QDomNodeListPrivate(impl, nsURI, localName));
4798}
4799
4800/*!
4801 Returns \c true if this element has an attribute with the local name
4802 \a localName and the namespace URI \a nsURI; otherwise returns
4803 false.
4804*/
4805bool QDomElement::hasAttributeNS(const QString& nsURI, const QString& localName) const
4806{
4807 if (!impl)
4808 return false;
4809 return IMPL->hasAttributeNS(nsURI, localName);
4810}
4811
4812/*!
4813 Returns the element's text or an empty string.
4814
4815 Example:
4816 \snippet code/src_xml_dom_qdom_snippet.cpp 13
4817
4818 The function text() of the QDomElement for the \c{<h1>} tag,
4819 will return the following text:
4820
4821 \snippet code/src_xml_dom_qdom_snippet.cpp 14
4822
4823 Comments are ignored by this function. It only evaluates QDomText
4824 and QDomCDATASection objects.
4825*/
4826QString QDomElement::text() const
4827{
4828 if (!impl)
4829 return QString();
4830 return IMPL->text();
4831}
4832
4833#undef IMPL
4834
4835/**************************************************************
4836 *
4837 * QDomTextPrivate
4838 *
4839 **************************************************************/
4840
4841QDomTextPrivate::QDomTextPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent, const QString& val)
4842 : QDomCharacterDataPrivate(d, parent, val)
4843{
4844 name = u"#text"_s;
4845}
4846
4847QDomTextPrivate::QDomTextPrivate(QDomTextPrivate* n, bool deep)
4848 : QDomCharacterDataPrivate(n, deep)
4849{
4850}
4851
4852QDomNodePrivate* QDomTextPrivate::cloneNode(bool deep)
4853{
4854 QDomNodePrivate* p = new QDomTextPrivate(this, deep);
4855 // We are not interested in this node
4856 p->ref.deref();
4857 return p;
4858}
4859
4860QDomTextPrivate* QDomTextPrivate::splitText(int offset)
4861{
4862 if (!parent()) {
4863 qWarning(msg: "QDomText::splitText The node has no parent. So I cannot split");
4864 return nullptr;
4865 }
4866
4867 QDomTextPrivate* t = new QDomTextPrivate(ownerDocument(), nullptr, value.mid(position: offset));
4868 value.truncate(pos: offset);
4869
4870 parent()->insertAfter(newChild: t, refChild: this);
4871 Q_ASSERT(t->ref.loadRelaxed() == 2);
4872
4873 // We are not interested in this node
4874 t->ref.deref();
4875
4876 return t;
4877}
4878
4879void QDomTextPrivate::save(QTextStream& s, int, int) const
4880{
4881 QDomTextPrivate *that = const_cast<QDomTextPrivate*>(this);
4882 s << encodeText(str: value, encodeQuotes: !(that->parent() && that->parent()->isElement()), performAVN: false, encodeEOLs: true);
4883}
4884
4885/**************************************************************
4886 *
4887 * QDomText
4888 *
4889 **************************************************************/
4890
4891#define IMPL static_cast<QDomTextPrivate *>(impl)
4892
4893/*!
4894 \class QDomText
4895 \reentrant
4896 \brief The QDomText class represents text data in the parsed XML document.
4897
4898 \inmodule QtXml
4899 \ingroup xml-tools
4900
4901 You can split the text in a QDomText object over two QDomText
4902 objects with splitText().
4903
4904 For further information about the Document Object Model see
4905 \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and
4906 \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}.
4907 For a more general introduction of the DOM implementation see the
4908 QDomDocument documentation.
4909*/
4910
4911/*!
4912 Constructs an empty QDomText object.
4913
4914 To construct a QDomText with content, use QDomDocument::createTextNode().
4915*/
4916QDomText::QDomText()
4917 : QDomCharacterData()
4918{
4919}
4920
4921/*!
4922 Constructs a copy of \a text.
4923
4924 The data of the copy is shared (shallow copy): modifying one node
4925 will also change the other. If you want to make a deep copy, use
4926 cloneNode().
4927*/
4928QDomText::QDomText(const QDomText &text)
4929 : QDomCharacterData(text)
4930{
4931}
4932
4933QDomText::QDomText(QDomTextPrivate* n)
4934 : QDomCharacterData(n)
4935{
4936}
4937
4938/*!
4939 Assigns \a other to this DOM text.
4940
4941 The data of the copy is shared (shallow copy): modifying one node
4942 will also change the other. If you want to make a deep copy, use
4943 cloneNode().
4944*/
4945QDomText &QDomText::operator=(const QDomText &other) = default;
4946
4947/*!
4948 \fn QDomNode::NodeType QDomText::nodeType() const
4949
4950 Returns \c TextNode.
4951*/
4952
4953/*!
4954 Splits this DOM text object into two QDomText objects. This object
4955 keeps its first \a offset characters and the second (newly
4956 created) object is inserted into the document tree after this
4957 object with the remaining characters.
4958
4959 The function returns the newly created object.
4960
4961 \sa QDomNode::normalize()
4962*/
4963QDomText QDomText::splitText(int offset)
4964{
4965 if (!impl)
4966 return QDomText();
4967 return QDomText(IMPL->splitText(offset));
4968}
4969
4970#undef IMPL
4971
4972/**************************************************************
4973 *
4974 * QDomCommentPrivate
4975 *
4976 **************************************************************/
4977
4978QDomCommentPrivate::QDomCommentPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent, const QString& val)
4979 : QDomCharacterDataPrivate(d, parent, val)
4980{
4981 name = u"#comment"_s;
4982}
4983
4984QDomCommentPrivate::QDomCommentPrivate(QDomCommentPrivate* n, bool deep)
4985 : QDomCharacterDataPrivate(n, deep)
4986{
4987}
4988
4989
4990QDomNodePrivate* QDomCommentPrivate::cloneNode(bool deep)
4991{
4992 QDomNodePrivate* p = new QDomCommentPrivate(this, deep);
4993 // We are not interested in this node
4994 p->ref.deref();
4995 return p;
4996}
4997
4998void QDomCommentPrivate::save(QTextStream& s, int depth, int indent) const
4999{
5000 /* We don't output whitespace if we would pollute a text node. */
5001 if (!(prev && prev->isText()))
5002 s << QString(indent < 1 ? 0 : depth * indent, u' ');
5003
5004 s << "<!--" << value;
5005 if (value.endsWith(c: u'-'))
5006 s << ' '; // Ensures that XML comment doesn't end with --->
5007 s << "-->";
5008
5009 if (!(next && next->isText()))
5010 s << Qt::endl;
5011}
5012
5013/**************************************************************
5014 *
5015 * QDomComment
5016 *
5017 **************************************************************/
5018
5019/*!
5020 \class QDomComment
5021 \reentrant
5022 \brief The QDomComment class represents an XML comment.
5023
5024 \inmodule QtXml
5025 \ingroup xml-tools
5026
5027 A comment in the parsed XML such as this:
5028
5029 \snippet code/src_xml_dom_qdom_snippet.cpp 15
5030
5031 is represented by QDomComment objects in the parsed Dom tree.
5032
5033 For further information about the Document Object Model see
5034 \l{W3C DOM Level 1}{Level 1} and
5035 \l{W3C DOM Level 2}{Level 2 Core}.
5036 For a more general introduction of the DOM implementation see the
5037 QDomDocument documentation.
5038*/
5039
5040/*!
5041 Constructs an empty comment. To construct a comment with content,
5042 use the QDomDocument::createComment() function.
5043*/
5044QDomComment::QDomComment()
5045 : QDomCharacterData()
5046{
5047}
5048
5049/*!
5050 Constructs a copy of \a comment.
5051
5052 The data of the copy is shared (shallow copy): modifying one node
5053 will also change the other. If you want to make a deep copy, use
5054 cloneNode().
5055*/
5056QDomComment::QDomComment(const QDomComment &comment)
5057 : QDomCharacterData(comment)
5058{
5059}
5060
5061QDomComment::QDomComment(QDomCommentPrivate* n)
5062 : QDomCharacterData(n)
5063{
5064}
5065
5066/*!
5067 Assigns \a other to this DOM comment.
5068
5069 The data of the copy is shared (shallow copy): modifying one node
5070 will also change the other. If you want to make a deep copy, use
5071 cloneNode().
5072*/
5073QDomComment &QDomComment::operator=(const QDomComment &other) = default;
5074
5075/*!
5076 \fn QDomNode::NodeType QDomComment::nodeType() const
5077
5078 Returns \c CommentNode.
5079*/
5080
5081/**************************************************************
5082 *
5083 * QDomCDATASectionPrivate
5084 *
5085 **************************************************************/
5086
5087QDomCDATASectionPrivate::QDomCDATASectionPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent,
5088 const QString& val)
5089 : QDomTextPrivate(d, parent, val)
5090{
5091 name = u"#cdata-section"_s;
5092}
5093
5094QDomCDATASectionPrivate::QDomCDATASectionPrivate(QDomCDATASectionPrivate* n, bool deep)
5095 : QDomTextPrivate(n, deep)
5096{
5097}
5098
5099QDomNodePrivate* QDomCDATASectionPrivate::cloneNode(bool deep)
5100{
5101 QDomNodePrivate* p = new QDomCDATASectionPrivate(this, deep);
5102 // We are not interested in this node
5103 p->ref.deref();
5104 return p;
5105}
5106
5107void QDomCDATASectionPrivate::save(QTextStream& s, int, int) const
5108{
5109 // ### How do we escape "]]>" ?
5110 // "]]>" is not allowed; so there should be none in value anyway
5111 s << "<![CDATA[" << value << "]]>";
5112}
5113
5114/**************************************************************
5115 *
5116 * QDomCDATASection
5117 *
5118 **************************************************************/
5119
5120/*!
5121 \class QDomCDATASection
5122 \reentrant
5123 \brief The QDomCDATASection class represents an XML CDATA section.
5124
5125 \inmodule QtXml
5126 \ingroup xml-tools
5127
5128 CDATA sections are used to escape blocks of text containing
5129 characters that would otherwise be regarded as markup. The only
5130 delimiter that is recognized in a CDATA section is the "]]&gt;"
5131 string that terminates the CDATA section. CDATA sections cannot be
5132 nested. Their primary purpose is for including material such as
5133 XML fragments, without needing to escape all the delimiters.
5134
5135 Adjacent QDomCDATASection nodes are not merged by the
5136 QDomNode::normalize() function.
5137
5138 For further information about the Document Object Model see
5139 \l{http://www.w3.org/TR/REC-DOM-Level-1/} and
5140 \l{http://www.w3.org/TR/DOM-Level-2-Core/}.
5141 For a more general introduction of the DOM implementation see the
5142 QDomDocument documentation.
5143*/
5144
5145/*!
5146 Constructs an empty CDATA section. To create a CDATA section with
5147 content, use the QDomDocument::createCDATASection() function.
5148*/
5149QDomCDATASection::QDomCDATASection()
5150 : QDomText()
5151{
5152}
5153
5154/*!
5155 Constructs a copy of \a cdataSection.
5156
5157 The data of the copy is shared (shallow copy): modifying one node
5158 will also change the other. If you want to make a deep copy, use
5159 cloneNode().
5160*/
5161QDomCDATASection::QDomCDATASection(const QDomCDATASection &cdataSection)
5162 : QDomText(cdataSection)
5163{
5164}
5165
5166QDomCDATASection::QDomCDATASection(QDomCDATASectionPrivate* n)
5167 : QDomText(n)
5168{
5169}
5170
5171/*!
5172 Assigns \a other to this CDATA section.
5173
5174 The data of the copy is shared (shallow copy): modifying one node
5175 will also change the other. If you want to make a deep copy, use
5176 cloneNode().
5177*/
5178QDomCDATASection &QDomCDATASection::operator=(const QDomCDATASection &other) = default;
5179
5180/*!
5181 \fn QDomNode::NodeType QDomCDATASection::nodeType() const
5182
5183 Returns \c CDATASection.
5184*/
5185
5186/**************************************************************
5187 *
5188 * QDomNotationPrivate
5189 *
5190 **************************************************************/
5191
5192QDomNotationPrivate::QDomNotationPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent,
5193 const QString& aname,
5194 const QString& pub, const QString& sys)
5195 : QDomNodePrivate(d, parent)
5196{
5197 name = aname;
5198 m_pub = pub;
5199 m_sys = sys;
5200}
5201
5202QDomNotationPrivate::QDomNotationPrivate(QDomNotationPrivate* n, bool deep)
5203 : QDomNodePrivate(n, deep)
5204{
5205 m_sys = n->m_sys;
5206 m_pub = n->m_pub;
5207}
5208
5209QDomNodePrivate* QDomNotationPrivate::cloneNode(bool deep)
5210{
5211 QDomNodePrivate* p = new QDomNotationPrivate(this, deep);
5212 // We are not interested in this node
5213 p->ref.deref();
5214 return p;
5215}
5216
5217void QDomNotationPrivate::save(QTextStream& s, int, int) const
5218{
5219 s << "<!NOTATION " << name << ' ';
5220 if (!m_pub.isNull()) {
5221 s << "PUBLIC " << quotedValue(data: m_pub);
5222 if (!m_sys.isNull())
5223 s << ' ' << quotedValue(data: m_sys);
5224 } else {
5225 s << "SYSTEM " << quotedValue(data: m_sys);
5226 }
5227 s << '>' << Qt::endl;
5228}
5229
5230/**************************************************************
5231 *
5232 * QDomNotation
5233 *
5234 **************************************************************/
5235
5236#define IMPL static_cast<QDomNotationPrivate *>(impl)
5237
5238/*!
5239 \class QDomNotation
5240 \reentrant
5241 \brief The QDomNotation class represents an XML notation.
5242
5243 \inmodule QtXml
5244 \ingroup xml-tools
5245
5246 A notation either declares, by name, the format of an unparsed
5247 entity (see section 4.7 of the XML 1.0 specification), or is used
5248 for formal declaration of processing instruction targets (see
5249 section 2.6 of the XML 1.0 specification).
5250
5251 DOM does not support editing notation nodes; they are therefore
5252 read-only.
5253
5254 A notation node does not have any parent.
5255
5256 You can retrieve the publicId() and systemId() from a notation
5257 node.
5258
5259 For further information about the Document Object Model see
5260 \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and
5261 \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}.
5262 For a more general introduction of the DOM implementation see the
5263 QDomDocument documentation.
5264*/
5265
5266
5267/*!
5268 Constructor.
5269*/
5270QDomNotation::QDomNotation()
5271 : QDomNode()
5272{
5273}
5274
5275/*!
5276 Constructs a copy of \a notation.
5277
5278 The data of the copy is shared (shallow copy): modifying one node
5279 will also change the other. If you want to make a deep copy, use
5280 cloneNode().
5281*/
5282QDomNotation::QDomNotation(const QDomNotation &notation)
5283 : QDomNode(notation)
5284{
5285}
5286
5287QDomNotation::QDomNotation(QDomNotationPrivate* n)
5288 : QDomNode(n)
5289{
5290}
5291
5292/*!
5293 Assigns \a other to this DOM notation.
5294
5295 The data of the copy is shared (shallow copy): modifying one node
5296 will also change the other. If you want to make a deep copy, use
5297 cloneNode().
5298*/
5299QDomNotation &QDomNotation::operator=(const QDomNotation &other) = default;
5300
5301/*!
5302 \fn QDomNode::NodeType QDomNotation::nodeType() const
5303
5304 Returns \c NotationNode.
5305*/
5306
5307/*!
5308 Returns the public identifier of this notation.
5309*/
5310QString QDomNotation::publicId() const
5311{
5312 if (!impl)
5313 return QString();
5314 return IMPL->m_pub;
5315}
5316
5317/*!
5318 Returns the system identifier of this notation.
5319*/
5320QString QDomNotation::systemId() const
5321{
5322 if (!impl)
5323 return QString();
5324 return IMPL->m_sys;
5325}
5326
5327#undef IMPL
5328
5329/**************************************************************
5330 *
5331 * QDomEntityPrivate
5332 *
5333 **************************************************************/
5334
5335QDomEntityPrivate::QDomEntityPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent,
5336 const QString& aname,
5337 const QString& pub, const QString& sys, const QString& notation)
5338 : QDomNodePrivate(d, parent)
5339{
5340 name = aname;
5341 m_pub = pub;
5342 m_sys = sys;
5343 m_notationName = notation;
5344}
5345
5346QDomEntityPrivate::QDomEntityPrivate(QDomEntityPrivate* n, bool deep)
5347 : QDomNodePrivate(n, deep)
5348{
5349 m_sys = n->m_sys;
5350 m_pub = n->m_pub;
5351 m_notationName = n->m_notationName;
5352}
5353
5354QDomNodePrivate* QDomEntityPrivate::cloneNode(bool deep)
5355{
5356 QDomNodePrivate* p = new QDomEntityPrivate(this, deep);
5357 // We are not interested in this node
5358 p->ref.deref();
5359 return p;
5360}
5361
5362/*
5363 Encode an entity value upon saving.
5364*/
5365static QByteArray encodeEntity(const QByteArray& str)
5366{
5367 QByteArray tmp(str);
5368 int len = tmp.size();
5369 int i = 0;
5370 const char* d = tmp.constData();
5371 while (i < len) {
5372 if (d[i] == '%'){
5373 tmp.replace(index: i, len: 1, s: "&#60;");
5374 d = tmp.constData();
5375 len += 4;
5376 i += 5;
5377 }
5378 else if (d[i] == '"') {
5379 tmp.replace(index: i, len: 1, s: "&#34;");
5380 d = tmp.constData();
5381 len += 4;
5382 i += 5;
5383 } else if (d[i] == '&' && i + 1 < len && d[i+1] == '#') {
5384 // Don't encode &lt; or &quot; or &custom;.
5385 // Only encode character references
5386 tmp.replace(index: i, len: 1, s: "&#38;");
5387 d = tmp.constData();
5388 len += 4;
5389 i += 5;
5390 } else {
5391 ++i;
5392 }
5393 }
5394
5395 return tmp;
5396}
5397
5398void QDomEntityPrivate::save(QTextStream& s, int, int) const
5399{
5400 QString _name = name;
5401 if (_name.startsWith(c: u'%'))
5402 _name = u"% "_s + _name.mid(position: 1);
5403
5404 if (m_sys.isNull() && m_pub.isNull()) {
5405 s << "<!ENTITY " << _name << " \"" << encodeEntity(str: value.toUtf8()) << "\">" << Qt::endl;
5406 } else {
5407 s << "<!ENTITY " << _name << ' ';
5408 if (m_pub.isNull()) {
5409 s << "SYSTEM " << quotedValue(data: m_sys);
5410 } else {
5411 s << "PUBLIC " << quotedValue(data: m_pub) << ' ' << quotedValue(data: m_sys);
5412 }
5413 if (! m_notationName.isNull()) {
5414 s << " NDATA " << m_notationName;
5415 }
5416 s << '>' << Qt::endl;
5417 }
5418}
5419
5420/**************************************************************
5421 *
5422 * QDomEntity
5423 *
5424 **************************************************************/
5425
5426#define IMPL static_cast<QDomEntityPrivate *>(impl)
5427
5428/*!
5429 \class QDomEntity
5430 \reentrant
5431 \brief The QDomEntity class represents an XML entity.
5432
5433 \inmodule QtXml
5434 \ingroup xml-tools
5435
5436 This class represents an entity in an XML document, either parsed
5437 or unparsed. Note that this models the entity itself not the
5438 entity declaration.
5439
5440 DOM does not support editing entity nodes; if a user wants to make
5441 changes to the contents of an entity, every related
5442 QDomEntityReference node must be replaced in the DOM tree by a
5443 clone of the entity's contents, and then the desired changes must
5444 be made to each of the clones instead. All the descendants of an
5445 entity node are read-only.
5446
5447 An entity node does not have any parent.
5448
5449 You can access the entity's publicId(), systemId() and
5450 notationName() when available.
5451
5452 For further information about the Document Object Model see
5453 \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and
5454 \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}.
5455 For a more general introduction of the DOM implementation see the
5456 QDomDocument documentation.
5457*/
5458
5459
5460/*!
5461 Constructs an empty entity.
5462*/
5463QDomEntity::QDomEntity()
5464 : QDomNode()
5465{
5466}
5467
5468
5469/*!
5470 Constructs a copy of \a entity.
5471
5472 The data of the copy is shared (shallow copy): modifying one node
5473 will also change the other. If you want to make a deep copy, use
5474 cloneNode().
5475*/
5476QDomEntity::QDomEntity(const QDomEntity &entity)
5477 : QDomNode(entity)
5478{
5479}
5480
5481QDomEntity::QDomEntity(QDomEntityPrivate* n)
5482 : QDomNode(n)
5483{
5484}
5485
5486/*!
5487 Assigns \a other to this DOM entity.
5488
5489 The data of the copy is shared (shallow copy): modifying one node
5490 will also change the other. If you want to make a deep copy, use
5491 cloneNode().
5492*/
5493QDomEntity &QDomEntity::operator=(const QDomEntity &other) = default;
5494
5495/*!
5496 \fn QDomNode::NodeType QDomEntity::nodeType() const
5497
5498 Returns \c EntityNode.
5499*/
5500
5501/*!
5502 Returns the public identifier associated with this entity. If the
5503 public identifier was not specified an empty string is returned.
5504*/
5505QString QDomEntity::publicId() const
5506{
5507 if (!impl)
5508 return QString();
5509 return IMPL->m_pub;
5510}
5511
5512/*!
5513 Returns the system identifier associated with this entity. If the
5514 system identifier was not specified an empty string is returned.
5515*/
5516QString QDomEntity::systemId() const
5517{
5518 if (!impl)
5519 return QString();
5520 return IMPL->m_sys;
5521}
5522
5523/*!
5524 For unparsed entities this function returns the name of the
5525 notation for the entity. For parsed entities this function returns
5526 an empty string.
5527*/
5528QString QDomEntity::notationName() const
5529{
5530 if (!impl)
5531 return QString();
5532 return IMPL->m_notationName;
5533}
5534
5535#undef IMPL
5536
5537/**************************************************************
5538 *
5539 * QDomEntityReferencePrivate
5540 *
5541 **************************************************************/
5542
5543QDomEntityReferencePrivate::QDomEntityReferencePrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent, const QString& aname)
5544 : QDomNodePrivate(d, parent)
5545{
5546 name = aname;
5547}
5548
5549QDomEntityReferencePrivate::QDomEntityReferencePrivate(QDomNodePrivate* n, bool deep)
5550 : QDomNodePrivate(n, deep)
5551{
5552}
5553
5554QDomNodePrivate* QDomEntityReferencePrivate::cloneNode(bool deep)
5555{
5556 QDomNodePrivate* p = new QDomEntityReferencePrivate(this, deep);
5557 // We are not interested in this node
5558 p->ref.deref();
5559 return p;
5560}
5561
5562void QDomEntityReferencePrivate::save(QTextStream& s, int, int) const
5563{
5564 s << '&' << name << ';';
5565}
5566
5567/**************************************************************
5568 *
5569 * QDomEntityReference
5570 *
5571 **************************************************************/
5572
5573/*!
5574 \class QDomEntityReference
5575 \reentrant
5576 \brief The QDomEntityReference class represents an XML entity reference.
5577
5578 \inmodule QtXml
5579 \ingroup xml-tools
5580
5581 A QDomEntityReference object may be inserted into the DOM tree
5582 when an entity reference is in the source document, or when the
5583 user wishes to insert an entity reference.
5584
5585 Note that character references and references to predefined
5586 entities are expanded by the XML processor so that characters are
5587 represented by their Unicode equivalent rather than by an entity
5588 reference.
5589
5590 Moreover, the XML processor may completely expand references to
5591 entities while building the DOM tree, instead of providing
5592 QDomEntityReference objects.
5593
5594 If it does provide such objects, then for a given entity reference
5595 node, it may be that there is no entity node representing the
5596 referenced entity; but if such an entity exists, then the child
5597 list of the entity reference node is the same as that of the
5598 entity node. As with the entity node, all descendants of the
5599 entity reference are read-only.
5600
5601 For further information about the Document Object Model see
5602 \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and
5603 \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}.
5604 For a more general introduction of the DOM implementation see the
5605 QDomDocument documentation.
5606*/
5607
5608/*!
5609 Constructs an empty entity reference. Use
5610 QDomDocument::createEntityReference() to create a entity reference
5611 with content.
5612*/
5613QDomEntityReference::QDomEntityReference()
5614 : QDomNode()
5615{
5616}
5617
5618/*!
5619 Constructs a copy of \a entityReference.
5620
5621 The data of the copy is shared (shallow copy): modifying one node
5622 will also change the other. If you want to make a deep copy, use
5623 cloneNode().
5624*/
5625QDomEntityReference::QDomEntityReference(const QDomEntityReference &entityReference)
5626 : QDomNode(entityReference)
5627{
5628}
5629
5630QDomEntityReference::QDomEntityReference(QDomEntityReferencePrivate* n)
5631 : QDomNode(n)
5632{
5633}
5634
5635/*!
5636 Assigns \a other to this entity reference.
5637
5638 The data of the copy is shared (shallow copy): modifying one node
5639 will also change the other. If you want to make a deep copy, use
5640 cloneNode().
5641*/
5642QDomEntityReference &QDomEntityReference::operator=(const QDomEntityReference &other) = default;
5643
5644/*!
5645 \fn QDomNode::NodeType QDomEntityReference::nodeType() const
5646
5647 Returns \c EntityReference.
5648*/
5649
5650/**************************************************************
5651 *
5652 * QDomProcessingInstructionPrivate
5653 *
5654 **************************************************************/
5655
5656QDomProcessingInstructionPrivate::QDomProcessingInstructionPrivate(QDomDocumentPrivate* d,
5657 QDomNodePrivate* parent, const QString& target, const QString& data)
5658 : QDomNodePrivate(d, parent)
5659{
5660 name = target;
5661 value = data;
5662}
5663
5664QDomProcessingInstructionPrivate::QDomProcessingInstructionPrivate(QDomProcessingInstructionPrivate* n, bool deep)
5665 : QDomNodePrivate(n, deep)
5666{
5667}
5668
5669
5670QDomNodePrivate* QDomProcessingInstructionPrivate::cloneNode(bool deep)
5671{
5672 QDomNodePrivate* p = new QDomProcessingInstructionPrivate(this, deep);
5673 // We are not interested in this node
5674 p->ref.deref();
5675 return p;
5676}
5677
5678void QDomProcessingInstructionPrivate::save(QTextStream& s, int, int) const
5679{
5680 s << "<?" << name << ' ' << value << "?>" << Qt::endl;
5681}
5682
5683/**************************************************************
5684 *
5685 * QDomProcessingInstruction
5686 *
5687 **************************************************************/
5688
5689/*!
5690 \class QDomProcessingInstruction
5691 \reentrant
5692 \brief The QDomProcessingInstruction class represents an XML processing
5693 instruction.
5694
5695 \inmodule QtXml
5696 \ingroup xml-tools
5697
5698 Processing instructions are used in XML to keep processor-specific
5699 information in the text of the document.
5700
5701 The XML declaration that appears at the top of an XML document,
5702 typically \tt{<?xml version='1.0' encoding='UTF-8'?>}, is treated by QDom as a
5703 processing instruction. This is unfortunate, since the XML declaration is
5704 not a processing instruction; among other differences, it cannot be
5705 inserted into a document anywhere but on the first line.
5706
5707 \note Do not use this function to create an XML declaration. Although the
5708 XML declaration shares the same syntax as a processing instruction, it
5709 is not one. According to the
5710 \l{https://www.w3.org/TR/xml/#sec-prolog-dtd}{XML 1.0 Specification} and the
5711 \l{https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-1590626202}{W3C DOM Structure Model},
5712 the XML declaration is part of the document prolog and not part of the
5713 DOM tree - meaning it should not be represented as a DOM node and cannot be
5714 created or inserted via the DOM API.
5715 If you need to generate a well-formed XML document that includes an XML
5716 declaration, use QXmlStreamWriter, which provides proper support for
5717 writing the declaration through \l {QXmlStreamWriter::}{writeStartDocument}.
5718
5719 The content of the processing instruction is retrieved with data()
5720 and set with setData(). The processing instruction's target is
5721 retrieved with target().
5722
5723 For further information about the Document Object Model see
5724 \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and
5725 \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}.
5726 For a more general introduction of the DOM implementation see the
5727 QDomDocument documentation.
5728*/
5729
5730/*!
5731 Constructs an empty processing instruction. Use
5732 QDomDocument::createProcessingInstruction() to create a processing
5733 instruction with content.
5734*/
5735QDomProcessingInstruction::QDomProcessingInstruction()
5736 : QDomNode()
5737{
5738}
5739
5740/*!
5741 Constructs a copy of \a processingInstruction.
5742
5743 The data of the copy is shared (shallow copy): modifying one node
5744 will also change the other. If you want to make a deep copy, use
5745 cloneNode().
5746*/
5747QDomProcessingInstruction::QDomProcessingInstruction(const QDomProcessingInstruction &processingInstruction)
5748 : QDomNode(processingInstruction)
5749{
5750}
5751
5752QDomProcessingInstruction::QDomProcessingInstruction(QDomProcessingInstructionPrivate* n)
5753 : QDomNode(n)
5754{
5755}
5756
5757/*!
5758 Assigns \a other to this processing instruction.
5759
5760 The data of the copy is shared (shallow copy): modifying one node
5761 will also change the other. If you want to make a deep copy, use
5762 cloneNode().
5763*/
5764QDomProcessingInstruction &
5765QDomProcessingInstruction::operator=(const QDomProcessingInstruction &other) = default;
5766
5767/*!
5768 \fn QDomNode::NodeType QDomProcessingInstruction::nodeType() const
5769
5770 Returns \c ProcessingInstructionNode.
5771*/
5772
5773/*!
5774 Returns the target of this processing instruction.
5775
5776 \sa data()
5777*/
5778QString QDomProcessingInstruction::target() const
5779{
5780 if (!impl)
5781 return QString();
5782 return impl->nodeName();
5783}
5784
5785/*!
5786 Returns the content of this processing instruction.
5787
5788 \sa setData(), target()
5789*/
5790QString QDomProcessingInstruction::data() const
5791{
5792 if (!impl)
5793 return QString();
5794 return impl->nodeValue();
5795}
5796
5797/*!
5798 Sets the data contained in the processing instruction to \a data.
5799
5800 \sa data()
5801*/
5802void QDomProcessingInstruction::setData(const QString &data)
5803{
5804 if (impl)
5805 impl->setNodeValue(data);
5806}
5807
5808/**************************************************************
5809 *
5810 * QDomDocumentPrivate
5811 *
5812 **************************************************************/
5813
5814QDomDocumentPrivate::QDomDocumentPrivate()
5815 : QDomNodePrivate(nullptr),
5816 impl(new QDomImplementationPrivate),
5817 nodeListTime(1)
5818{
5819 type = new QDomDocumentTypePrivate(this, this);
5820 type->ref.deref();
5821
5822 name = u"#document"_s;
5823}
5824
5825QDomDocumentPrivate::QDomDocumentPrivate(const QString& aname)
5826 : QDomNodePrivate(nullptr),
5827 impl(new QDomImplementationPrivate),
5828 nodeListTime(1)
5829{
5830 type = new QDomDocumentTypePrivate(this, this);
5831 type->ref.deref();
5832 type->name = aname;
5833
5834 name = u"#document"_s;
5835}
5836
5837QDomDocumentPrivate::QDomDocumentPrivate(QDomDocumentTypePrivate* dt)
5838 : QDomNodePrivate(nullptr),
5839 impl(new QDomImplementationPrivate),
5840 nodeListTime(1)
5841{
5842 if (dt != nullptr) {
5843 type = dt;
5844 } else {
5845 type = new QDomDocumentTypePrivate(this, this);
5846 type->ref.deref();
5847 }
5848
5849 name = u"#document"_s;
5850}
5851
5852QDomDocumentPrivate::QDomDocumentPrivate(QDomDocumentPrivate* n, bool deep)
5853 : QDomNodePrivate(n, deep),
5854 impl(n->impl->clone()),
5855 nodeListTime(1)
5856{
5857 type = static_cast<QDomDocumentTypePrivate*>(n->type->cloneNode());
5858 type->setParent(this);
5859}
5860
5861QDomDocumentPrivate::~QDomDocumentPrivate()
5862{
5863}
5864
5865void QDomDocumentPrivate::clear()
5866{
5867 impl.reset();
5868 type.reset();
5869 QDomNodePrivate::clear();
5870}
5871
5872QDomDocument::ParseResult QDomDocumentPrivate::setContent(QXmlStreamReader *reader,
5873 QDomDocument::ParseOptions options)
5874{
5875 clear();
5876 impl = new QDomImplementationPrivate;
5877 type = new QDomDocumentTypePrivate(this, this);
5878 type->ref.deref();
5879
5880 if (!reader) {
5881 const auto error = u"Failed to set content, XML reader is not initialized"_s;
5882 qWarning(msg: "%s", qPrintable(error));
5883 return { .errorMessage: error };
5884 }
5885
5886 QDomParser domParser(this, reader, options);
5887
5888 if (!domParser.parse())
5889 return domParser.result();
5890 return {};
5891}
5892
5893QDomNodePrivate* QDomDocumentPrivate::cloneNode(bool deep)
5894{
5895 QDomNodePrivate *p = new QDomDocumentPrivate(this, deep);
5896 // We are not interested in this node
5897 p->ref.deref();
5898 return p;
5899}
5900
5901QDomElementPrivate* QDomDocumentPrivate::documentElement()
5902{
5903 QDomNodePrivate *p = first;
5904 while (p && !p->isElement())
5905 p = p->next;
5906
5907 return static_cast<QDomElementPrivate *>(p);
5908}
5909
5910QDomElementPrivate* QDomDocumentPrivate::createElement(const QString &tagName)
5911{
5912 bool ok;
5913 QString fixedName = fixedXmlName(name: tagName, ok: &ok);
5914 if (!ok)
5915 return nullptr;
5916
5917 QDomElementPrivate *e = new QDomElementPrivate(this, nullptr, fixedName);
5918 e->ref.deref();
5919 return e;
5920}
5921
5922QDomElementPrivate* QDomDocumentPrivate::createElementNS(const QString &nsURI, const QString &qName)
5923{
5924 bool ok;
5925 QString fixedName = fixedXmlName(name: qName, ok: &ok, namespaces: true);
5926 if (!ok)
5927 return nullptr;
5928
5929 QDomElementPrivate *e = new QDomElementPrivate(this, nullptr, nsURI, fixedName);
5930 e->ref.deref();
5931 return e;
5932}
5933
5934QDomDocumentFragmentPrivate* QDomDocumentPrivate::createDocumentFragment()
5935{
5936 QDomDocumentFragmentPrivate *f = new QDomDocumentFragmentPrivate(this, nullptr);
5937 f->ref.deref();
5938 return f;
5939}
5940
5941QDomTextPrivate* QDomDocumentPrivate::createTextNode(const QString &data)
5942{
5943 bool ok;
5944 QString fixedData = fixedCharData(data, ok: &ok);
5945 if (!ok)
5946 return nullptr;
5947
5948 QDomTextPrivate *t = new QDomTextPrivate(this, nullptr, fixedData);
5949 t->ref.deref();
5950 return t;
5951}
5952
5953QDomCommentPrivate* QDomDocumentPrivate::createComment(const QString &data)
5954{
5955 bool ok;
5956 QString fixedData = fixedComment(data, ok: &ok);
5957 if (!ok)
5958 return nullptr;
5959
5960 QDomCommentPrivate *c = new QDomCommentPrivate(this, nullptr, fixedData);
5961 c->ref.deref();
5962 return c;
5963}
5964
5965QDomCDATASectionPrivate* QDomDocumentPrivate::createCDATASection(const QString &data)
5966{
5967 bool ok;
5968 QString fixedData = fixedCDataSection(data, ok: &ok);
5969 if (!ok)
5970 return nullptr;
5971
5972 QDomCDATASectionPrivate *c = new QDomCDATASectionPrivate(this, nullptr, fixedData);
5973 c->ref.deref();
5974 return c;
5975}
5976
5977QDomProcessingInstructionPrivate* QDomDocumentPrivate::createProcessingInstruction(const QString &target,
5978 const QString &data)
5979{
5980 bool ok;
5981 QString fixedData = fixedPIData(data, ok: &ok);
5982 if (!ok)
5983 return nullptr;
5984 // [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
5985 QString fixedTarget = fixedXmlName(name: target, ok: &ok);
5986 if (!ok)
5987 return nullptr;
5988
5989 QDomProcessingInstructionPrivate *p = new QDomProcessingInstructionPrivate(this, nullptr, fixedTarget, fixedData);
5990 p->ref.deref();
5991 return p;
5992}
5993QDomAttrPrivate* QDomDocumentPrivate::createAttribute(const QString &aname)
5994{
5995 bool ok;
5996 QString fixedName = fixedXmlName(name: aname, ok: &ok);
5997 if (!ok)
5998 return nullptr;
5999
6000 QDomAttrPrivate *a = new QDomAttrPrivate(this, nullptr, fixedName);
6001 a->ref.deref();
6002 return a;
6003}
6004
6005QDomAttrPrivate* QDomDocumentPrivate::createAttributeNS(const QString &nsURI, const QString &qName)
6006{
6007 bool ok;
6008 QString fixedName = fixedXmlName(name: qName, ok: &ok, namespaces: true);
6009 if (!ok)
6010 return nullptr;
6011
6012 QDomAttrPrivate *a = new QDomAttrPrivate(this, nullptr, nsURI, fixedName);
6013 a->ref.deref();
6014 return a;
6015}
6016
6017QDomEntityReferencePrivate* QDomDocumentPrivate::createEntityReference(const QString &aname)
6018{
6019 bool ok;
6020 QString fixedName = fixedXmlName(name: aname, ok: &ok);
6021 if (!ok)
6022 return nullptr;
6023
6024 QDomEntityReferencePrivate *e = new QDomEntityReferencePrivate(this, nullptr, fixedName);
6025 e->ref.deref();
6026 return e;
6027}
6028
6029QDomNodePrivate* QDomDocumentPrivate::importNode(QDomNodePrivate *importedNode, bool deep)
6030{
6031 QDomNodePrivate *node = nullptr;
6032 switch (importedNode->nodeType()) {
6033 case QDomNode::AttributeNode:
6034 node = new QDomAttrPrivate(static_cast<QDomAttrPrivate *>(importedNode), true);
6035 break;
6036 case QDomNode::DocumentFragmentNode:
6037 node = new QDomDocumentFragmentPrivate(
6038 static_cast<QDomDocumentFragmentPrivate *>(importedNode), deep);
6039 break;
6040 case QDomNode::ElementNode:
6041 node = new QDomElementPrivate(static_cast<QDomElementPrivate *>(importedNode), deep);
6042 break;
6043 case QDomNode::EntityNode:
6044 node = new QDomEntityPrivate(static_cast<QDomEntityPrivate *>(importedNode), deep);
6045 break;
6046 case QDomNode::EntityReferenceNode:
6047 node = new QDomEntityReferencePrivate(
6048 static_cast<QDomEntityReferencePrivate *>(importedNode), false);
6049 break;
6050 case QDomNode::NotationNode:
6051 node = new QDomNotationPrivate(static_cast<QDomNotationPrivate *>(importedNode), deep);
6052 break;
6053 case QDomNode::ProcessingInstructionNode:
6054 node = new QDomProcessingInstructionPrivate(
6055 static_cast<QDomProcessingInstructionPrivate *>(importedNode), deep);
6056 break;
6057 case QDomNode::TextNode:
6058 node = new QDomTextPrivate(static_cast<QDomTextPrivate *>(importedNode), deep);
6059 break;
6060 case QDomNode::CDATASectionNode:
6061 node = new QDomCDATASectionPrivate(static_cast<QDomCDATASectionPrivate *>(importedNode),
6062 deep);
6063 break;
6064 case QDomNode::CommentNode:
6065 node = new QDomCommentPrivate(static_cast<QDomCommentPrivate *>(importedNode), deep);
6066 break;
6067 default:
6068 break;
6069 }
6070 if (node) {
6071 node->setOwnerDocument(this);
6072 // The QDomNode constructor increases the refcount, so deref first to
6073 // keep refcount balanced.
6074 node->ref.deref();
6075 }
6076 return node;
6077}
6078
6079void QDomDocumentPrivate::saveDocument(QTextStream& s, const int indent, QDomNode::EncodingPolicy encUsed) const
6080{
6081 const QDomNodePrivate* n = first;
6082
6083 if (encUsed == QDomNode::EncodingFromDocument) {
6084#if QT_CONFIG(regularexpression)
6085 const QDomNodePrivate* n = first;
6086
6087 if (n && n->isProcessingInstruction() && n->nodeName() == "xml"_L1) {
6088 // we have an XML declaration
6089 QString data = n->nodeValue();
6090 QRegularExpression encoding(QString::fromLatin1(ba: "encoding\\s*=\\s*((\"([^\"]*)\")|('([^']*)'))"));
6091 auto match = encoding.match(subject: data);
6092 QString enc = match.captured(nth: 3);
6093 if (enc.isEmpty())
6094 enc = match.captured(nth: 5);
6095 if (!enc.isEmpty()) {
6096 auto encoding = QStringConverter::encodingForName(name: enc.toUtf8().constData());
6097 if (!encoding)
6098 qWarning() << "QDomDocument::save(): Unsupported encoding" << enc << "specified.";
6099 else
6100 s.setEncoding(encoding.value());
6101 }
6102 }
6103#endif
6104 bool doc = false;
6105
6106 while (n) {
6107 if (!doc && !(n->isProcessingInstruction() && n->nodeName() == "xml"_L1)) {
6108 // save doctype after XML declaration
6109 type->save(s, 0, indent);
6110 doc = true;
6111 }
6112 n->saveSubTree(n, s, depth: 0, indent);
6113 n = n->next;
6114 }
6115 }
6116 else {
6117
6118 // Write out the XML declaration.
6119 const QByteArray codecName = QStringConverter::nameForEncoding(e: s.encoding());
6120
6121 s << "<?xml version=\"1.0\" encoding=\""
6122 << codecName
6123 << "\"?>\n";
6124
6125 // Skip the first processing instruction by name "xml", if any such exists.
6126 const QDomNodePrivate* startNode = n;
6127
6128 // First, we try to find the PI and sets the startNode to the one appearing after it.
6129 while (n) {
6130 if (n->isProcessingInstruction() && n->nodeName() == "xml"_L1) {
6131 startNode = n->next;
6132 break;
6133 }
6134 else
6135 n = n->next;
6136 }
6137
6138 // Now we serialize all the nodes after the faked XML declaration(the PI).
6139 while (startNode) {
6140 startNode->saveSubTree(n: startNode, s, depth: 0, indent);
6141 startNode = startNode->next;
6142 }
6143 }
6144}
6145
6146/**************************************************************
6147 *
6148 * QDomDocument
6149 *
6150 **************************************************************/
6151
6152#define IMPL static_cast<QDomDocumentPrivate *>(impl)
6153
6154/*!
6155 \class QDomDocument
6156 \reentrant
6157 \brief The QDomDocument class represents an XML document.
6158
6159 \inmodule QtXml
6160
6161 \ingroup xml-tools
6162
6163 The QDomDocument class represents the entire XML document.
6164 Conceptually, it is the root of the document tree, and provides
6165 the primary access to the document's data.
6166
6167 Since elements, text nodes, comments, processing instructions,
6168 etc., cannot exist outside the context of a document, the document
6169 class also contains the factory functions needed to create these
6170 objects. The node objects created have an ownerDocument() function
6171 which associates them with the document within whose context they
6172 were created. The DOM classes that will be used most often are
6173 QDomNode, QDomDocument, QDomElement and QDomText.
6174
6175 The parsed XML is represented internally by a tree of objects that
6176 can be accessed using the various QDom classes. All QDom classes
6177 only \e reference objects in the internal tree. The internal
6178 objects in the DOM tree will get deleted once the last QDom
6179 object referencing them or the QDomDocument itself is deleted.
6180
6181 Creation of elements, text nodes, etc. is done using the various
6182 factory functions provided in this class. Using the default
6183 constructors of the QDom classes will only result in empty
6184 objects that cannot be manipulated or inserted into the Document.
6185
6186 The QDomDocument class has several functions for creating document
6187 data, for example, createElement(), createTextNode(),
6188 createComment(), createCDATASection(),
6189 createProcessingInstruction(), createAttribute() and
6190 createEntityReference(). Some of these functions have versions
6191 that support namespaces, i.e. createElementNS() and
6192 createAttributeNS(). The createDocumentFragment() function is used
6193 to hold parts of the document; this is useful for manipulating for
6194 complex documents.
6195
6196 The entire content of the document is set with setContent(). This
6197 function parses the string it is passed as an XML document and
6198 creates the DOM tree that represents the document. The root
6199 element is available using documentElement(). The textual
6200 representation of the document can be obtained using toString().
6201
6202 \note The DOM tree might end up reserving a lot of memory if the XML
6203 document is big. For such documents, the QXmlStreamReader class
6204 might be a better solution.
6205
6206 It is possible to insert a node from another document into the
6207 document using importNode().
6208
6209 You can obtain a list of all the elements that have a particular
6210 tag with elementsByTagName() or with elementsByTagNameNS().
6211
6212 The QDom classes are typically used as follows:
6213
6214 \snippet code/src_xml_dom_qdom.cpp 16
6215
6216 Once \c doc and \c elem go out of scope, the whole internal tree
6217 representing the XML document is deleted.
6218
6219 To create a document using DOM use code like this:
6220
6221 \snippet code/src_xml_dom_qdom.cpp 17
6222
6223 For further information about the Document Object Model see
6224 the Document Object Model (DOM)
6225 \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and
6226 \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}
6227 Specifications.
6228
6229 \sa {DOM Bookmarks Application}
6230*/
6231
6232/*!
6233 Constructs an empty document.
6234*/
6235QDomDocument::QDomDocument()
6236{
6237 impl = nullptr;
6238}
6239
6240/*!
6241 Creates a document and sets the name of the document type to \a
6242 name.
6243*/
6244QDomDocument::QDomDocument(const QString& name)
6245{
6246 // We take over ownership
6247 impl = new QDomDocumentPrivate(name);
6248}
6249
6250/*!
6251 Creates a document with the document type \a doctype.
6252
6253 \sa QDomImplementation::createDocumentType()
6254*/
6255QDomDocument::QDomDocument(const QDomDocumentType& doctype)
6256{
6257 impl = new QDomDocumentPrivate(static_cast<QDomDocumentTypePrivate *>(doctype.impl));
6258}
6259
6260/*!
6261 Constructs a copy of \a document.
6262
6263 The data of the copy is shared (shallow copy): modifying one node
6264 will also change the other. If you want to make a deep copy, use
6265 cloneNode().
6266*/
6267QDomDocument::QDomDocument(const QDomDocument &document)
6268 : QDomNode(document)
6269{
6270}
6271
6272QDomDocument::QDomDocument(QDomDocumentPrivate *pimpl)
6273 : QDomNode(pimpl)
6274{
6275}
6276
6277/*!
6278 Assigns \a other to this DOM document.
6279
6280 The data of the copy is shared (shallow copy): modifying one node
6281 will also change the other. If you want to make a deep copy, use
6282 cloneNode().
6283*/
6284QDomDocument &QDomDocument::operator=(const QDomDocument &other) = default;
6285
6286/*!
6287 Destroys the object and frees its resources.
6288*/
6289QDomDocument::~QDomDocument()
6290{
6291}
6292
6293#if QT_DEPRECATED_SINCE(6, 8)
6294QT_WARNING_PUSH
6295QT_WARNING_DISABLE_DEPRECATED
6296/*!
6297 \overload
6298 \deprecated [6.8] Use the overloads taking ParseOptions instead.
6299
6300 This function reads the XML document from the string \a text, returning
6301 true if the content was successfully parsed; otherwise returns \c false.
6302 Since \a text is already a Unicode string, no encoding detection
6303 is done.
6304*/
6305bool QDomDocument::setContent(const QString& text, bool namespaceProcessing,
6306 QString *errorMsg, int *errorLine, int *errorColumn)
6307{
6308 QXmlStreamReader reader(text);
6309 reader.setNamespaceProcessing(namespaceProcessing);
6310 return setContent(reader: &reader, namespaceProcessing, errorMsg, errorLine, errorColumn);
6311}
6312
6313/*!
6314 \deprecated [6.8] Use the overload taking ParseOptions instead.
6315 \overload
6316
6317 This function parses the XML document from the byte array \a
6318 data and sets it as the content of the document. It tries to
6319 detect the encoding of the document as required by the XML
6320 specification.
6321
6322 If \a namespaceProcessing is true, the parser recognizes
6323 namespaces in the XML file and sets the prefix name, local name
6324 and namespace URI to appropriate values. If \a namespaceProcessing
6325 is false, the parser does no namespace processing when it reads
6326 the XML file.
6327
6328 If a parse error occurs, this function returns \c false and the error
6329 message is placed in \c{*}\a{errorMsg}, the line number in
6330 \c{*}\a{errorLine} and the column number in \c{*}\a{errorColumn}
6331 (unless the associated pointer is set to \c nullptr); otherwise this
6332 function returns \c true.
6333
6334 If \a namespaceProcessing is true, the function QDomNode::prefix()
6335 returns a string for all elements and attributes. It returns an
6336 empty string if the element or attribute has no prefix.
6337
6338 Text nodes consisting only of whitespace are stripped and won't
6339 appear in the QDomDocument.
6340
6341 If \a namespaceProcessing is false, the functions
6342 QDomNode::prefix(), QDomNode::localName() and
6343 QDomNode::namespaceURI() return an empty string.
6344
6345//! [entity-refs]
6346 Entity references are handled as follows:
6347 \list
6348 \li References to internal general entities and character entities occurring in the
6349 content are included. The result is a QDomText node with the references replaced
6350 by their corresponding entity values.
6351 \li References to parameter entities occurring in the internal subset are included.
6352 The result is a QDomDocumentType node which contains entity and notation declarations
6353 with the references replaced by their corresponding entity values.
6354 \li Any general parsed entity reference which is not defined in the internal subset and
6355 which occurs in the content is represented as a QDomEntityReference node.
6356 \li Any parsed entity reference which is not defined in the internal subset and which
6357 occurs outside of the content is replaced with an empty string.
6358 \li Any unparsed entity reference is replaced with an empty string.
6359 \endlist
6360//! [entity-refs]
6361
6362 \sa QDomNode::namespaceURI(), QDomNode::localName(),
6363 QDomNode::prefix(), QString::isNull(), QString::isEmpty()
6364*/
6365bool QDomDocument::setContent(const QByteArray &data, bool namespaceProcessing,
6366 QString *errorMsg, int *errorLine, int *errorColumn)
6367{
6368 QXmlStreamReader reader(data);
6369 reader.setNamespaceProcessing(namespaceProcessing);
6370 return setContent(reader: &reader, namespaceProcessing, errorMsg, errorLine, errorColumn);
6371}
6372
6373static inline QDomDocument::ParseOptions toParseOptions(bool namespaceProcessing)
6374{
6375 return namespaceProcessing ? QDomDocument::ParseOption::UseNamespaceProcessing
6376 : QDomDocument::ParseOption::Default;
6377}
6378
6379static inline void unpackParseResult(const QDomDocument::ParseResult &parseResult,
6380 QString *errorMsg, int *errorLine, int *errorColumn)
6381{
6382 if (!parseResult) {
6383 if (errorMsg)
6384 *errorMsg = parseResult.errorMessage;
6385 if (errorLine)
6386 *errorLine = static_cast<int>(parseResult.errorLine);
6387 if (errorColumn)
6388 *errorColumn = static_cast<int>(parseResult.errorColumn);
6389 }
6390}
6391
6392/*!
6393 \overload
6394 \deprecated [6.8] Use the overload taking ParseOptions instead.
6395
6396 This function reads the XML document from the IO device \a dev, returning
6397 true if the content was successfully parsed; otherwise returns \c false.
6398
6399 \note This method will try to open \a dev in read-only mode if it is not
6400 already open. In that case, the caller is responsible for calling close.
6401 This will change in Qt 7, which will no longer open \a dev. Applications
6402 should therefore open the device themselves before calling setContent.
6403*/
6404bool QDomDocument::setContent(QIODevice* dev, bool namespaceProcessing,
6405 QString *errorMsg, int *errorLine, int *errorColumn)
6406{
6407 ParseResult result = setContent(device: dev, options: toParseOptions(namespaceProcessing));
6408 unpackParseResult(parseResult: result, errorMsg, errorLine, errorColumn);
6409 return bool(result);
6410}
6411
6412/*!
6413 \overload
6414 \deprecated [6.8] Use the overload returning ParseResult instead.
6415
6416 This function reads the XML document from the string \a text, returning
6417 true if the content was successfully parsed; otherwise returns \c false.
6418 Since \a text is already a Unicode string, no encoding detection
6419 is performed.
6420
6421 No namespace processing is performed either.
6422*/
6423bool QDomDocument::setContent(const QString& text, QString *errorMsg, int *errorLine, int *errorColumn)
6424{
6425 return setContent(text, namespaceProcessing: false, errorMsg, errorLine, errorColumn);
6426}
6427
6428/*!
6429 \overload
6430 \deprecated [6.8] Use the overload returning ParseResult instead.
6431
6432 This function reads the XML document from the byte array \a buffer,
6433 returning true if the content was successfully parsed; otherwise returns
6434 false.
6435
6436 No namespace processing is performed.
6437*/
6438bool QDomDocument::setContent(const QByteArray& buffer, QString *errorMsg, int *errorLine, int *errorColumn )
6439{
6440 return setContent(data: buffer, namespaceProcessing: false, errorMsg, errorLine, errorColumn);
6441}
6442
6443/*!
6444 \overload
6445 \deprecated [6.8] Use the overload returning ParseResult instead.
6446
6447 This function reads the XML document from the IO device \a dev, returning
6448 true if the content was successfully parsed; otherwise returns \c false.
6449
6450 No namespace processing is performed.
6451*/
6452bool QDomDocument::setContent(QIODevice* dev, QString *errorMsg, int *errorLine, int *errorColumn )
6453{
6454 return setContent(dev, namespaceProcessing: false, errorMsg, errorLine, errorColumn);
6455}
6456
6457/*!
6458 \overload
6459 \since 5.15
6460 \deprecated [6.8] Use the overload taking ParseOptions instead.
6461
6462 This function reads the XML document from the QXmlStreamReader \a reader
6463 and parses it. Returns \c true if the content was successfully parsed;
6464 otherwise returns \c false.
6465
6466 If \a namespaceProcessing is \c true, the parser recognizes namespaces in the XML
6467 file and sets the prefix name, local name and namespace URI to appropriate values.
6468 If \a namespaceProcessing is \c false, the parser does no namespace processing when
6469 it reads the XML file.
6470
6471 If a parse error occurs, the error message is placed in \c{*}\a{errorMsg}, the line
6472 number in \c{*}\a{errorLine} and the column number in \c{*}\a{errorColumn} (unless
6473 the associated pointer is set to \c nullptr).
6474
6475 \sa QXmlStreamReader
6476*/
6477bool QDomDocument::setContent(QXmlStreamReader *reader, bool namespaceProcessing,
6478 QString *errorMsg, int *errorLine, int *errorColumn)
6479{
6480 ParseResult result = setContent(reader, options: toParseOptions(namespaceProcessing));
6481 unpackParseResult(parseResult: result, errorMsg, errorLine, errorColumn);
6482 return bool(result);
6483}
6484QT_WARNING_POP
6485#endif // QT_DEPRECATED_SINCE(6, 8)
6486
6487/*!
6488 \enum QDomDocument::ParseOption
6489 \since 6.5
6490
6491 This enum describes the possible options that can be used when
6492 parsing an XML document using the setContent() method.
6493
6494 \value Default No parse options are set.
6495 \value UseNamespaceProcessing Namespace processing is enabled.
6496 \value PreserveSpacingOnlyNodes Text nodes containing only spacing
6497 characters are preserved.
6498
6499 \sa setContent()
6500*/
6501
6502/*!
6503 \struct QDomDocument::ParseResult
6504 \since 6.5
6505 \inmodule QtXml
6506 \ingroup xml-tools
6507 \brief The struct is used to store the result of QDomDocument::setContent().
6508
6509 The QDomDocument::ParseResult struct is used for storing the result of
6510 QDomDocument::setContent(). If an error is found while parsing an XML
6511 document, the message, line and column number of an error are stored in
6512 \c ParseResult.
6513
6514 \sa QDomDocument::setContent()
6515*/
6516
6517/*!
6518 \variable QDomDocument::ParseResult::errorMessage
6519
6520 The field contains the text message of an error found by
6521 QDomDocument::setContent() while parsing an XML document.
6522
6523 \sa QDomDocument::setContent()
6524*/
6525
6526/*!
6527 \variable QDomDocument::ParseResult::errorLine
6528
6529 The field contains the line number of an error found by
6530 QDomDocument::setContent() while parsing an XML document.
6531
6532 \sa QDomDocument::setContent()
6533*/
6534
6535/*!
6536 \variable QDomDocument::ParseResult::errorColumn
6537
6538 The field contains the column number of an error found by
6539 QDomDocument::setContent() while parsing an XML document.
6540
6541 \sa QDomDocument::setContent()
6542*/
6543
6544/*!
6545 \fn QDomDocument::ParseResult::operator bool() const
6546
6547 Returns \c false if any error is found by QDomDocument::setContent();
6548 otherwise returns \c true.
6549
6550 \sa QDomDocument::setContent()
6551*/
6552
6553/*!
6554 \fn ParseResult QDomDocument::setContent(const QByteArray &data, ParseOptions options)
6555 \fn ParseResult QDomDocument::setContent(QAnyStringView text, ParseOptions options)
6556 \fn ParseResult QDomDocument::setContent(QIODevice *device, ParseOptions options)
6557 \fn ParseResult QDomDocument::setContent(QXmlStreamReader *reader, ParseOptions options)
6558
6559 \since 6.5
6560
6561 This function parses the XML document from the byte array \a
6562 data, string view \a text, IO \a device, or stream \a reader
6563 and sets it as the content of the document. It tries to
6564 detect the encoding of the document, in accordance with the
6565 XML specification. Returns the result of parsing in ParseResult,
6566 which explicitly converts to \c bool.
6567
6568 You can use the \a options parameter to specify different parsing
6569 options, for example, to enable namespace processing, etc.
6570
6571 By default, namespace processing is disabled. If it's disabled, the
6572 parser does no namespace processing when it reads the XML file. The
6573 functions QDomNode::prefix(), QDomNode::localName() and
6574 QDomNode::namespaceURI() return an empty string.
6575
6576 If namespace processing is enabled via the parse \a options, the parser
6577 recognizes namespaces in the XML file and sets the prefix name, local
6578 name and namespace URI to appropriate values. The functions
6579 QDomNode::prefix(), QDomNode::localName() and QDomNode::namespaceURI()
6580 return a string for all elements and attributes and return an empty
6581 string if the element or attribute has no prefix.
6582
6583 Text nodes consisting only of whitespace are stripped and won't
6584 appear in the QDomDocument. Since Qt 6.5, one can pass
6585 QDomDocument::ParseOption::PreserveSpacingOnlyNodes as a parse
6586 option, to specify that spacing-only text nodes must be preserved.
6587
6588 \include qdom.cpp entity-refs
6589
6590 \note The overload taking IO \a device will try to open it in read-only
6591 mode if it is not already open. In that case, the caller is responsible
6592 for calling close. This will change in Qt 7, which will no longer open
6593 the IO \a device. Applications should therefore open the device themselves
6594 before calling setContent().
6595
6596 \sa ParseResult, ParseOptions
6597*/
6598QDomDocument::ParseResult QDomDocument::setContentImpl(const QByteArray &data, ParseOptions options)
6599{
6600 QXmlStreamReader reader(data);
6601 reader.setNamespaceProcessing(options.testFlag(flag: ParseOption::UseNamespaceProcessing));
6602 return setContent(reader: &reader, options);
6603}
6604
6605QDomDocument::ParseResult QDomDocument::setContent(QAnyStringView data, ParseOptions options)
6606{
6607 QXmlStreamReader reader(data);
6608 reader.setNamespaceProcessing(options.testFlag(flag: ParseOption::UseNamespaceProcessing));
6609 return setContent(reader: &reader, options);
6610}
6611
6612QDomDocument::ParseResult QDomDocument::setContent(QIODevice *device, ParseOptions options)
6613{
6614#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
6615 if (!device->isOpen()) {
6616 qWarning(msg: "QDomDocument called with unopened QIODevice. "
6617 "This will not be supported in future Qt versions.");
6618 if (!device->open(mode: QIODevice::ReadOnly)) {
6619 const auto error = u"QDomDocument::setContent: Failed to open device."_s;
6620 qWarning(msg: "%s", qPrintable(error));
6621 return { .errorMessage: error };
6622 }
6623 }
6624#endif
6625
6626 QXmlStreamReader reader(device);
6627 reader.setNamespaceProcessing(options.testFlag(flag: ParseOption::UseNamespaceProcessing));
6628 return setContent(reader: &reader, options);
6629}
6630
6631QDomDocument::ParseResult QDomDocument::setContent(QXmlStreamReader *reader, ParseOptions options)
6632{
6633 if (!impl)
6634 impl = new QDomDocumentPrivate();
6635 return IMPL->setContent(reader, options);
6636}
6637
6638/*!
6639 Converts the parsed document back to its textual representation.
6640
6641 This function uses \a indent as the amount of space to indent
6642 subelements.
6643
6644 If \a indent is -1, no whitespace at all is added.
6645*/
6646QString QDomDocument::toString(int indent) const
6647{
6648 QString str;
6649 QTextStream s(&str, QIODevice::WriteOnly);
6650 save(stream&: s, indent);
6651 return str;
6652}
6653
6654/*!
6655 Converts the parsed document back to its textual representation
6656 and returns a QByteArray containing the data encoded as UTF-8.
6657
6658 This function uses \a indent as the amount of space to indent
6659 subelements.
6660
6661 \sa toString()
6662*/
6663QByteArray QDomDocument::toByteArray(int indent) const
6664{
6665 // ### if there is an encoding specified in the xml declaration, this
6666 // encoding declaration should be changed to utf8
6667 return toString(indent).toUtf8();
6668}
6669
6670
6671/*!
6672 Returns the document type of this document.
6673*/
6674QDomDocumentType QDomDocument::doctype() const
6675{
6676 if (!impl)
6677 return QDomDocumentType();
6678 return QDomDocumentType(IMPL->doctype());
6679}
6680
6681/*!
6682 Returns a QDomImplementation object.
6683*/
6684QDomImplementation QDomDocument::implementation() const
6685{
6686 if (!impl)
6687 return QDomImplementation();
6688 return QDomImplementation(IMPL->implementation());
6689}
6690
6691/*!
6692 Returns the root element of the document.
6693*/
6694QDomElement QDomDocument::documentElement() const
6695{
6696 if (!impl)
6697 return QDomElement();
6698 return QDomElement(IMPL->documentElement());
6699}
6700
6701/*!
6702 Creates a new element called \a tagName that can be inserted into
6703 the DOM tree, e.g. using QDomNode::appendChild().
6704
6705 If \a tagName is not a valid XML name, the behavior of this function is governed
6706 by QDomImplementation::InvalidDataPolicy.
6707
6708 \sa createElementNS(), QDomNode::appendChild(), QDomNode::insertBefore(),
6709 QDomNode::insertAfter()
6710*/
6711QDomElement QDomDocument::createElement(const QString& tagName)
6712{
6713 if (!impl)
6714 impl = new QDomDocumentPrivate();
6715 return QDomElement(IMPL->createElement(tagName));
6716}
6717
6718/*!
6719 Creates a new document fragment, that can be used to hold parts of
6720 the document, e.g. when doing complex manipulations of the
6721 document tree.
6722*/
6723QDomDocumentFragment QDomDocument::createDocumentFragment()
6724{
6725 if (!impl)
6726 impl = new QDomDocumentPrivate();
6727 return QDomDocumentFragment(IMPL->createDocumentFragment());
6728}
6729
6730/*!
6731 Creates a text node for the string \a value that can be inserted
6732 into the document tree, e.g. using QDomNode::appendChild().
6733
6734 If \a value contains characters which cannot be stored as character
6735 data of an XML document (even in the form of character references), the
6736 behavior of this function is governed by QDomImplementation::InvalidDataPolicy.
6737
6738 \sa QDomNode::appendChild(), QDomNode::insertBefore(), QDomNode::insertAfter()
6739*/
6740QDomText QDomDocument::createTextNode(const QString& value)
6741{
6742 if (!impl)
6743 impl = new QDomDocumentPrivate();
6744 return QDomText(IMPL->createTextNode(data: value));
6745}
6746
6747/*!
6748 Creates a new comment for the string \a value that can be inserted
6749 into the document, e.g. using QDomNode::appendChild().
6750
6751 If \a value contains characters which cannot be stored in an XML comment,
6752 the behavior of this function is governed by QDomImplementation::InvalidDataPolicy.
6753
6754 \sa QDomNode::appendChild(), QDomNode::insertBefore(), QDomNode::insertAfter()
6755*/
6756QDomComment QDomDocument::createComment(const QString& value)
6757{
6758 if (!impl)
6759 impl = new QDomDocumentPrivate();
6760 return QDomComment(IMPL->createComment(data: value));
6761}
6762
6763/*!
6764 Creates a new CDATA section for the string \a value that can be
6765 inserted into the document, e.g. using QDomNode::appendChild().
6766
6767 If \a value contains characters which cannot be stored in a CDATA section,
6768 the behavior of this function is governed by
6769 QDomImplementation::InvalidDataPolicy.
6770
6771 \sa QDomNode::appendChild(), QDomNode::insertBefore(), QDomNode::insertAfter()
6772*/
6773QDomCDATASection QDomDocument::createCDATASection(const QString& value)
6774{
6775 if (!impl)
6776 impl = new QDomDocumentPrivate();
6777 return QDomCDATASection(IMPL->createCDATASection(data: value));
6778}
6779
6780/*!
6781 Creates a new processing instruction that can be inserted into the
6782 document, e.g. using QDomNode::appendChild(). This function sets
6783 the target for the processing instruction to \a target and the
6784 data to \a data.
6785
6786 If \a target is not a valid XML name, or data if contains characters which cannot
6787 appear in a processing instruction, the behavior of this function is governed by
6788 QDomImplementation::InvalidDataPolicy.
6789
6790 \sa QDomNode::appendChild(), QDomNode::insertBefore(), QDomNode::insertAfter()
6791*/
6792QDomProcessingInstruction QDomDocument::createProcessingInstruction(const QString& target,
6793 const QString& data)
6794{
6795 if (!impl)
6796 impl = new QDomDocumentPrivate();
6797 return QDomProcessingInstruction(IMPL->createProcessingInstruction(target, data));
6798}
6799
6800
6801/*!
6802 Creates a new attribute called \a name that can be inserted into
6803 an element, e.g. using QDomElement::setAttributeNode().
6804
6805 If \a name is not a valid XML name, the behavior of this function is governed by
6806 QDomImplementation::InvalidDataPolicy.
6807
6808 \sa createAttributeNS()
6809*/
6810QDomAttr QDomDocument::createAttribute(const QString& name)
6811{
6812 if (!impl)
6813 impl = new QDomDocumentPrivate();
6814 return QDomAttr(IMPL->createAttribute(aname: name));
6815}
6816
6817/*!
6818 Creates a new entity reference called \a name that can be inserted
6819 into the document, e.g. using QDomNode::appendChild().
6820
6821 If \a name is not a valid XML name, the behavior of this function is governed by
6822 QDomImplementation::InvalidDataPolicy.
6823
6824 \sa QDomNode::appendChild(), QDomNode::insertBefore(), QDomNode::insertAfter()
6825*/
6826QDomEntityReference QDomDocument::createEntityReference(const QString& name)
6827{
6828 if (!impl)
6829 impl = new QDomDocumentPrivate();
6830 return QDomEntityReference(IMPL->createEntityReference(aname: name));
6831}
6832
6833/*!
6834 Returns a QDomNodeList, that contains all the elements in the
6835 document with the name \a tagname. The order of the node list is
6836 the order they are encountered in a preorder traversal of the
6837 element tree.
6838
6839 \sa elementsByTagNameNS(), QDomElement::elementsByTagName()
6840*/
6841QDomNodeList QDomDocument::elementsByTagName(const QString& tagname) const
6842{
6843 return QDomNodeList(new QDomNodeListPrivate(impl, tagname));
6844}
6845
6846/*!
6847 Imports the node \a importedNode from another document to this
6848 document. \a importedNode remains in the original document; this
6849 function creates a copy that can be used within this document.
6850
6851 This function returns the imported node that belongs to this
6852 document. The returned node has no parent. It is not possible to
6853 import QDomDocument and QDomDocumentType nodes. In those cases
6854 this function returns a \l{QDomNode::isNull()}{null node}.
6855
6856 If \a importedNode is a \l{QDomNode::isNull()}{null node},
6857 a null node is returned.
6858
6859 If \a deep is true, this function imports not only the node \a
6860 importedNode but its whole subtree; if it is false, only the \a
6861 importedNode is imported. The argument \a deep has no effect on
6862 QDomAttr and QDomEntityReference nodes, since the descendants of
6863 QDomAttr nodes are always imported and those of
6864 QDomEntityReference nodes are never imported.
6865
6866 The behavior of this function is slightly different depending on
6867 the node types:
6868 \table
6869 \header \li Node Type \li Behavior
6870 \row \li QDomAttr
6871 \li The owner element is set to 0 and the specified flag is
6872 set to true in the generated attribute. The whole subtree
6873 of \a importedNode is always imported for attribute nodes:
6874 \a deep has no effect.
6875 \row \li QDomDocument
6876 \li Document nodes cannot be imported.
6877 \row \li QDomDocumentFragment
6878 \li If \a deep is true, this function imports the whole
6879 document fragment; otherwise it only generates an empty
6880 document fragment.
6881 \row \li QDomDocumentType
6882 \li Document type nodes cannot be imported.
6883 \row \li QDomElement
6884 \li Attributes for which QDomAttr::specified() is true are
6885 also imported, other attributes are not imported. If \a
6886 deep is true, this function also imports the subtree of \a
6887 importedNode; otherwise it imports only the element node
6888 (and some attributes, see above).
6889 \row \li QDomEntity
6890 \li Entity nodes can be imported, but at the moment there is
6891 no way to use them since the document type is read-only in
6892 DOM level 2.
6893 \row \li QDomEntityReference
6894 \li Descendants of entity reference nodes are never imported:
6895 \a deep has no effect.
6896 \row \li QDomNotation
6897 \li Notation nodes can be imported, but at the moment there is
6898 no way to use them since the document type is read-only in
6899 DOM level 2.
6900 \row \li QDomProcessingInstruction
6901 \li The target and value of the processing instruction is
6902 copied to the new node.
6903 \row \li QDomText
6904 \li The text is copied to the new node.
6905 \row \li QDomCDATASection
6906 \li The text is copied to the new node.
6907 \row \li QDomComment
6908 \li The text is copied to the new node.
6909 \endtable
6910
6911 \sa QDomElement::setAttribute(), QDomNode::insertBefore(),
6912 QDomNode::insertAfter(), QDomNode::replaceChild(), QDomNode::removeChild(),
6913 QDomNode::appendChild()
6914*/
6915QDomNode QDomDocument::importNode(const QDomNode& importedNode, bool deep)
6916{
6917 if (importedNode.isNull())
6918 return QDomNode();
6919 if (!impl)
6920 impl = new QDomDocumentPrivate();
6921 return QDomNode(IMPL->importNode(importedNode: importedNode.impl, deep));
6922}
6923
6924/*!
6925 Creates a new element with namespace support that can be inserted
6926 into the DOM tree. The name of the element is \a qName and the
6927 namespace URI is \a nsURI. This function also sets
6928 QDomNode::prefix() and QDomNode::localName() to appropriate values
6929 (depending on \a qName).
6930
6931 If \a qName is an empty string, returns a null element regardless of
6932 whether the invalid data policy is set.
6933
6934 \sa createElement()
6935*/
6936QDomElement QDomDocument::createElementNS(const QString& nsURI, const QString& qName)
6937{
6938 if (!impl)
6939 impl = new QDomDocumentPrivate();
6940 return QDomElement(IMPL->createElementNS(nsURI, qName));
6941}
6942
6943/*!
6944 Creates a new attribute with namespace support that can be
6945 inserted into an element. The name of the attribute is \a qName
6946 and the namespace URI is \a nsURI. This function also sets
6947 QDomNode::prefix() and QDomNode::localName() to appropriate values
6948 (depending on \a qName).
6949
6950 If \a qName is not a valid XML name, the behavior of this function is governed by
6951 QDomImplementation::InvalidDataPolicy.
6952
6953 \sa createAttribute()
6954*/
6955QDomAttr QDomDocument::createAttributeNS(const QString& nsURI, const QString& qName)
6956{
6957 if (!impl)
6958 impl = new QDomDocumentPrivate();
6959 return QDomAttr(IMPL->createAttributeNS(nsURI, qName));
6960}
6961
6962/*!
6963 Returns a QDomNodeList that contains all the elements in the
6964 document with the local name \a localName and a namespace URI of
6965 \a nsURI. The order of the node list is the order they are
6966 encountered in a preorder traversal of the element tree.
6967
6968 \sa elementsByTagName(), QDomElement::elementsByTagNameNS()
6969*/
6970QDomNodeList QDomDocument::elementsByTagNameNS(const QString& nsURI, const QString& localName)
6971{
6972 return QDomNodeList(new QDomNodeListPrivate(impl, nsURI, localName));
6973}
6974
6975/*!
6976 Returns the element whose ID is equal to \a elementId. If no
6977 element with the ID was found, this function returns a
6978 \l{QDomNode::isNull()}{null element}.
6979
6980 Since the QDomClasses do not know which attributes are element
6981 IDs, this function returns always a
6982 \l{QDomNode::isNull()}{null element}.
6983 This may change in a future version.
6984*/
6985QDomElement QDomDocument::elementById(const QString& /*elementId*/)
6986{
6987 qWarning(msg: "elementById() is not implemented and will always return a null node.");
6988 return QDomElement();
6989}
6990
6991/*!
6992 \fn QDomNode::NodeType QDomDocument::nodeType() const
6993
6994 Returns \c DocumentNode.
6995*/
6996
6997#undef IMPL
6998
6999/**************************************************************
7000 *
7001 * Node casting functions
7002 *
7003 **************************************************************/
7004
7005/*!
7006 Converts a QDomNode into a QDomAttr. If the node is not an
7007 attribute, the returned object will be \l{QDomNode::isNull()}{null}.
7008
7009 \sa isAttr()
7010*/
7011QDomAttr QDomNode::toAttr() const
7012{
7013 if (impl && impl->isAttr())
7014 return QDomAttr(static_cast<QDomAttrPrivate *>(impl));
7015 return QDomAttr();
7016}
7017
7018/*!
7019 Converts a QDomNode into a QDomCDATASection. If the node is not a
7020 CDATA section, the returned object will be \l{QDomNode::isNull()}{null}.
7021
7022 \sa isCDATASection()
7023*/
7024QDomCDATASection QDomNode::toCDATASection() const
7025{
7026 if (impl && impl->isCDATASection())
7027 return QDomCDATASection(static_cast<QDomCDATASectionPrivate *>(impl));
7028 return QDomCDATASection();
7029}
7030
7031/*!
7032 Converts a QDomNode into a QDomDocumentFragment. If the node is
7033 not a document fragment the returned object will be \l{QDomNode::isNull()}{null}.
7034
7035 \sa isDocumentFragment()
7036*/
7037QDomDocumentFragment QDomNode::toDocumentFragment() const
7038{
7039 if (impl && impl->isDocumentFragment())
7040 return QDomDocumentFragment(static_cast<QDomDocumentFragmentPrivate *>(impl));
7041 return QDomDocumentFragment();
7042}
7043
7044/*!
7045 Converts a QDomNode into a QDomDocument. If the node is not a
7046 document the returned object will be \l{QDomNode::isNull()}{null}.
7047
7048 \sa isDocument()
7049*/
7050QDomDocument QDomNode::toDocument() const
7051{
7052 if (impl && impl->isDocument())
7053 return QDomDocument(static_cast<QDomDocumentPrivate *>(impl));
7054 return QDomDocument();
7055}
7056
7057/*!
7058 Converts a QDomNode into a QDomDocumentType. If the node is not a
7059 document type the returned object will be \l{QDomNode::isNull()}{null}.
7060
7061 \sa isDocumentType()
7062*/
7063QDomDocumentType QDomNode::toDocumentType() const
7064{
7065 if (impl && impl->isDocumentType())
7066 return QDomDocumentType(static_cast<QDomDocumentTypePrivate *>(impl));
7067 return QDomDocumentType();
7068}
7069
7070/*!
7071 Converts a QDomNode into a QDomElement. If the node is not an
7072 element the returned object will be \l{QDomNode::isNull()}{null}.
7073
7074 \sa isElement()
7075*/
7076QDomElement QDomNode::toElement() const
7077{
7078 if (impl && impl->isElement())
7079 return QDomElement(static_cast<QDomElementPrivate *>(impl));
7080 return QDomElement();
7081}
7082
7083/*!
7084 Converts a QDomNode into a QDomEntityReference. If the node is not
7085 an entity reference, the returned object will be \l{QDomNode::isNull()}{null}.
7086
7087 \sa isEntityReference()
7088*/
7089QDomEntityReference QDomNode::toEntityReference() const
7090{
7091 if (impl && impl->isEntityReference())
7092 return QDomEntityReference(static_cast<QDomEntityReferencePrivate *>(impl));
7093 return QDomEntityReference();
7094}
7095
7096/*!
7097 Converts a QDomNode into a QDomText. If the node is not a text,
7098 the returned object will be \l{QDomNode::isNull()}{null}.
7099
7100 \sa isText()
7101*/
7102QDomText QDomNode::toText() const
7103{
7104 if (impl && impl->isText())
7105 return QDomText(static_cast<QDomTextPrivate *>(impl));
7106 return QDomText();
7107}
7108
7109/*!
7110 Converts a QDomNode into a QDomEntity. If the node is not an
7111 entity the returned object will be \l{QDomNode::isNull()}{null}.
7112
7113 \sa isEntity()
7114*/
7115QDomEntity QDomNode::toEntity() const
7116{
7117 if (impl && impl->isEntity())
7118 return QDomEntity(static_cast<QDomEntityPrivate *>(impl));
7119 return QDomEntity();
7120}
7121
7122/*!
7123 Converts a QDomNode into a QDomNotation. If the node is not a
7124 notation the returned object will be \l{QDomNode::isNull()}{null}.
7125
7126 \sa isNotation()
7127*/
7128QDomNotation QDomNode::toNotation() const
7129{
7130 if (impl && impl->isNotation())
7131 return QDomNotation(static_cast<QDomNotationPrivate *>(impl));
7132 return QDomNotation();
7133}
7134
7135/*!
7136 Converts a QDomNode into a QDomProcessingInstruction. If the node
7137 is not a processing instruction the returned object will be \l{QDomNode::isNull()}{null}.
7138
7139 \sa isProcessingInstruction()
7140*/
7141QDomProcessingInstruction QDomNode::toProcessingInstruction() const
7142{
7143 if (impl && impl->isProcessingInstruction())
7144 return QDomProcessingInstruction(static_cast<QDomProcessingInstructionPrivate *>(impl));
7145 return QDomProcessingInstruction();
7146}
7147
7148/*!
7149 Converts a QDomNode into a QDomCharacterData. If the node is not a
7150 character data node the returned object will be \l{QDomNode::isNull()}{null}.
7151
7152 \sa isCharacterData()
7153*/
7154QDomCharacterData QDomNode::toCharacterData() const
7155{
7156 if (impl && impl->isCharacterData())
7157 return QDomCharacterData(static_cast<QDomCharacterDataPrivate *>(impl));
7158 return QDomCharacterData();
7159}
7160
7161/*!
7162 Converts a QDomNode into a QDomComment. If the node is not a
7163 comment the returned object will be \l{QDomNode::isNull()}{null}.
7164
7165 \sa isComment()
7166*/
7167QDomComment QDomNode::toComment() const
7168{
7169 if (impl && impl->isComment())
7170 return QDomComment(static_cast<QDomCommentPrivate *>(impl));
7171 return QDomComment();
7172}
7173
7174/*!
7175 \variable QDomNode::impl
7176 \internal
7177 Pointer to private data structure.
7178*/
7179
7180QT_END_NAMESPACE
7181
7182#endif // feature dom
7183

source code of qtbase/src/xml/dom/qdom.cpp