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