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 maps of entities() and
3279 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 the entities described in the DTD.
3334
3335 \note Only entities declared with a public or a system identifier are
3336 represented. The parser expands internal entities and discards their
3337 declarations, so those do not appear in this map. The internal subset
3338 itself is still available verbatim from internalSubset().
3339
3340 \sa notations(), internalSubset(), QDomDocument::setContent()
3341*/
3342QDomNamedNodeMap QDomDocumentType::entities() const
3343{
3344 if (!impl)
3345 return QDomNamedNodeMap();
3346 return QDomNamedNodeMap(IMPL->entities);
3347}
3348
3349/*!
3350 Returns a map of all notations described in the DTD.
3351*/
3352QDomNamedNodeMap QDomDocumentType::notations() const
3353{
3354 if (!impl)
3355 return QDomNamedNodeMap();
3356 return QDomNamedNodeMap(IMPL->notations);
3357}
3358
3359/*!
3360 Returns the public identifier of the external DTD subset or
3361 an empty string if there is no public identifier.
3362
3363 \sa systemId(), internalSubset(), QDomImplementation::createDocumentType()
3364*/
3365QString QDomDocumentType::publicId() const
3366{
3367 if (!impl)
3368 return QString();
3369 return IMPL->publicId;
3370}
3371
3372/*!
3373 Returns the system identifier of the external DTD subset or
3374 an empty string if there is no system identifier.
3375
3376 \sa publicId(), internalSubset(), QDomImplementation::createDocumentType()
3377*/
3378QString QDomDocumentType::systemId() const
3379{
3380 if (!impl)
3381 return QString();
3382 return IMPL->systemId;
3383}
3384
3385/*!
3386 Returns the internal subset of the document type or an empty
3387 string if there is no internal subset.
3388
3389 \sa publicId(), systemId()
3390*/
3391QString QDomDocumentType::internalSubset() const
3392{
3393 if (!impl)
3394 return QString();
3395 return IMPL->internalSubset;
3396}
3397
3398/*
3399 Are these needed at all? The only difference when removing these
3400 two methods in all subclasses is that we'd get a different type
3401 for null nodes.
3402*/
3403
3404/*!
3405 \fn QDomNode::NodeType QDomDocumentType::nodeType() const
3406
3407 Returns \c DocumentTypeNode.
3408
3409 \sa isDocumentType(), QDomNode::toDocumentType()
3410*/
3411
3412#undef IMPL
3413
3414/**************************************************************
3415 *
3416 * QDomDocumentFragmentPrivate
3417 *
3418 **************************************************************/
3419
3420QDomDocumentFragmentPrivate::QDomDocumentFragmentPrivate(QDomDocumentPrivate* doc, QDomNodePrivate* parent)
3421 : QDomNodePrivate(doc, parent)
3422{
3423 name = u"#document-fragment"_s;
3424}
3425
3426QDomDocumentFragmentPrivate::QDomDocumentFragmentPrivate(QDomNodePrivate* n, bool deep)
3427 : QDomNodePrivate(n, deep)
3428{
3429}
3430
3431QDomNodePrivate* QDomDocumentFragmentPrivate::cloneNode(bool deep)
3432{
3433 QDomNodePrivate* p = new QDomDocumentFragmentPrivate(this, deep);
3434 // We are not interested in this node
3435 p->ref.deref();
3436 return p;
3437}
3438
3439/**************************************************************
3440 *
3441 * QDomDocumentFragment
3442 *
3443 **************************************************************/
3444
3445/*!
3446 \class QDomDocumentFragment
3447 \reentrant
3448 \brief The QDomDocumentFragment class is a tree of QDomNodes which is not usually a complete QDomDocument.
3449
3450 \inmodule QtXml
3451 \ingroup xml-tools
3452
3453 If you want to do complex tree operations it is useful to have a
3454 lightweight class to store nodes and their relations.
3455 QDomDocumentFragment stores a subtree of a document which does not
3456 necessarily represent a well-formed XML document.
3457
3458 QDomDocumentFragment is also useful if you want to group several
3459 nodes in a list and insert them all together as children of some
3460 node. In these cases QDomDocumentFragment can be used as a
3461 temporary container for this list of children.
3462
3463 The most important feature of QDomDocumentFragment is that it is
3464 treated in a special way by QDomNode::insertAfter(),
3465 QDomNode::insertBefore(), QDomNode::replaceChild() and
3466 QDomNode::appendChild(): instead of inserting the fragment itself, all
3467 the fragment's children are inserted.
3468*/
3469
3470/*!
3471 Constructs an empty document fragment.
3472*/
3473QDomDocumentFragment::QDomDocumentFragment()
3474{
3475}
3476
3477QDomDocumentFragment::QDomDocumentFragment(QDomDocumentFragmentPrivate* n)
3478 : QDomNode(n)
3479{
3480}
3481
3482/*!
3483 Constructs a copy of \a documentFragment.
3484
3485 The data of the copy is shared (shallow copy): modifying one node
3486 will also change the other. If you want to make a deep copy, use
3487 cloneNode().
3488*/
3489QDomDocumentFragment::QDomDocumentFragment(const QDomDocumentFragment &documentFragment)
3490 : QDomNode(documentFragment)
3491{
3492}
3493
3494/*!
3495 Assigns \a other to this DOM document fragment.
3496
3497 The data of the copy is shared (shallow copy): modifying one node
3498 will also change the other. If you want to make a deep copy, use
3499 cloneNode().
3500*/
3501QDomDocumentFragment &QDomDocumentFragment::operator=(const QDomDocumentFragment &other) = default;
3502
3503/*!
3504 \fn QDomNode::NodeType QDomDocumentFragment::nodeType() const
3505
3506 Returns \c DocumentFragment.
3507
3508 \sa isDocumentFragment(), QDomNode::toDocumentFragment()
3509*/
3510
3511/**************************************************************
3512 *
3513 * QDomCharacterDataPrivate
3514 *
3515 **************************************************************/
3516
3517QDomCharacterDataPrivate::QDomCharacterDataPrivate(QDomDocumentPrivate* d, QDomNodePrivate* p,
3518 const QString& data)
3519 : QDomNodePrivate(d, p)
3520{
3521 value = data;
3522 name = u"#character-data"_s;
3523}
3524
3525QDomCharacterDataPrivate::QDomCharacterDataPrivate(QDomCharacterDataPrivate* n, bool deep)
3526 : QDomNodePrivate(n, deep)
3527{
3528}
3529
3530QDomNodePrivate* QDomCharacterDataPrivate::cloneNode(bool deep)
3531{
3532 QDomNodePrivate* p = new QDomCharacterDataPrivate(this, deep);
3533 // We are not interested in this node
3534 p->ref.deref();
3535 return p;
3536}
3537
3538int QDomCharacterDataPrivate::dataLength() const
3539{
3540 return value.size();
3541}
3542
3543QString QDomCharacterDataPrivate::substringData(unsigned long offset, unsigned long n) const
3544{
3545 return value.mid(offset, n);
3546}
3547
3548void QDomCharacterDataPrivate::insertData(unsigned long offset, const QString& arg)
3549{
3550 value.insert(offset, arg);
3551}
3552
3553void QDomCharacterDataPrivate::deleteData(unsigned long offset, unsigned long n)
3554{
3555 value.remove(offset, n);
3556}
3557
3558void QDomCharacterDataPrivate::replaceData(unsigned long offset, unsigned long n, const QString& arg)
3559{
3560 value.replace(offset, n, arg);
3561}
3562
3563void QDomCharacterDataPrivate::appendData(const QString& arg)
3564{
3565 value += arg;
3566}
3567
3568/**************************************************************
3569 *
3570 * QDomCharacterData
3571 *
3572 **************************************************************/
3573
3574#define IMPL static_cast<QDomCharacterDataPrivate *>(impl)
3575
3576/*!
3577 \class QDomCharacterData
3578 \reentrant
3579 \brief The QDomCharacterData class represents a generic string in the DOM.
3580
3581 \inmodule QtXml
3582 \ingroup xml-tools
3583
3584 Character data as used in XML specifies a generic data string.
3585 More specialized versions of this class are QDomText, QDomComment
3586 and QDomCDATASection.
3587
3588 The data string is set with setData() and retrieved with data().
3589 You can retrieve a portion of the data string using
3590 substringData(). Extra data can be appended with appendData(), or
3591 inserted with insertData(). Portions of the data string can be
3592 deleted with deleteData() or replaced with replaceData(). The
3593 length of the data string is returned by length().
3594
3595 The node type of the node containing this character data is
3596 returned by nodeType().
3597
3598 \sa QDomText, QDomComment, QDomCDATASection
3599*/
3600
3601/*!
3602 Constructs an empty character data object.
3603*/
3604QDomCharacterData::QDomCharacterData()
3605{
3606}
3607
3608/*!
3609 Constructs a copy of \a characterData.
3610
3611 The data of the copy is shared (shallow copy): modifying one node
3612 will also change the other. If you want to make a deep copy, use
3613 cloneNode().
3614*/
3615QDomCharacterData::QDomCharacterData(const QDomCharacterData &characterData)
3616 : QDomNode(characterData)
3617{
3618}
3619
3620QDomCharacterData::QDomCharacterData(QDomCharacterDataPrivate* n)
3621 : QDomNode(n)
3622{
3623}
3624
3625/*!
3626 Assigns \a other to this character data.
3627
3628 The data of the copy is shared (shallow copy): modifying one node
3629 will also change the other. If you want to make a deep copy, use
3630 cloneNode().
3631*/
3632QDomCharacterData &QDomCharacterData::operator=(const QDomCharacterData &other) = default;
3633
3634/*!
3635 Returns the string stored in this object.
3636
3637 If the node is a \l{isNull()}{null node}, it will return
3638 an empty string.
3639*/
3640QString QDomCharacterData::data() const
3641{
3642 if (!impl)
3643 return QString();
3644 return impl->nodeValue();
3645}
3646
3647/*!
3648 Sets this object's string to \a data.
3649*/
3650void QDomCharacterData::setData(const QString &data)
3651{
3652 if (impl)
3653 impl->setNodeValue(data);
3654}
3655
3656/*!
3657 Returns the length of the stored string.
3658*/
3659int QDomCharacterData::length() const
3660{
3661 if (impl)
3662 return IMPL->dataLength();
3663 return 0;
3664}
3665
3666/*!
3667 Returns the substring of length \a count from position \a offset.
3668*/
3669QString QDomCharacterData::substringData(unsigned long offset, unsigned long count)
3670{
3671 if (!impl)
3672 return QString();
3673 return IMPL->substringData(offset, count);
3674}
3675
3676/*!
3677 Appends the string \a arg to the stored string.
3678*/
3679void QDomCharacterData::appendData(const QString& arg)
3680{
3681 if (impl)
3682 IMPL->appendData(arg);
3683}
3684
3685/*!
3686 Inserts the string \a arg into the stored string at position \a offset.
3687*/
3688void QDomCharacterData::insertData(unsigned long offset, const QString& arg)
3689{
3690 if (impl)
3691 IMPL->insertData(offset, arg);
3692}
3693
3694/*!
3695 Deletes a substring of length \a count from position \a offset.
3696*/
3697void QDomCharacterData::deleteData(unsigned long offset, unsigned long count)
3698{
3699 if (impl)
3700 IMPL->deleteData(offset, count);
3701}
3702
3703/*!
3704 Replaces the substring of length \a count starting at position \a
3705 offset with the string \a arg.
3706*/
3707void QDomCharacterData::replaceData(unsigned long offset, unsigned long count, const QString& arg)
3708{
3709 if (impl)
3710 IMPL->replaceData(offset, count, arg);
3711}
3712
3713/*!
3714 Returns the type of node this object refers to (i.e. \c TextNode,
3715 \c CDATASectionNode, \c CommentNode or \c CharacterDataNode). For
3716 a \l{isNull()}{null node}, returns \c CharacterDataNode.
3717*/
3718QDomNode::NodeType QDomCharacterData::nodeType() const
3719{
3720 if (!impl)
3721 return CharacterDataNode;
3722 return QDomNode::nodeType();
3723}
3724
3725#undef IMPL
3726
3727/**************************************************************
3728 *
3729 * QDomAttrPrivate
3730 *
3731 **************************************************************/
3732
3733QDomAttrPrivate::QDomAttrPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent, const QString& name_)
3734 : QDomNodePrivate(d, parent)
3735{
3736 name = name_;
3737 m_specified = false;
3738}
3739
3740QDomAttrPrivate::QDomAttrPrivate(QDomDocumentPrivate* d, QDomNodePrivate* p, const QString& nsURI, const QString& qName)
3741 : QDomNodePrivate(d, p)
3742{
3743 qt_split_namespace(prefix, name, qName, !nsURI.isNull());
3744 namespaceURI = nsURI;
3745 createdWithDom1Interface = false;
3746 m_specified = false;
3747}
3748
3749QDomAttrPrivate::QDomAttrPrivate(QDomAttrPrivate* n, bool deep)
3750 : QDomNodePrivate(n, deep)
3751{
3752 m_specified = n->specified();
3753}
3754
3755void QDomAttrPrivate::setNodeValue(const QString& v)
3756{
3757 value = v;
3758 QDomTextPrivate *t = new QDomTextPrivate(nullptr, this, v);
3759 // keep the refcount balanced: appendChild() does a ref anyway.
3760 t->ref.deref();
3761 if (first) {
3762 auto removed = removeChild(first);
3763 if (removed && !removed->ref.loadRelaxed()) // removeChild() already deref()ed
3764 delete removed;
3765 }
3766 appendChild(t);
3767}
3768
3769QDomNodePrivate* QDomAttrPrivate::cloneNode(bool deep)
3770{
3771 QDomNodePrivate* p = new QDomAttrPrivate(this, deep);
3772 // We are not interested in this node
3773 p->ref.deref();
3774 return p;
3775}
3776
3777bool QDomAttrPrivate::specified() const
3778{
3779 return m_specified;
3780}
3781
3782/* \internal
3783 Encode & escape \a str. Yes, it makes no sense to return a QString,
3784 but is so for legacy reasons.
3785
3786 Remember that content produced should be able to roundtrip with 2.11 End-of-Line Handling
3787 and 3.3.3 Attribute-Value Normalization.
3788
3789 If \a performAVN is true, characters will be escaped to survive Attribute Value Normalization.
3790 If \a encodeEOLs is true, characters will be escaped to survive End-of-Line Handling.
3791*/
3792static QString encodeText(const QString &str,
3793 const bool encodeQuotes = true,
3794 const bool performAVN = false,
3795 const bool encodeEOLs = false)
3796{
3797 QString retval;
3798 qsizetype start = 0;
3799 auto appendToOutput = [&](qsizetype cur, const auto &replacement)
3800 {
3801 if (start < cur) {
3802 retval.reserve(str.size() + replacement.size());
3803 retval.append(QStringView(str).first(cur).sliced(start));
3804 }
3805 // Skip over str[cur], replaced by replacement
3806 start = cur + 1;
3807 retval.append(replacement);
3808 };
3809
3810 const qsizetype len = str.size();
3811 for (qsizetype cur = 0; cur < len; ++cur) {
3812 switch (str[cur].unicode()) {
3813 case u'<':
3814 appendToOutput(cur, "&lt;"_L1);
3815 break;
3816 case u'"':
3817 if (encodeQuotes)
3818 appendToOutput(cur, "&quot;"_L1);
3819 break;
3820 case u'&':
3821 appendToOutput(cur, "&amp;"_L1);
3822 break;
3823 case u'>':
3824 if (cur >= 2 && str[cur - 1] == u']' && str[cur - 2] == u']')
3825 appendToOutput(cur, "&gt;"_L1);
3826 break;
3827 case u'\r':
3828 if (performAVN || encodeEOLs)
3829 appendToOutput(cur, "&#xd;"_L1); // \r == 0x0d
3830 break;
3831 case u'\n':
3832 if (performAVN)
3833 appendToOutput(cur, "&#xa;"_L1); // \n == 0x0a
3834 break;
3835 case u'\t':
3836 if (performAVN)
3837 appendToOutput(cur, "&#x9;"_L1); // \t == 0x09
3838 break;
3839 default:
3840 break;
3841 }
3842 }
3843 if (start > 0) {
3844 retval.append(QStringView(str).first(len).sliced(start));
3845 return retval;
3846 }
3847 return str;
3848}
3849
3850void QDomAttrPrivate::save(QTextStream& s, int, int) const
3851{
3852 if (namespaceURI.isNull()) {
3853 s << name << "=\"" << encodeText(value, true, true) << '\"';
3854 } else {
3855 s << prefix << ':' << name << "=\"" << encodeText(value, true, true) << '\"';
3856 /* This is a fix for 138243, as good as it gets.
3857 *
3858 * QDomElementPrivate::save() output a namespace declaration if
3859 * the element is in a namespace, no matter what. This function do as well, meaning
3860 * that we get two identical namespace declaration if we don't have the if-
3861 * statement below.
3862 *
3863 * This doesn't work when the parent element has the same prefix as us but
3864 * a different namespace. However, this can only occur by the user modifying the element,
3865 * and we don't do fixups by that anyway, and hence it's the user responsibility to not
3866 * arrive in those situations. */
3867 if (!ownerNode ||
3868 ownerNode->prefix != prefix) {
3869 s << " xmlns:" << prefix << "=\"" << encodeText(namespaceURI, true, true) << '\"';
3870 }
3871 }
3872}
3873
3874/**************************************************************
3875 *
3876 * QDomAttr
3877 *
3878 **************************************************************/
3879
3880#define IMPL static_cast<QDomAttrPrivate *>(impl)
3881
3882/*!
3883 \class QDomAttr
3884 \reentrant
3885 \brief The QDomAttr class represents one attribute of a QDomElement.
3886
3887 \inmodule QtXml
3888 \ingroup xml-tools
3889
3890 For example, the following piece of XML produces an element with
3891 no children, but two attributes:
3892
3893 \snippet code/src_xml_dom_qdom_snippet.cpp 7
3894
3895 You can access the attributes of an element with code like this:
3896
3897 \snippet code/src_xml_dom_qdom.cpp 8
3898
3899 This example also shows that changing an attribute received from
3900 an element changes the attribute of the element. If you do not
3901 want to change the value of the element's attribute you must
3902 use cloneNode() to get an independent copy of the attribute.
3903
3904 QDomAttr can return the name() and value() of an attribute. An
3905 attribute's value is set with setValue(). If specified() returns
3906 true the value was set with setValue(). The node this
3907 attribute is attached to (if any) is returned by ownerElement().
3908
3909 For further information about the Document Object Model see
3910 \l{http://www.w3.org/TR/REC-DOM-Level-1/} and
3911 \l{http://www.w3.org/TR/DOM-Level-2-Core/}.
3912 For a more general introduction of the DOM implementation see the
3913 QDomDocument documentation.
3914*/
3915
3916
3917/*!
3918 Constructs an empty attribute.
3919*/
3920QDomAttr::QDomAttr()
3921{
3922}
3923
3924/*!
3925 Constructs a copy of \a attr.
3926
3927 The data of the copy is shared (shallow copy): modifying one node
3928 will also change the other. If you want to make a deep copy, use
3929 cloneNode().
3930*/
3931QDomAttr::QDomAttr(const QDomAttr &attr)
3932 : QDomNode(attr)
3933{
3934}
3935
3936QDomAttr::QDomAttr(QDomAttrPrivate* n)
3937 : QDomNode(n)
3938{
3939}
3940
3941/*!
3942 Assigns \a other to this DOM attribute.
3943
3944 The data of the copy is shared (shallow copy): modifying one node
3945 will also change the other. If you want to make a deep copy, use
3946 cloneNode().
3947*/
3948QDomAttr &QDomAttr::operator=(const QDomAttr &other) = default;
3949
3950/*!
3951 Returns the attribute's name.
3952*/
3953QString QDomAttr::name() const
3954{
3955 if (!impl)
3956 return QString();
3957 return impl->nodeName();
3958}
3959
3960/*!
3961 Returns \c true if the attribute has been set by the user with setValue().
3962 Returns \c false if the value hasn't been specified or set.
3963
3964 \sa setValue()
3965*/
3966bool QDomAttr::specified() const
3967{
3968 if (!impl)
3969 return false;
3970 return IMPL->specified();
3971}
3972
3973/*!
3974 Returns the element node this attribute is attached to or a
3975 \l{QDomNode::isNull()}{null node} if this attribute is not
3976 attached to any element.
3977*/
3978QDomElement QDomAttr::ownerElement() const
3979{
3980 Q_ASSERT(impl->parent());
3981 if (!impl->parent()->isElement())
3982 return QDomElement();
3983 return QDomElement(static_cast<QDomElementPrivate *>(impl->parent()));
3984}
3985
3986/*!
3987 Returns the value of the attribute or an empty string if the
3988 attribute has not been specified.
3989
3990 \sa specified(), setValue()
3991*/
3992QString QDomAttr::value() const
3993{
3994 if (!impl)
3995 return QString();
3996 return impl->nodeValue();
3997}
3998
3999/*!
4000 Sets the attribute's value to \a value.
4001
4002 \sa value()
4003*/
4004void QDomAttr::setValue(const QString &value)
4005{
4006 if (!impl)
4007 return;
4008 impl->setNodeValue(value);
4009 IMPL->m_specified = true;
4010}
4011
4012/*!
4013 \fn QDomNode::NodeType QDomAttr::nodeType() const
4014
4015 Returns \l{QDomNode::NodeType}{AttributeNode}.
4016*/
4017
4018#undef IMPL
4019
4020/**************************************************************
4021 *
4022 * QDomElementPrivate
4023 *
4024 **************************************************************/
4025
4026QDomElementPrivate::QDomElementPrivate(QDomDocumentPrivate* d, QDomNodePrivate* p,
4027 const QString& tagname)
4028 : QDomNodePrivate(d, p)
4029{
4030 name = tagname;
4031 m_attr = new QDomNamedNodeMapPrivate(this);
4032}
4033
4034QDomElementPrivate::QDomElementPrivate(QDomDocumentPrivate* d, QDomNodePrivate* p,
4035 const QString& nsURI, const QString& qName)
4036 : QDomNodePrivate(d, p)
4037{
4038 qt_split_namespace(prefix, name, qName, !nsURI.isNull());
4039 namespaceURI = nsURI;
4040 createdWithDom1Interface = false;
4041 m_attr = new QDomNamedNodeMapPrivate(this);
4042}
4043
4044QDomElementPrivate::QDomElementPrivate(QDomElementPrivate* n, bool deep) :
4045 QDomNodePrivate(n, deep)
4046{
4047 m_attr = n->m_attr->clone(this);
4048 // Reference is down to 0, so we set it to 1 here.
4049 m_attr->ref.ref();
4050}
4051
4052QDomElementPrivate::~QDomElementPrivate()
4053{
4054 if (!m_attr->ref.deref())
4055 delete m_attr;
4056}
4057
4058QDomNodePrivate* QDomElementPrivate::cloneNode(bool deep)
4059{
4060 QDomNodePrivate* p = new QDomElementPrivate(this, deep);
4061 // We are not interested in this node
4062 p->ref.deref();
4063 return p;
4064}
4065
4066QString QDomElementPrivate::attribute(const QString& name_, const QString& defValue) const
4067{
4068 QDomNodePrivate* n = m_attr->namedItem(name_);
4069 if (!n)
4070 return defValue;
4071
4072 return n->nodeValue();
4073}
4074
4075QString QDomElementPrivate::attributeNS(const QString& nsURI, const QString& localName, const QString& defValue) const
4076{
4077 QDomNodePrivate* n = m_attr->namedItemNS(nsURI, localName);
4078 if (!n)
4079 return defValue;
4080
4081 return n->nodeValue();
4082}
4083
4084void QDomElementPrivate::setAttribute(const QString& aname, const QString& newValue)
4085{
4086 QDomNodePrivate* n = m_attr->namedItem(aname);
4087 if (!n) {
4088 n = new QDomAttrPrivate(ownerDocument(), this, aname);
4089 n->setNodeValue(newValue);
4090
4091 // Referencing is done by the map, so we set the reference counter back
4092 // to 0 here. This is ok since we created the QDomAttrPrivate.
4093 n->ref.deref();
4094 m_attr->setNamedItem(n);
4095 } else {
4096 n->setNodeValue(newValue);
4097 }
4098}
4099
4100void QDomElementPrivate::setAttributeNS(const QString& nsURI, const QString& qName, const QString& newValue)
4101{
4102 QString prefix, localName;
4103 qt_split_namespace(prefix, localName, qName, true);
4104 QDomNodePrivate* n = m_attr->namedItemNS(nsURI, localName);
4105 if (!n) {
4106 n = new QDomAttrPrivate(ownerDocument(), this, nsURI, qName);
4107 n->setNodeValue(newValue);
4108
4109 // Referencing is done by the map, so we set the reference counter back
4110 // to 0 here. This is ok since we created the QDomAttrPrivate.
4111 n->ref.deref();
4112 m_attr->setNamedItem(n);
4113 } else {
4114 n->setNodeValue(newValue);
4115 n->prefix = std::move(prefix);
4116 }
4117}
4118
4119void QDomElementPrivate::removeAttribute(const QString& aname)
4120{
4121 QDomNodePrivate* p = m_attr->removeNamedItem(aname);
4122 if (p && p->ref.loadRelaxed() == 0)
4123 delete p;
4124}
4125
4126QDomAttrPrivate* QDomElementPrivate::attributeNode(const QString& aname)
4127{
4128 return static_cast<QDomAttrPrivate *>(m_attr->namedItem(aname));
4129}
4130
4131QDomAttrPrivate* QDomElementPrivate::attributeNodeNS(const QString& nsURI, const QString& localName)
4132{
4133 return static_cast<QDomAttrPrivate *>(m_attr->namedItemNS(nsURI, localName));
4134}
4135
4136QDomAttrPrivate* QDomElementPrivate::setAttributeNode(QDomAttrPrivate* newAttr)
4137{
4138 if (!newAttr)
4139 return nullptr;
4140
4141 QDomNodePrivate* foundAttr = m_attr->namedItem(newAttr->nodeName());
4142 if (foundAttr)
4143 m_attr->removeNamedItem(newAttr->nodeName());
4144
4145 // Referencing is done by the maps
4146 m_attr->setNamedItem(newAttr);
4147 newAttr->setParent(this);
4148
4149 return static_cast<QDomAttrPrivate *>(foundAttr);
4150}
4151
4152QDomAttrPrivate* QDomElementPrivate::setAttributeNodeNS(QDomAttrPrivate* newAttr)
4153{
4154 QDomNodePrivate* n = nullptr;
4155 if (!newAttr->prefix.isNull())
4156 n = m_attr->namedItemNS(newAttr->namespaceURI, newAttr->name);
4157
4158 // Referencing is done by the maps
4159 m_attr->setNamedItem(newAttr);
4160
4161 return static_cast<QDomAttrPrivate *>(n);
4162}
4163
4164QDomAttrPrivate* QDomElementPrivate::removeAttributeNode(QDomAttrPrivate* oldAttr)
4165{
4166 return static_cast<QDomAttrPrivate *>(m_attr->removeNamedItem(oldAttr->nodeName()));
4167}
4168
4169bool QDomElementPrivate::hasAttribute(const QString& aname) const
4170{
4171 return m_attr->contains(aname);
4172}
4173
4174bool QDomElementPrivate::hasAttributeNS(const QString& nsURI, const QString& localName) const
4175{
4176 return m_attr->containsNS(nsURI, localName);
4177}
4178
4179QString QDomElementPrivate::text() const
4180{
4181 QString t(u""_s);
4182
4183 // pre-order depth-first-search; visitation is t += nodeValue()
4184 if (QDomNodePrivate* p = first) {
4185 while (true) {
4186 if (p->isText() || p->isCDATASection()) {
4187 t += p->nodeValue();
4188 } else if (p->isElement() && p->first) {
4189 p = p->first; // descend into Elements
4190 continue;
4191 }
4192
4193 while (!p->next) {
4194 p = p->parent(); // ascend into visited parent (pre-order DFS)
4195 if (p == this)
4196 return t; // done
4197 }
4198
4199 p = p->next;
4200 }
4201 }
4202 return t;
4203}
4204
4205void QDomElementPrivate::save(QTextStream& s, int depth, int indent) const
4206{
4207 if (!(prev && prev->isText()))
4208 s << QString(indent < 1 ? 0 : depth * indent, u' ');
4209
4210 QString qName(name);
4211 QString nsDecl(u""_s);
4212 if (!namespaceURI.isNull()) {
4213 /** ###
4214 *
4215 * If we still have QDom, optimize this so that we only declare namespaces that are not
4216 * yet declared. We loose default namespace mappings, so maybe we should rather store
4217 * the information that we get from startPrefixMapping()/endPrefixMapping() and use them.
4218 * Modifications becomes more complex then, however.
4219 *
4220 * We cannot do this in a patch release because it would require too invasive changes, and
4221 * hence possibly behavioral changes.
4222 */
4223 if (prefix.isEmpty()) {
4224 nsDecl = u" xmlns"_s;
4225 } else {
4226 qName = prefix + u':' + name;
4227 nsDecl = u" xmlns:"_s + prefix;
4228 }
4229 nsDecl += u"=\""_s + encodeText(namespaceURI) + u'\"';
4230 }
4231 s << '<' << qName << nsDecl;
4232
4233
4234 /* Write out attributes. */
4235 if (!m_attr->map.isEmpty()) {
4236 /*
4237 * To ensure that we always output attributes in a consistent
4238 * order, sort the attributes before writing them into the
4239 * stream. (Note that the order may be different than the one
4240 * that e.g. we've read from a file, or the program order in
4241 * which these attributes have been populated. We just want to
4242 * guarantee reproducibile outputs.)
4243 */
4244 struct SavedAttribute {
4245 QString prefix;
4246 QString name;
4247 QString encodedValue;
4248 };
4249
4250 /* Gather all the attributes to save. */
4251 QVarLengthArray<SavedAttribute, 8> attributesToSave;
4252 attributesToSave.reserve(m_attr->map.size());
4253
4254 QDuplicateTracker<QString> outputtedPrefixes;
4255 for (const auto &[key, value] : std::as_const(m_attr->map).asKeyValueRange()) {
4256 Q_UNUSED(key); /* We extract the attribute name from the value. */
4257 bool mayNeedXmlNS = false;
4258
4259 SavedAttribute attr;
4260 attr.name = value->name;
4261 attr.encodedValue = encodeText(value->value, true, true);
4262 if (!value->namespaceURI.isNull()) {
4263 attr.prefix = value->prefix;
4264 mayNeedXmlNS = true;
4265 }
4266
4267 attributesToSave.push_back(std::move(attr));
4268
4269 /*
4270 * This is a fix for 138243, as good as it gets.
4271 *
4272 * QDomElementPrivate::save() output a namespace
4273 * declaration if the element is in a namespace, no matter
4274 * what. This function do as well, meaning that we get two
4275 * identical namespace declaration if we don't have the if-
4276 * statement below.
4277 *
4278 * This doesn't work when the parent element has the same
4279 * prefix as us but a different namespace. However, this
4280 * can only occur by the user modifying the element, and we
4281 * don't do fixups by that anyway, and hence it's the user
4282 * responsibility to avoid those situations.
4283 */
4284
4285 if (mayNeedXmlNS
4286 && ((!value->ownerNode || value->ownerNode->prefix != value->prefix)
4287 && !outputtedPrefixes.hasSeen(value->prefix)))
4288 {
4289 SavedAttribute nsAttr;
4290 nsAttr.prefix = QStringLiteral("xmlns");
4291 nsAttr.name = value->prefix;
4292 nsAttr.encodedValue = encodeText(value->namespaceURI, true, true);
4293 attributesToSave.push_back(std::move(nsAttr));
4294 }
4295 }
4296
4297 /* Sort the attributes by prefix and name. */
4298 const auto savedAttributeComparator = [](const SavedAttribute &lhs, const SavedAttribute &rhs)
4299 {
4300 const int cmp = QString::compare(lhs.prefix, rhs.prefix);
4301 return (cmp < 0) || ((cmp == 0) && (lhs.name < rhs.name));
4302 };
4303
4304 std::sort(attributesToSave.begin(), attributesToSave.end(), savedAttributeComparator);
4305
4306 /* Actually stream the sorted attributes. */
4307 for (const auto &attr : attributesToSave) {
4308 s << ' ';
4309 if (!attr.prefix.isEmpty())
4310 s << attr.prefix << ':';
4311 s << attr.name << "=\"" << attr.encodedValue << '\"';
4312 }
4313 }
4314
4315 if (last) {
4316 // has child nodes
4317 if (first->isText())
4318 s << '>';
4319 else {
4320 s << '>';
4321
4322 /* -1 disables new lines. */
4323 if (indent != -1)
4324 s << Qt::endl;
4325 }
4326 } else {
4327 s << "/>";
4328 }
4329}
4330
4331void QDomElementPrivate::afterSave(QTextStream &s, int depth, int indent) const
4332{
4333 if (last) {
4334 QString qName(name);
4335
4336 if (!prefix.isEmpty())
4337 qName = prefix + u':' + name;
4338
4339 if (!last->isText())
4340 s << QString(indent < 1 ? 0 : depth * indent, u' ');
4341
4342 s << "</" << qName << '>';
4343 }
4344
4345 if (!(next && next->isText())) {
4346 /* -1 disables new lines. */
4347 if (indent != -1)
4348 s << Qt::endl;
4349 }
4350}
4351
4352/**************************************************************
4353 *
4354 * QDomElement
4355 *
4356 **************************************************************/
4357
4358#define IMPL static_cast<QDomElementPrivate *>(impl)
4359
4360/*!
4361 \class QDomElement
4362 \reentrant
4363 \brief The QDomElement class represents one element in the DOM tree.
4364
4365 \inmodule QtXml
4366 \ingroup xml-tools
4367
4368 Elements have a tagName() and zero or more attributes associated
4369 with them. The tag name can be changed with setTagName().
4370
4371 Element attributes are represented by QDomAttr objects that can
4372 be queried using the attribute() and attributeNode() functions.
4373 You can set attributes with the setAttribute() and
4374 setAttributeNode() functions. Attributes can be removed with
4375 removeAttribute(). There are namespace-aware equivalents to these
4376 functions, i.e. setAttributeNS(), setAttributeNodeNS() and
4377 removeAttributeNS().
4378
4379 If you want to access the text of a node use text(), e.g.
4380
4381 \snippet code/src_xml_dom_qdom_snippet.cpp 9
4382
4383 The text() function operates recursively to find the text (since
4384 not all elements contain text). If you want to find all the text
4385 in all of a node's children, iterate over the children looking for
4386 QDomText nodes, e.g.
4387
4388 \snippet code/src_xml_dom_qdom.cpp 10
4389
4390 Note that we attempt to convert each node to a text node and use
4391 text() rather than using firstChild().toText().data() or
4392 n.toText().data() directly on the node, because the node may not
4393 be a text element.
4394
4395 You can get a list of all the descendents of an element which have
4396 a specified tag name with elementsByTagName() or
4397 elementsByTagNameNS().
4398
4399 To browse the elements of a dom document use firstChildElement(), lastChildElement(),
4400 nextSiblingElement() and previousSiblingElement(). For example, to iterate over all
4401 child elements called "entry" in a root element called "database", you can use:
4402
4403 \snippet code/src_xml_dom_qdom_snippet.cpp 11
4404
4405 For further information about the Document Object Model see
4406 \l{W3C DOM Level 1}{Level 1} and
4407 \l{W3C DOM Level 2}{Level 2 Core}.
4408 For a more general introduction of the DOM implementation see the
4409 QDomDocument documentation.
4410*/
4411
4412/*!
4413 Constructs an empty element. Use the QDomDocument::createElement()
4414 function to construct elements with content.
4415*/
4416QDomElement::QDomElement()
4417 : QDomNode()
4418{
4419}
4420
4421/*!
4422 Constructs a copy of \a element.
4423
4424 The data of the copy is shared (shallow copy): modifying one node
4425 will also change the other. If you want to make a deep copy, use
4426 cloneNode().
4427*/
4428QDomElement::QDomElement(const QDomElement &element)
4429 : QDomNode(element)
4430{
4431}
4432
4433QDomElement::QDomElement(QDomElementPrivate* n)
4434 : QDomNode(n)
4435{
4436}
4437
4438/*!
4439 Assigns \a other to this DOM element.
4440
4441 The data of the copy is shared (shallow copy): modifying one node
4442 will also change the other. If you want to make a deep copy, use
4443 cloneNode().
4444*/
4445QDomElement &QDomElement::operator=(const QDomElement &other) = default;
4446
4447/*!
4448 \fn QDomNode::NodeType QDomElement::nodeType() const
4449
4450 Returns \c ElementNode.
4451*/
4452
4453/*!
4454 Sets this element's tag name to \a name.
4455
4456 \sa tagName()
4457*/
4458void QDomElement::setTagName(const QString& name)
4459{
4460 if (impl)
4461 impl->name = name;
4462}
4463
4464/*!
4465 Returns the tag name of this element. For an XML element like this:
4466
4467 \snippet code/src_xml_dom_qdom_snippet.cpp 12
4468
4469 the tagname would return "img".
4470
4471 \sa setTagName()
4472*/
4473QString QDomElement::tagName() const
4474{
4475 if (!impl)
4476 return QString();
4477 return impl->nodeName();
4478}
4479
4480
4481/*!
4482 Returns a QDomNamedNodeMap containing all this element's attributes.
4483
4484 \sa attribute(), setAttribute(), attributeNode(), setAttributeNode()
4485*/
4486QDomNamedNodeMap QDomElement::attributes() const
4487{
4488 if (!impl)
4489 return QDomNamedNodeMap();
4490 return QDomNamedNodeMap(IMPL->attributes());
4491}
4492
4493/*!
4494 Returns the attribute called \a name. If the attribute does not
4495 exist \a defValue is returned.
4496
4497 \sa setAttribute(), attributeNode(), setAttributeNode(), attributeNS()
4498*/
4499QString QDomElement::attribute(const QString& name, const QString& defValue) const
4500{
4501 if (!impl)
4502 return defValue;
4503 return IMPL->attribute(name, defValue);
4504}
4505
4506/*!
4507 Adds an attribute called \a name with value \a value. If an
4508 attribute with the same name exists, its value is replaced by \a
4509 value.
4510
4511 \sa attribute(), setAttributeNode(), setAttributeNS()
4512*/
4513void QDomElement::setAttribute(const QString& name, const QString& value)
4514{
4515 if (!impl)
4516 return;
4517 IMPL->setAttribute(name, value);
4518}
4519
4520/*!
4521 \fn void QDomElement::setAttribute(const QString& name, int value)
4522
4523 \overload
4524 The formatting always uses QLocale::C.
4525*/
4526
4527/*!
4528 \fn void QDomElement::setAttribute(const QString& name, uint value)
4529
4530 \overload
4531 The formatting always uses QLocale::C.
4532*/
4533
4534/*!
4535 \overload
4536
4537 The formatting always uses QLocale::C.
4538*/
4539void QDomElement::setAttribute(const QString& name, qlonglong value)
4540{
4541 if (!impl)
4542 return;
4543 QString x;
4544 x.setNum(value);
4545 IMPL->setAttribute(name, x);
4546}
4547
4548/*!
4549 \overload
4550
4551 The formatting always uses QLocale::C.
4552*/
4553void QDomElement::setAttribute(const QString& name, qulonglong value)
4554{
4555 if (!impl)
4556 return;
4557 QString x;
4558 x.setNum(value);
4559 IMPL->setAttribute(name, x);
4560}
4561
4562/*!
4563 \overload
4564
4565 The formatting always uses QLocale::C.
4566*/
4567void QDomElement::setAttribute(const QString& name, float value)
4568{
4569 if (!impl)
4570 return;
4571 QString x;
4572 x.setNum(value, 'g', 8);
4573 IMPL->setAttribute(name, x);
4574}
4575
4576/*!
4577 \overload
4578
4579 The formatting always uses QLocale::C.
4580*/
4581void QDomElement::setAttribute(const QString& name, double value)
4582{
4583 if (!impl)
4584 return;
4585 QString x;
4586 x.setNum(value, 'g', 17);
4587 IMPL->setAttribute(name, x);
4588}
4589
4590/*!
4591 Removes the attribute called name \a name from this element.
4592
4593 \sa setAttribute(), attribute(), removeAttributeNS()
4594*/
4595void QDomElement::removeAttribute(const QString& name)
4596{
4597 if (!impl)
4598 return;
4599 IMPL->removeAttribute(name);
4600}
4601
4602/*!
4603 Returns the QDomAttr object that corresponds to the attribute
4604 called \a name. If no such attribute exists a
4605 \l{QDomNode::isNull()}{null attribute} is returned.
4606
4607 \sa setAttributeNode(), attribute(), setAttribute(), attributeNodeNS()
4608*/
4609QDomAttr QDomElement::attributeNode(const QString& name)
4610{
4611 if (!impl)
4612 return QDomAttr();
4613 return QDomAttr(IMPL->attributeNode(name));
4614}
4615
4616/*!
4617 Adds the attribute \a newAttr to this element.
4618
4619 If the element has another attribute that has the same name as \a
4620 newAttr, this function replaces that attribute and returns it;
4621 otherwise the function returns a
4622 \l{QDomNode::isNull()}{null attribute}.
4623
4624 \sa attributeNode(), setAttribute(), setAttributeNodeNS()
4625*/
4626QDomAttr QDomElement::setAttributeNode(const QDomAttr& newAttr)
4627{
4628 if (!impl)
4629 return QDomAttr();
4630 return QDomAttr(IMPL->setAttributeNode(static_cast<QDomAttrPrivate *>(newAttr.impl)));
4631}
4632
4633/*!
4634 Removes the attribute \a oldAttr from the element and returns it.
4635
4636 \sa attributeNode(), setAttributeNode()
4637*/
4638QDomAttr QDomElement::removeAttributeNode(const QDomAttr& oldAttr)
4639{
4640 if (!impl)
4641 return QDomAttr(); // ### should this return oldAttr?
4642 return QDomAttr(IMPL->removeAttributeNode(static_cast<QDomAttrPrivate *>(oldAttr.impl)));
4643}
4644
4645/*!
4646 Returns a QDomNodeList containing all descendants of this element
4647 named \a tagname encountered during a preorder traversal of the
4648 element subtree with this element as its root. The order of the
4649 elements in the returned list is the order they are encountered
4650 during the preorder traversal.
4651
4652 \sa elementsByTagNameNS(), QDomDocument::elementsByTagName()
4653*/
4654QDomNodeList QDomElement::elementsByTagName(const QString& tagname) const
4655{
4656 return QDomNodeList(new QDomNodeListPrivate(impl, tagname));
4657}
4658
4659/*!
4660 Returns \c true if this element has an attribute called \a name;
4661 otherwise returns \c false.
4662
4663 \b{Note:} This function does not take the presence of namespaces
4664 into account. As a result, the specified name will be tested
4665 against fully-qualified attribute names that include any namespace
4666 prefixes that may be present.
4667
4668 Use hasAttributeNS() to explicitly test for attributes with specific
4669 namespaces and names.
4670*/
4671bool QDomElement::hasAttribute(const QString& name) const
4672{
4673 if (!impl)
4674 return false;
4675 return IMPL->hasAttribute(name);
4676}
4677
4678/*!
4679 Returns the attribute with the local name \a localName and the
4680 namespace URI \a nsURI. If the attribute does not exist \a
4681 defValue is returned.
4682
4683 \sa setAttributeNS(), attributeNodeNS(), setAttributeNodeNS(), attribute()
4684*/
4685QString QDomElement::attributeNS(const QString& nsURI, const QString& localName, const QString& defValue) const
4686{
4687 if (!impl)
4688 return defValue;
4689 return IMPL->attributeNS(nsURI, localName, defValue);
4690}
4691
4692/*!
4693 Adds an attribute with the qualified name \a qName and the
4694 namespace URI \a nsURI with the value \a value. If an attribute
4695 with the same local name and namespace URI exists, its prefix is
4696 replaced by the prefix of \a qName and its value is replaced by \a
4697 value.
4698
4699 Although \a qName is the qualified name, the local name is used to
4700 decide if an existing attribute's value should be replaced.
4701
4702 \sa attributeNS(), setAttributeNodeNS(), setAttribute()
4703*/
4704void QDomElement::setAttributeNS(const QString& nsURI, const QString& qName, const QString& value)
4705{
4706 if (!impl)
4707 return;
4708 IMPL->setAttributeNS(nsURI, qName, value);
4709}
4710
4711/*!
4712 \fn void QDomElement::setAttributeNS(const QString& nsURI, const QString& qName, int value)
4713
4714 \overload
4715*/
4716
4717/*!
4718 \fn void QDomElement::setAttributeNS(const QString& nsURI, const QString& qName, uint value)
4719
4720 \overload
4721*/
4722
4723/*!
4724 \overload
4725*/
4726void QDomElement::setAttributeNS(const QString& nsURI, const QString& qName, qlonglong value)
4727{
4728 if (!impl)
4729 return;
4730 QString x;
4731 x.setNum(value);
4732 IMPL->setAttributeNS(nsURI, qName, x);
4733}
4734
4735/*!
4736 \overload
4737*/
4738void QDomElement::setAttributeNS(const QString& nsURI, const QString& qName, qulonglong value)
4739{
4740 if (!impl)
4741 return;
4742 QString x;
4743 x.setNum(value);
4744 IMPL->setAttributeNS(nsURI, qName, x);
4745}
4746
4747/*!
4748 \overload
4749*/
4750void QDomElement::setAttributeNS(const QString& nsURI, const QString& qName, double value)
4751{
4752 if (!impl)
4753 return;
4754 QString x;
4755 x.setNum(value, 'g', 17);
4756 IMPL->setAttributeNS(nsURI, qName, x);
4757}
4758
4759/*!
4760 Removes the attribute with the local name \a localName and the
4761 namespace URI \a nsURI from this element.
4762
4763 \sa setAttributeNS(), attributeNS(), removeAttribute()
4764*/
4765void QDomElement::removeAttributeNS(const QString& nsURI, const QString& localName)
4766{
4767 if (!impl)
4768 return;
4769 QDomNodePrivate *n = IMPL->attributeNodeNS(nsURI, localName);
4770 if (!n)
4771 return;
4772 IMPL->removeAttribute(n->nodeName());
4773}
4774
4775/*!
4776 Returns the QDomAttr object that corresponds to the attribute
4777 with the local name \a localName and the namespace URI \a nsURI.
4778 If no such attribute exists a \l{QDomNode::isNull()}{null
4779 attribute} is returned.
4780
4781 \sa setAttributeNode(), attribute(), setAttribute()
4782*/
4783QDomAttr QDomElement::attributeNodeNS(const QString& nsURI, const QString& localName)
4784{
4785 if (!impl)
4786 return QDomAttr();
4787 return QDomAttr(IMPL->attributeNodeNS(nsURI, localName));
4788}
4789
4790/*!
4791 Adds the attribute \a newAttr to this element.
4792
4793 If the element has another attribute that has the same local name
4794 and namespace URI as \a newAttr, this function replaces that
4795 attribute and returns it; otherwise the function returns a
4796 \l{QDomNode::isNull()}{null attribute}.
4797
4798 \sa attributeNodeNS(), setAttributeNS(), setAttributeNode()
4799*/
4800QDomAttr QDomElement::setAttributeNodeNS(const QDomAttr& newAttr)
4801{
4802 if (!impl)
4803 return QDomAttr();
4804 return QDomAttr(IMPL->setAttributeNodeNS(static_cast<QDomAttrPrivate *>(newAttr.impl)));
4805}
4806
4807/*!
4808 Returns a QDomNodeList containing all descendants of this element
4809 with local name \a localName and namespace URI \a nsURI encountered
4810 during a preorder traversal of the element subtree with this element
4811 as its root. The order of the elements in the returned list is the
4812 order they are encountered during the preorder traversal.
4813
4814 \sa elementsByTagName(), QDomDocument::elementsByTagNameNS()
4815*/
4816QDomNodeList QDomElement::elementsByTagNameNS(const QString& nsURI, const QString& localName) const
4817{
4818 return QDomNodeList(new QDomNodeListPrivate(impl, nsURI, localName));
4819}
4820
4821/*!
4822 Returns \c true if this element has an attribute with the local name
4823 \a localName and the namespace URI \a nsURI; otherwise returns
4824 false.
4825*/
4826bool QDomElement::hasAttributeNS(const QString& nsURI, const QString& localName) const
4827{
4828 if (!impl)
4829 return false;
4830 return IMPL->hasAttributeNS(nsURI, localName);
4831}
4832
4833/*!
4834 Returns the element's text or an empty string.
4835
4836 Example:
4837 \snippet code/src_xml_dom_qdom_snippet.cpp 13
4838
4839 The function text() of the QDomElement for the \c{<h1>} tag,
4840 will return the following text:
4841
4842 \snippet code/src_xml_dom_qdom_snippet.cpp 14
4843
4844 Comments are ignored by this function. It only evaluates QDomText
4845 and QDomCDATASection objects.
4846*/
4847QString QDomElement::text() const
4848{
4849 if (!impl)
4850 return QString();
4851 return IMPL->text();
4852}
4853
4854#undef IMPL
4855
4856/**************************************************************
4857 *
4858 * QDomTextPrivate
4859 *
4860 **************************************************************/
4861
4862QDomTextPrivate::QDomTextPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent, const QString& val)
4863 : QDomCharacterDataPrivate(d, parent, val)
4864{
4865 name = u"#text"_s;
4866}
4867
4868QDomTextPrivate::QDomTextPrivate(QDomTextPrivate* n, bool deep)
4869 : QDomCharacterDataPrivate(n, deep)
4870{
4871}
4872
4873QDomNodePrivate* QDomTextPrivate::cloneNode(bool deep)
4874{
4875 QDomNodePrivate* p = new QDomTextPrivate(this, deep);
4876 // We are not interested in this node
4877 p->ref.deref();
4878 return p;
4879}
4880
4881QDomTextPrivate* QDomTextPrivate::splitText(int offset)
4882{
4883 if (!parent()) {
4884 qWarning("QDomText::splitText The node has no parent. So I cannot split");
4885 return nullptr;
4886 }
4887
4888 QDomTextPrivate* t = new QDomTextPrivate(ownerDocument(), nullptr, value.mid(offset));
4889 value.truncate(offset);
4890
4891 parent()->insertAfter(t, this);
4892 Q_ASSERT(t->ref.loadRelaxed() == 2);
4893
4894 // We are not interested in this node
4895 t->ref.deref();
4896
4897 return t;
4898}
4899
4900void QDomTextPrivate::save(QTextStream& s, int, int) const
4901{
4902 QDomTextPrivate *that = const_cast<QDomTextPrivate*>(this);
4903 s << encodeText(value, !(that->parent() && that->parent()->isElement()), false, true);
4904}
4905
4906/**************************************************************
4907 *
4908 * QDomText
4909 *
4910 **************************************************************/
4911
4912#define IMPL static_cast<QDomTextPrivate *>(impl)
4913
4914/*!
4915 \class QDomText
4916 \reentrant
4917 \brief The QDomText class represents text data in the parsed XML document.
4918
4919 \inmodule QtXml
4920 \ingroup xml-tools
4921
4922 You can split the text in a QDomText object over two QDomText
4923 objects with splitText().
4924
4925 For further information about the Document Object Model see
4926 \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and
4927 \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}.
4928 For a more general introduction of the DOM implementation see the
4929 QDomDocument documentation.
4930*/
4931
4932/*!
4933 Constructs an empty QDomText object.
4934
4935 To construct a QDomText with content, use QDomDocument::createTextNode().
4936*/
4937QDomText::QDomText()
4938 : QDomCharacterData()
4939{
4940}
4941
4942/*!
4943 Constructs a copy of \a text.
4944
4945 The data of the copy is shared (shallow copy): modifying one node
4946 will also change the other. If you want to make a deep copy, use
4947 cloneNode().
4948*/
4949QDomText::QDomText(const QDomText &text)
4950 : QDomCharacterData(text)
4951{
4952}
4953
4954QDomText::QDomText(QDomTextPrivate* n)
4955 : QDomCharacterData(n)
4956{
4957}
4958
4959/*!
4960 Assigns \a other to this DOM text.
4961
4962 The data of the copy is shared (shallow copy): modifying one node
4963 will also change the other. If you want to make a deep copy, use
4964 cloneNode().
4965*/
4966QDomText &QDomText::operator=(const QDomText &other) = default;
4967
4968/*!
4969 \fn QDomNode::NodeType QDomText::nodeType() const
4970
4971 Returns \c TextNode.
4972*/
4973
4974/*!
4975 Splits this DOM text object into two QDomText objects. This object
4976 keeps its first \a offset characters and the second (newly
4977 created) object is inserted into the document tree after this
4978 object with the remaining characters.
4979
4980 The function returns the newly created object.
4981
4982 \sa QDomNode::normalize()
4983*/
4984QDomText QDomText::splitText(int offset)
4985{
4986 if (!impl)
4987 return QDomText();
4988 return QDomText(IMPL->splitText(offset));
4989}
4990
4991#undef IMPL
4992
4993/**************************************************************
4994 *
4995 * QDomCommentPrivate
4996 *
4997 **************************************************************/
4998
4999QDomCommentPrivate::QDomCommentPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent, const QString& val)
5000 : QDomCharacterDataPrivate(d, parent, val)
5001{
5002 name = u"#comment"_s;
5003}
5004
5005QDomCommentPrivate::QDomCommentPrivate(QDomCommentPrivate* n, bool deep)
5006 : QDomCharacterDataPrivate(n, deep)
5007{
5008}
5009
5010
5011QDomNodePrivate* QDomCommentPrivate::cloneNode(bool deep)
5012{
5013 QDomNodePrivate* p = new QDomCommentPrivate(this, deep);
5014 // We are not interested in this node
5015 p->ref.deref();
5016 return p;
5017}
5018
5019void QDomCommentPrivate::save(QTextStream& s, int depth, int indent) const
5020{
5021 /* We don't output whitespace if we would pollute a text node. */
5022 if (!(prev && prev->isText()))
5023 s << QString(indent < 1 ? 0 : depth * indent, u' ');
5024
5025 s << "<!--" << value;
5026 if (value.endsWith(u'-'))
5027 s << ' '; // Ensures that XML comment doesn't end with --->
5028 s << "-->";
5029
5030 if (!(next && next->isText()))
5031 s << Qt::endl;
5032}
5033
5034/**************************************************************
5035 *
5036 * QDomComment
5037 *
5038 **************************************************************/
5039
5040/*!
5041 \class QDomComment
5042 \reentrant
5043 \brief The QDomComment class represents an XML comment.
5044
5045 \inmodule QtXml
5046 \ingroup xml-tools
5047
5048 A comment in the parsed XML such as this:
5049
5050 \snippet code/src_xml_dom_qdom_snippet.cpp 15
5051
5052 is represented by QDomComment objects in the parsed Dom tree.
5053
5054 For further information about the Document Object Model see
5055 \l{W3C DOM Level 1}{Level 1} and
5056 \l{W3C DOM Level 2}{Level 2 Core}.
5057 For a more general introduction of the DOM implementation see the
5058 QDomDocument documentation.
5059*/
5060
5061/*!
5062 Constructs an empty comment. To construct a comment with content,
5063 use the QDomDocument::createComment() function.
5064*/
5065QDomComment::QDomComment()
5066 : QDomCharacterData()
5067{
5068}
5069
5070/*!
5071 Constructs a copy of \a comment.
5072
5073 The data of the copy is shared (shallow copy): modifying one node
5074 will also change the other. If you want to make a deep copy, use
5075 cloneNode().
5076*/
5077QDomComment::QDomComment(const QDomComment &comment)
5078 : QDomCharacterData(comment)
5079{
5080}
5081
5082QDomComment::QDomComment(QDomCommentPrivate* n)
5083 : QDomCharacterData(n)
5084{
5085}
5086
5087/*!
5088 Assigns \a other to this DOM comment.
5089
5090 The data of the copy is shared (shallow copy): modifying one node
5091 will also change the other. If you want to make a deep copy, use
5092 cloneNode().
5093*/
5094QDomComment &QDomComment::operator=(const QDomComment &other) = default;
5095
5096/*!
5097 \fn QDomNode::NodeType QDomComment::nodeType() const
5098
5099 Returns \c CommentNode.
5100*/
5101
5102/**************************************************************
5103 *
5104 * QDomCDATASectionPrivate
5105 *
5106 **************************************************************/
5107
5108QDomCDATASectionPrivate::QDomCDATASectionPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent,
5109 const QString& val)
5110 : QDomTextPrivate(d, parent, val)
5111{
5112 name = u"#cdata-section"_s;
5113}
5114
5115QDomCDATASectionPrivate::QDomCDATASectionPrivate(QDomCDATASectionPrivate* n, bool deep)
5116 : QDomTextPrivate(n, deep)
5117{
5118}
5119
5120QDomNodePrivate* QDomCDATASectionPrivate::cloneNode(bool deep)
5121{
5122 QDomNodePrivate* p = new QDomCDATASectionPrivate(this, deep);
5123 // We are not interested in this node
5124 p->ref.deref();
5125 return p;
5126}
5127
5128void QDomCDATASectionPrivate::save(QTextStream& s, int, int) const
5129{
5130 // ### How do we escape "]]>" ?
5131 // "]]>" is not allowed; so there should be none in value anyway
5132 s << "<![CDATA[" << value << "]]>";
5133}
5134
5135/**************************************************************
5136 *
5137 * QDomCDATASection
5138 *
5139 **************************************************************/
5140
5141/*!
5142 \class QDomCDATASection
5143 \reentrant
5144 \brief The QDomCDATASection class represents an XML CDATA section.
5145
5146 \inmodule QtXml
5147 \ingroup xml-tools
5148
5149 CDATA sections are used to escape blocks of text containing
5150 characters that would otherwise be regarded as markup. The only
5151 delimiter that is recognized in a CDATA section is the "]]&gt;"
5152 string that terminates the CDATA section. CDATA sections cannot be
5153 nested. Their primary purpose is for including material such as
5154 XML fragments, without needing to escape all the delimiters.
5155
5156 Adjacent QDomCDATASection nodes are not merged by the
5157 QDomNode::normalize() function.
5158
5159 For further information about the Document Object Model see
5160 \l{http://www.w3.org/TR/REC-DOM-Level-1/} and
5161 \l{http://www.w3.org/TR/DOM-Level-2-Core/}.
5162 For a more general introduction of the DOM implementation see the
5163 QDomDocument documentation.
5164*/
5165
5166/*!
5167 Constructs an empty CDATA section. To create a CDATA section with
5168 content, use the QDomDocument::createCDATASection() function.
5169*/
5170QDomCDATASection::QDomCDATASection()
5171 : QDomText()
5172{
5173}
5174
5175/*!
5176 Constructs a copy of \a cdataSection.
5177
5178 The data of the copy is shared (shallow copy): modifying one node
5179 will also change the other. If you want to make a deep copy, use
5180 cloneNode().
5181*/
5182QDomCDATASection::QDomCDATASection(const QDomCDATASection &cdataSection)
5183 : QDomText(cdataSection)
5184{
5185}
5186
5187QDomCDATASection::QDomCDATASection(QDomCDATASectionPrivate* n)
5188 : QDomText(n)
5189{
5190}
5191
5192/*!
5193 Assigns \a other to this CDATA section.
5194
5195 The data of the copy is shared (shallow copy): modifying one node
5196 will also change the other. If you want to make a deep copy, use
5197 cloneNode().
5198*/
5199QDomCDATASection &QDomCDATASection::operator=(const QDomCDATASection &other) = default;
5200
5201/*!
5202 \fn QDomNode::NodeType QDomCDATASection::nodeType() const
5203
5204 Returns \c CDATASection.
5205*/
5206
5207/**************************************************************
5208 *
5209 * QDomNotationPrivate
5210 *
5211 **************************************************************/
5212
5213QDomNotationPrivate::QDomNotationPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent,
5214 const QString& aname,
5215 const QString& pub, const QString& sys)
5216 : QDomNodePrivate(d, parent)
5217{
5218 name = aname;
5219 m_pub = pub;
5220 m_sys = sys;
5221}
5222
5223QDomNotationPrivate::QDomNotationPrivate(QDomNotationPrivate* n, bool deep)
5224 : QDomNodePrivate(n, deep)
5225{
5226 m_sys = n->m_sys;
5227 m_pub = n->m_pub;
5228}
5229
5230QDomNodePrivate* QDomNotationPrivate::cloneNode(bool deep)
5231{
5232 QDomNodePrivate* p = new QDomNotationPrivate(this, deep);
5233 // We are not interested in this node
5234 p->ref.deref();
5235 return p;
5236}
5237
5238void QDomNotationPrivate::save(QTextStream& s, int, int) const
5239{
5240 s << "<!NOTATION " << name << ' ';
5241 if (!m_pub.isNull()) {
5242 s << "PUBLIC " << quotedValue(m_pub);
5243 if (!m_sys.isNull())
5244 s << ' ' << quotedValue(m_sys);
5245 } else {
5246 s << "SYSTEM " << quotedValue(m_sys);
5247 }
5248 s << '>' << Qt::endl;
5249}
5250
5251/**************************************************************
5252 *
5253 * QDomNotation
5254 *
5255 **************************************************************/
5256
5257#define IMPL static_cast<QDomNotationPrivate *>(impl)
5258
5259/*!
5260 \class QDomNotation
5261 \reentrant
5262 \brief The QDomNotation class represents an XML notation.
5263
5264 \inmodule QtXml
5265 \ingroup xml-tools
5266
5267 A notation either declares, by name, the format of an unparsed
5268 entity (see section 4.7 of the XML 1.0 specification), or is used
5269 for formal declaration of processing instruction targets (see
5270 section 2.6 of the XML 1.0 specification).
5271
5272 DOM does not support editing notation nodes; they are therefore
5273 read-only.
5274
5275 A notation node does not have any parent.
5276
5277 You can retrieve the publicId() and systemId() from a notation
5278 node.
5279
5280 For further information about the Document Object Model see
5281 \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and
5282 \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}.
5283 For a more general introduction of the DOM implementation see the
5284 QDomDocument documentation.
5285*/
5286
5287
5288/*!
5289 Constructor.
5290*/
5291QDomNotation::QDomNotation()
5292 : QDomNode()
5293{
5294}
5295
5296/*!
5297 Constructs a copy of \a notation.
5298
5299 The data of the copy is shared (shallow copy): modifying one node
5300 will also change the other. If you want to make a deep copy, use
5301 cloneNode().
5302*/
5303QDomNotation::QDomNotation(const QDomNotation &notation)
5304 : QDomNode(notation)
5305{
5306}
5307
5308QDomNotation::QDomNotation(QDomNotationPrivate* n)
5309 : QDomNode(n)
5310{
5311}
5312
5313/*!
5314 Assigns \a other to this DOM notation.
5315
5316 The data of the copy is shared (shallow copy): modifying one node
5317 will also change the other. If you want to make a deep copy, use
5318 cloneNode().
5319*/
5320QDomNotation &QDomNotation::operator=(const QDomNotation &other) = default;
5321
5322/*!
5323 \fn QDomNode::NodeType QDomNotation::nodeType() const
5324
5325 Returns \c NotationNode.
5326*/
5327
5328/*!
5329 Returns the public identifier of this notation.
5330*/
5331QString QDomNotation::publicId() const
5332{
5333 if (!impl)
5334 return QString();
5335 return IMPL->m_pub;
5336}
5337
5338/*!
5339 Returns the system identifier of this notation.
5340*/
5341QString QDomNotation::systemId() const
5342{
5343 if (!impl)
5344 return QString();
5345 return IMPL->m_sys;
5346}
5347
5348#undef IMPL
5349
5350/**************************************************************
5351 *
5352 * QDomEntityPrivate
5353 *
5354 **************************************************************/
5355
5356QDomEntityPrivate::QDomEntityPrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent,
5357 const QString& aname,
5358 const QString& pub, const QString& sys, const QString& notation)
5359 : QDomNodePrivate(d, parent)
5360{
5361 name = aname;
5362 m_pub = pub;
5363 m_sys = sys;
5364 m_notationName = notation;
5365}
5366
5367QDomEntityPrivate::QDomEntityPrivate(QDomEntityPrivate* n, bool deep)
5368 : QDomNodePrivate(n, deep)
5369{
5370 m_sys = n->m_sys;
5371 m_pub = n->m_pub;
5372 m_notationName = n->m_notationName;
5373}
5374
5375QDomNodePrivate* QDomEntityPrivate::cloneNode(bool deep)
5376{
5377 QDomNodePrivate* p = new QDomEntityPrivate(this, deep);
5378 // We are not interested in this node
5379 p->ref.deref();
5380 return p;
5381}
5382
5383void QDomEntityPrivate::save(QTextStream& s, int, int) const
5384{
5385 QString _name = name;
5386 if (_name.startsWith(u'%'))
5387 _name = u"% "_s + _name.mid(1);
5388
5389 if (m_sys.isNull() && m_pub.isNull()) {
5390 // entity nodes are only ever created for external entity declarations,
5391 // so at least one of the two IDs is non-null. If we ever change this again,
5392 // we need to re-activate this branch (see git history for historic version).
5393 Q_UNREACHABLE();
5394 } else {
5395 s << "<!ENTITY " << _name << ' ';
5396 if (m_pub.isNull()) {
5397 s << "SYSTEM " << quotedValue(m_sys);
5398 } else {
5399 s << "PUBLIC " << quotedValue(m_pub) << ' ' << quotedValue(m_sys);
5400 }
5401 if (! m_notationName.isNull()) {
5402 s << " NDATA " << m_notationName;
5403 }
5404 s << '>' << Qt::endl;
5405 }
5406}
5407
5408/**************************************************************
5409 *
5410 * QDomEntity
5411 *
5412 **************************************************************/
5413
5414#define IMPL static_cast<QDomEntityPrivate *>(impl)
5415
5416/*!
5417 \class QDomEntity
5418 \reentrant
5419 \brief The QDomEntity class represents an XML entity.
5420
5421 \inmodule QtXml
5422 \ingroup xml-tools
5423
5424 This class represents an entity in an XML document, either parsed
5425 or unparsed. Note that this models the entity itself not the
5426 entity declaration.
5427
5428 \note Only entities declared with a public or a system identifier are
5429 represented. The parser expands internal entities and discards their
5430 declarations, so a QDomEntity is never created for them. See
5431 QDomDocument::setContent() for how entity references are handled.
5432
5433 DOM does not support editing entity nodes; if a user wants to make
5434 changes to the contents of an entity, every related
5435 QDomEntityReference node must be replaced in the DOM tree by a
5436 clone of the entity's contents, and then the desired changes must
5437 be made to each of the clones instead. All the descendants of an
5438 entity node are read-only.
5439
5440 An entity node does not have any parent.
5441
5442 You can access the entity's publicId(), systemId() and
5443 notationName() when available.
5444
5445 For further information about the Document Object Model see
5446 \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and
5447 \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}.
5448 For a more general introduction of the DOM implementation see the
5449 QDomDocument documentation.
5450*/
5451
5452
5453/*!
5454 Constructs an empty entity.
5455*/
5456QDomEntity::QDomEntity()
5457 : QDomNode()
5458{
5459}
5460
5461
5462/*!
5463 Constructs a copy of \a entity.
5464
5465 The data of the copy is shared (shallow copy): modifying one node
5466 will also change the other. If you want to make a deep copy, use
5467 cloneNode().
5468*/
5469QDomEntity::QDomEntity(const QDomEntity &entity)
5470 : QDomNode(entity)
5471{
5472}
5473
5474QDomEntity::QDomEntity(QDomEntityPrivate* n)
5475 : QDomNode(n)
5476{
5477}
5478
5479/*!
5480 Assigns \a other to this DOM entity.
5481
5482 The data of the copy is shared (shallow copy): modifying one node
5483 will also change the other. If you want to make a deep copy, use
5484 cloneNode().
5485*/
5486QDomEntity &QDomEntity::operator=(const QDomEntity &other) = default;
5487
5488/*!
5489 \fn QDomNode::NodeType QDomEntity::nodeType() const
5490
5491 Returns \c EntityNode.
5492*/
5493
5494/*!
5495 Returns the public identifier associated with this entity. If the
5496 public identifier was not specified an empty string is returned.
5497*/
5498QString QDomEntity::publicId() const
5499{
5500 if (!impl)
5501 return QString();
5502 return IMPL->m_pub;
5503}
5504
5505/*!
5506 Returns the system identifier associated with this entity. If the
5507 system identifier was not specified an empty string is returned.
5508*/
5509QString QDomEntity::systemId() const
5510{
5511 if (!impl)
5512 return QString();
5513 return IMPL->m_sys;
5514}
5515
5516/*!
5517 For unparsed entities this function returns the name of the
5518 notation for the entity. For parsed entities this function returns
5519 an empty string.
5520*/
5521QString QDomEntity::notationName() const
5522{
5523 if (!impl)
5524 return QString();
5525 return IMPL->m_notationName;
5526}
5527
5528#undef IMPL
5529
5530/**************************************************************
5531 *
5532 * QDomEntityReferencePrivate
5533 *
5534 **************************************************************/
5535
5536QDomEntityReferencePrivate::QDomEntityReferencePrivate(QDomDocumentPrivate* d, QDomNodePrivate* parent, const QString& aname)
5537 : QDomNodePrivate(d, parent)
5538{
5539 name = aname;
5540}
5541
5542QDomEntityReferencePrivate::QDomEntityReferencePrivate(QDomNodePrivate* n, bool deep)
5543 : QDomNodePrivate(n, deep)
5544{
5545}
5546
5547QDomNodePrivate* QDomEntityReferencePrivate::cloneNode(bool deep)
5548{
5549 QDomNodePrivate* p = new QDomEntityReferencePrivate(this, deep);
5550 // We are not interested in this node
5551 p->ref.deref();
5552 return p;
5553}
5554
5555void QDomEntityReferencePrivate::save(QTextStream& s, int, int) const
5556{
5557 s << '&' << name << ';';
5558}
5559
5560/**************************************************************
5561 *
5562 * QDomEntityReference
5563 *
5564 **************************************************************/
5565
5566/*!
5567 \class QDomEntityReference
5568 \reentrant
5569 \brief The QDomEntityReference class represents an XML entity reference.
5570
5571 \inmodule QtXml
5572 \ingroup xml-tools
5573
5574 A QDomEntityReference object may be inserted into the DOM tree
5575 when an entity reference is in the source document, or when the
5576 user wishes to insert an entity reference.
5577
5578 Note that character references and references to predefined
5579 entities are expanded by the XML processor so that characters are
5580 represented by their Unicode equivalent rather than by an entity
5581 reference.
5582
5583 Moreover, the XML processor may completely expand references to
5584 entities while building the DOM tree, instead of providing
5585 QDomEntityReference objects.
5586
5587 If it does provide such objects, then for a given entity reference
5588 node, it may be that there is no entity node representing the
5589 referenced entity; but if such an entity exists, then the child
5590 list of the entity reference node is the same as that of the
5591 entity node. As with the entity node, all descendants of the
5592 entity reference are read-only.
5593
5594 For further information about the Document Object Model see
5595 \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and
5596 \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}.
5597 For a more general introduction of the DOM implementation see the
5598 QDomDocument documentation.
5599*/
5600
5601/*!
5602 Constructs an empty entity reference. Use
5603 QDomDocument::createEntityReference() to create a entity reference
5604 with content.
5605*/
5606QDomEntityReference::QDomEntityReference()
5607 : QDomNode()
5608{
5609}
5610
5611/*!
5612 Constructs a copy of \a entityReference.
5613
5614 The data of the copy is shared (shallow copy): modifying one node
5615 will also change the other. If you want to make a deep copy, use
5616 cloneNode().
5617*/
5618QDomEntityReference::QDomEntityReference(const QDomEntityReference &entityReference)
5619 : QDomNode(entityReference)
5620{
5621}
5622
5623QDomEntityReference::QDomEntityReference(QDomEntityReferencePrivate* n)
5624 : QDomNode(n)
5625{
5626}
5627
5628/*!
5629 Assigns \a other to this entity reference.
5630
5631 The data of the copy is shared (shallow copy): modifying one node
5632 will also change the other. If you want to make a deep copy, use
5633 cloneNode().
5634*/
5635QDomEntityReference &QDomEntityReference::operator=(const QDomEntityReference &other) = default;
5636
5637/*!
5638 \fn QDomNode::NodeType QDomEntityReference::nodeType() const
5639
5640 Returns \c EntityReference.
5641*/
5642
5643/**************************************************************
5644 *
5645 * QDomProcessingInstructionPrivate
5646 *
5647 **************************************************************/
5648
5649QDomProcessingInstructionPrivate::QDomProcessingInstructionPrivate(QDomDocumentPrivate* d,
5650 QDomNodePrivate* parent, const QString& target, const QString& data)
5651 : QDomNodePrivate(d, parent)
5652{
5653 name = target;
5654 value = data;
5655}
5656
5657QDomProcessingInstructionPrivate::QDomProcessingInstructionPrivate(QDomProcessingInstructionPrivate* n, bool deep)
5658 : QDomNodePrivate(n, deep)
5659{
5660}
5661
5662
5663QDomNodePrivate* QDomProcessingInstructionPrivate::cloneNode(bool deep)
5664{
5665 QDomNodePrivate* p = new QDomProcessingInstructionPrivate(this, deep);
5666 // We are not interested in this node
5667 p->ref.deref();
5668 return p;
5669}
5670
5671void QDomProcessingInstructionPrivate::save(QTextStream& s, int, int) const
5672{
5673 s << "<?" << name << ' ' << value << "?>" << Qt::endl;
5674}
5675
5676/**************************************************************
5677 *
5678 * QDomProcessingInstruction
5679 *
5680 **************************************************************/
5681
5682/*!
5683 \class QDomProcessingInstruction
5684 \reentrant
5685 \brief The QDomProcessingInstruction class represents an XML processing
5686 instruction.
5687
5688 \inmodule QtXml
5689 \ingroup xml-tools
5690
5691 Processing instructions are used in XML to keep processor-specific
5692 information in the text of the document.
5693
5694 The XML declaration that appears at the top of an XML document,
5695 typically \tt{<?xml version='1.0' encoding='UTF-8'?>}, is treated by QDom as a
5696 processing instruction. This is unfortunate, since the XML declaration is
5697 not a processing instruction; among other differences, it cannot be
5698 inserted into a document anywhere but on the first line.
5699
5700 \note Do not use this function to create an XML declaration. Although the
5701 XML declaration shares the same syntax as a processing instruction, it
5702 is not one. According to the
5703 \l{https://www.w3.org/TR/xml/#sec-prolog-dtd}{XML 1.0 Specification} and the
5704 \l{https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-1590626202}{W3C DOM Structure Model},
5705 the XML declaration is part of the document prolog and not part of the
5706 DOM tree - meaning it should not be represented as a DOM node and cannot be
5707 created or inserted via the DOM API.
5708 If you need to generate a well-formed XML document that includes an XML
5709 declaration, use QXmlStreamWriter, which provides proper support for
5710 writing the declaration through \l {QXmlStreamWriter::}{writeStartDocument}.
5711
5712 The content of the processing instruction is retrieved with data()
5713 and set with setData(). The processing instruction's target is
5714 retrieved with target().
5715
5716 For further information about the Document Object Model see
5717 \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and
5718 \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}.
5719 For a more general introduction of the DOM implementation see the
5720 QDomDocument documentation.
5721*/
5722
5723/*!
5724 Constructs an empty processing instruction. Use
5725 QDomDocument::createProcessingInstruction() to create a processing
5726 instruction with content.
5727*/
5728QDomProcessingInstruction::QDomProcessingInstruction()
5729 : QDomNode()
5730{
5731}
5732
5733/*!
5734 Constructs a copy of \a processingInstruction.
5735
5736 The data of the copy is shared (shallow copy): modifying one node
5737 will also change the other. If you want to make a deep copy, use
5738 cloneNode().
5739*/
5740QDomProcessingInstruction::QDomProcessingInstruction(const QDomProcessingInstruction &processingInstruction)
5741 : QDomNode(processingInstruction)
5742{
5743}
5744
5745QDomProcessingInstruction::QDomProcessingInstruction(QDomProcessingInstructionPrivate* n)
5746 : QDomNode(n)
5747{
5748}
5749
5750/*!
5751 Assigns \a other to this processing instruction.
5752
5753 The data of the copy is shared (shallow copy): modifying one node
5754 will also change the other. If you want to make a deep copy, use
5755 cloneNode().
5756*/
5757QDomProcessingInstruction &
5758QDomProcessingInstruction::operator=(const QDomProcessingInstruction &other) = default;
5759
5760/*!
5761 \fn QDomNode::NodeType QDomProcessingInstruction::nodeType() const
5762
5763 Returns \c ProcessingInstructionNode.
5764*/
5765
5766/*!
5767 Returns the target of this processing instruction.
5768
5769 \sa data()
5770*/
5771QString QDomProcessingInstruction::target() const
5772{
5773 if (!impl)
5774 return QString();
5775 return impl->nodeName();
5776}
5777
5778/*!
5779 Returns the content of this processing instruction.
5780
5781 \sa setData(), target()
5782*/
5783QString QDomProcessingInstruction::data() const
5784{
5785 if (!impl)
5786 return QString();
5787 return impl->nodeValue();
5788}
5789
5790/*!
5791 Sets the data contained in the processing instruction to \a data.
5792
5793 \sa data()
5794*/
5795void QDomProcessingInstruction::setData(const QString &data)
5796{
5797 if (impl)
5798 impl->setNodeValue(data);
5799}
5800
5801/**************************************************************
5802 *
5803 * QDomDocumentPrivate
5804 *
5805 **************************************************************/
5806
5807QDomDocumentPrivate::QDomDocumentPrivate()
5808 : QDomNodePrivate(nullptr),
5809 impl(new QDomImplementationPrivate),
5810 nodeListTime(1)
5811{
5812 type = new QDomDocumentTypePrivate(this, this);
5813 type->ref.deref();
5814
5815 name = u"#document"_s;
5816}
5817
5818QDomDocumentPrivate::QDomDocumentPrivate(const QString& aname)
5819 : QDomNodePrivate(nullptr),
5820 impl(new QDomImplementationPrivate),
5821 nodeListTime(1)
5822{
5823 type = new QDomDocumentTypePrivate(this, this);
5824 type->ref.deref();
5825 type->name = aname;
5826
5827 name = u"#document"_s;
5828}
5829
5830QDomDocumentPrivate::QDomDocumentPrivate(QDomDocumentTypePrivate* dt)
5831 : QDomNodePrivate(nullptr),
5832 impl(new QDomImplementationPrivate),
5833 nodeListTime(1)
5834{
5835 if (dt != nullptr) {
5836 type = dt;
5837 } else {
5838 type = new QDomDocumentTypePrivate(this, this);
5839 type->ref.deref();
5840 }
5841
5842 name = u"#document"_s;
5843}
5844
5845QDomDocumentPrivate::QDomDocumentPrivate(QDomDocumentPrivate* n, bool deep)
5846 : QDomNodePrivate(n, deep),
5847 impl(n->impl->clone()),
5848 nodeListTime(1)
5849{
5850 type = static_cast<QDomDocumentTypePrivate*>(n->type->cloneNode());
5851 type->setParent(this);
5852}
5853
5854QDomDocumentPrivate::~QDomDocumentPrivate()
5855{
5856}
5857
5858void QDomDocumentPrivate::clear()
5859{
5860 impl.reset();
5861 type.reset();
5862 QDomNodePrivate::clear();
5863}
5864
5865QDomDocument::ParseResult QDomDocumentPrivate::setContent(QXmlStreamReader *reader,
5866 QDomDocument::ParseOptions options)
5867{
5868 clear();
5869 impl = new QDomImplementationPrivate;
5870 type = new QDomDocumentTypePrivate(this, this);
5871 type->ref.deref();
5872
5873 if (!reader) {
5874 const auto error = u"Failed to set content, XML reader is not initialized"_s;
5875 qWarning("%s", qPrintable(error));
5876 return { error };
5877 }
5878
5879 QDomParser domParser(this, reader, options);
5880
5881 if (!domParser.parse())
5882 return domParser.result();
5883 return {};
5884}
5885
5886QDomNodePrivate* QDomDocumentPrivate::cloneNode(bool deep)
5887{
5888 QDomNodePrivate *p = new QDomDocumentPrivate(this, deep);
5889 // We are not interested in this node
5890 p->ref.deref();
5891 return p;
5892}
5893
5894QDomElementPrivate* QDomDocumentPrivate::documentElement()
5895{
5896 QDomNodePrivate *p = first;
5897 while (p && !p->isElement())
5898 p = p->next;
5899
5900 return static_cast<QDomElementPrivate *>(p);
5901}
5902
5903QDomElementPrivate* QDomDocumentPrivate::createElement(const QString &tagName)
5904{
5905 bool ok;
5906 QString fixedName = fixedXmlName(tagName, &ok);
5907 if (!ok)
5908 return nullptr;
5909
5910 QDomElementPrivate *e = new QDomElementPrivate(this, nullptr, fixedName);
5911 e->ref.deref();
5912 return e;
5913}
5914
5915QDomElementPrivate* QDomDocumentPrivate::createElementNS(const QString &nsURI, const QString &qName)
5916{
5917 bool ok;
5918 QString fixedName = fixedXmlName(qName, &ok, true);
5919 if (!ok)
5920 return nullptr;
5921
5922 QDomElementPrivate *e = new QDomElementPrivate(this, nullptr, nsURI, fixedName);
5923 e->ref.deref();
5924 return e;
5925}
5926
5927QDomDocumentFragmentPrivate* QDomDocumentPrivate::createDocumentFragment()
5928{
5929 QDomDocumentFragmentPrivate *f = new QDomDocumentFragmentPrivate(this, nullptr);
5930 f->ref.deref();
5931 return f;
5932}
5933
5934QDomTextPrivate* QDomDocumentPrivate::createTextNode(const QString &data)
5935{
5936 bool ok;
5937 QString fixedData = fixedCharData(data, &ok);
5938 if (!ok)
5939 return nullptr;
5940
5941 QDomTextPrivate *t = new QDomTextPrivate(this, nullptr, fixedData);
5942 t->ref.deref();
5943 return t;
5944}
5945
5946QDomCommentPrivate* QDomDocumentPrivate::createComment(const QString &data)
5947{
5948 bool ok;
5949 QString fixedData = fixedComment(data, &ok);
5950 if (!ok)
5951 return nullptr;
5952
5953 QDomCommentPrivate *c = new QDomCommentPrivate(this, nullptr, fixedData);
5954 c->ref.deref();
5955 return c;
5956}
5957
5958QDomCDATASectionPrivate* QDomDocumentPrivate::createCDATASection(const QString &data)
5959{
5960 bool ok;
5961 QString fixedData = fixedCDataSection(data, &ok);
5962 if (!ok)
5963 return nullptr;
5964
5965 QDomCDATASectionPrivate *c = new QDomCDATASectionPrivate(this, nullptr, fixedData);
5966 c->ref.deref();
5967 return c;
5968}
5969
5970QDomProcessingInstructionPrivate* QDomDocumentPrivate::createProcessingInstruction(const QString &target,
5971 const QString &data)
5972{
5973 bool ok;
5974 QString fixedData = fixedPIData(data, &ok);
5975 if (!ok)
5976 return nullptr;
5977 // [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
5978 QString fixedTarget = fixedXmlName(target, &ok);
5979 if (!ok)
5980 return nullptr;
5981
5982 QDomProcessingInstructionPrivate *p = new QDomProcessingInstructionPrivate(this, nullptr, fixedTarget, fixedData);
5983 p->ref.deref();
5984 return p;
5985}
5986QDomAttrPrivate* QDomDocumentPrivate::createAttribute(const QString &aname)
5987{
5988 bool ok;
5989 QString fixedName = fixedXmlName(aname, &ok);
5990 if (!ok)
5991 return nullptr;
5992
5993 QDomAttrPrivate *a = new QDomAttrPrivate(this, nullptr, fixedName);
5994 a->ref.deref();
5995 return a;
5996}
5997
5998QDomAttrPrivate* QDomDocumentPrivate::createAttributeNS(const QString &nsURI, const QString &qName)
5999{
6000 bool ok;
6001 QString fixedName = fixedXmlName(qName, &ok, true);
6002 if (!ok)
6003 return nullptr;
6004
6005 QDomAttrPrivate *a = new QDomAttrPrivate(this, nullptr, nsURI, fixedName);
6006 a->ref.deref();
6007 return a;
6008}
6009
6010QDomEntityReferencePrivate* QDomDocumentPrivate::createEntityReference(const QString &aname)
6011{
6012 bool ok;
6013 QString fixedName = fixedXmlName(aname, &ok);
6014 if (!ok)
6015 return nullptr;
6016
6017 QDomEntityReferencePrivate *e = new QDomEntityReferencePrivate(this, nullptr, fixedName);
6018 e->ref.deref();
6019 return e;
6020}
6021
6022QDomNodePrivate* QDomDocumentPrivate::importNode(QDomNodePrivate *importedNode, bool deep)
6023{
6024 QDomNodePrivate *node = nullptr;
6025 switch (importedNode->nodeType()) {
6026 case QDomNode::AttributeNode:
6027 node = new QDomAttrPrivate(static_cast<QDomAttrPrivate *>(importedNode), true);
6028 break;
6029 case QDomNode::DocumentFragmentNode:
6030 node = new QDomDocumentFragmentPrivate(
6031 static_cast<QDomDocumentFragmentPrivate *>(importedNode), deep);
6032 break;
6033 case QDomNode::ElementNode:
6034 node = new QDomElementPrivate(static_cast<QDomElementPrivate *>(importedNode), deep);
6035 break;
6036 case QDomNode::EntityNode:
6037 node = new QDomEntityPrivate(static_cast<QDomEntityPrivate *>(importedNode), deep);
6038 break;
6039 case QDomNode::EntityReferenceNode:
6040 node = new QDomEntityReferencePrivate(
6041 static_cast<QDomEntityReferencePrivate *>(importedNode), false);
6042 break;
6043 case QDomNode::NotationNode:
6044 node = new QDomNotationPrivate(static_cast<QDomNotationPrivate *>(importedNode), deep);
6045 break;
6046 case QDomNode::ProcessingInstructionNode:
6047 node = new QDomProcessingInstructionPrivate(
6048 static_cast<QDomProcessingInstructionPrivate *>(importedNode), deep);
6049 break;
6050 case QDomNode::TextNode:
6051 node = new QDomTextPrivate(static_cast<QDomTextPrivate *>(importedNode), deep);
6052 break;
6053 case QDomNode::CDATASectionNode:
6054 node = new QDomCDATASectionPrivate(static_cast<QDomCDATASectionPrivate *>(importedNode),
6055 deep);
6056 break;
6057 case QDomNode::CommentNode:
6058 node = new QDomCommentPrivate(static_cast<QDomCommentPrivate *>(importedNode), deep);
6059 break;
6060 default:
6061 break;
6062 }
6063 if (node) {
6064 node->setOwnerDocument(this);
6065 // The QDomNode constructor increases the refcount, so deref first to
6066 // keep refcount balanced.
6067 node->ref.deref();
6068 }
6069 return node;
6070}
6071
6072void QDomDocumentPrivate::saveDocument(QTextStream& s, const int indent, QDomNode::EncodingPolicy encUsed) const
6073{
6074 const QDomNodePrivate* n = first;
6075
6076 if (encUsed == QDomNode::EncodingFromDocument) {
6077#if QT_CONFIG(regularexpression)
6078 const QDomNodePrivate* n = first;
6079
6080 if (n && n->isProcessingInstruction() && n->nodeName() == "xml"_L1) {
6081 // we have an XML declaration
6082 QString data = n->nodeValue();
6083 QRegularExpression encoding(QString::fromLatin1("encoding\\s*=\\s*((\"([^\"]*)\")|('([^']*)'))"));
6084 auto match = encoding.match(data);
6085 QString enc = match.captured(3);
6086 if (enc.isEmpty())
6087 enc = match.captured(5);
6088 if (!enc.isEmpty()) {
6089 auto encoding = QStringConverter::encodingForName(enc.toUtf8().constData());
6090 if (!encoding)
6091 qWarning() << "QDomDocument::save(): Unsupported encoding" << enc << "specified.";
6092 else
6093 s.setEncoding(encoding.value());
6094 }
6095 }
6096#endif
6097 bool doc = false;
6098
6099 while (n) {
6100 if (!doc && !(n->isProcessingInstruction() && n->nodeName() == "xml"_L1)) {
6101 // save doctype after XML declaration
6102 type->save(s, 0, indent);
6103 doc = true;
6104 }
6105 n->saveSubTree(n, s, 0, indent);
6106 n = n->next;
6107 }
6108 }
6109 else {
6110
6111 // Write out the XML declaration.
6112 const QByteArray codecName = QStringConverter::nameForEncoding(s.encoding());
6113
6114 s << "<?xml version=\"1.0\" encoding=\""
6115 << codecName
6116 << "\"?>\n";
6117
6118 // Skip the first processing instruction by name "xml", if any such exists.
6119 const QDomNodePrivate* startNode = n;
6120
6121 // First, we try to find the PI and sets the startNode to the one appearing after it.
6122 while (n) {
6123 if (n->isProcessingInstruction() && n->nodeName() == "xml"_L1) {
6124 startNode = n->next;
6125 break;
6126 }
6127 else
6128 n = n->next;
6129 }
6130
6131 // Now we serialize all the nodes after the faked XML declaration(the PI).
6132 while (startNode) {
6133 startNode->saveSubTree(startNode, s, 0, indent);
6134 startNode = startNode->next;
6135 }
6136 }
6137}
6138
6139/**************************************************************
6140 *
6141 * QDomDocument
6142 *
6143 **************************************************************/
6144
6145#define IMPL static_cast<QDomDocumentPrivate *>(impl)
6146
6147/*!
6148 \class QDomDocument
6149 \reentrant
6150 \brief The QDomDocument class represents an XML document.
6151
6152 \inmodule QtXml
6153
6154 \ingroup xml-tools
6155
6156 The QDomDocument class represents the entire XML document.
6157 Conceptually, it is the root of the document tree, and provides
6158 the primary access to the document's data.
6159
6160 Since elements, text nodes, comments, processing instructions,
6161 etc., cannot exist outside the context of a document, the document
6162 class also contains the factory functions needed to create these
6163 objects. The node objects created have an ownerDocument() function
6164 which associates them with the document within whose context they
6165 were created. The DOM classes that will be used most often are
6166 QDomNode, QDomDocument, QDomElement and QDomText.
6167
6168 The parsed XML is represented internally by a tree of objects that
6169 can be accessed using the various QDom classes. All QDom classes
6170 only \e reference objects in the internal tree. The internal
6171 objects in the DOM tree will get deleted once the last QDom
6172 object referencing them or the QDomDocument itself is deleted.
6173
6174 Creation of elements, text nodes, etc. is done using the various
6175 factory functions provided in this class. Using the default
6176 constructors of the QDom classes will only result in empty
6177 objects that cannot be manipulated or inserted into the Document.
6178
6179 The QDomDocument class has several functions for creating document
6180 data, for example, createElement(), createTextNode(),
6181 createComment(), createCDATASection(),
6182 createProcessingInstruction(), createAttribute() and
6183 createEntityReference(). Some of these functions have versions
6184 that support namespaces, i.e. createElementNS() and
6185 createAttributeNS(). The createDocumentFragment() function is used
6186 to hold parts of the document; this is useful for manipulating for
6187 complex documents.
6188
6189 The entire content of the document is set with setContent(). This
6190 function parses the string it is passed as an XML document and
6191 creates the DOM tree that represents the document. The root
6192 element is available using documentElement(). The textual
6193 representation of the document can be obtained using toString().
6194
6195 \note The DOM tree might end up reserving a lot of memory if the XML
6196 document is big. For such documents, the QXmlStreamReader class
6197 might be a better solution.
6198
6199 It is possible to insert a node from another document into the
6200 document using importNode().
6201
6202 You can obtain a list of all the elements that have a particular
6203 tag with elementsByTagName() or with elementsByTagNameNS().
6204
6205 The QDom classes are typically used as follows:
6206
6207 \snippet code/src_xml_dom_qdom.cpp 16
6208
6209 Once \c doc and \c elem go out of scope, the whole internal tree
6210 representing the XML document is deleted.
6211
6212 To create a document using DOM use code like this:
6213
6214 \snippet code/src_xml_dom_qdom.cpp 17
6215
6216 For further information about the Document Object Model see
6217 the Document Object Model (DOM)
6218 \l{http://www.w3.org/TR/REC-DOM-Level-1/}{Level 1} and
6219 \l{http://www.w3.org/TR/DOM-Level-2-Core/}{Level 2 Core}
6220 Specifications.
6221
6222 \sa {DOM Bookmarks Application}
6223*/
6224
6225/*!
6226 Constructs an empty document.
6227*/
6228QDomDocument::QDomDocument()
6229{
6230 impl = nullptr;
6231}
6232
6233/*!
6234 Creates a document and sets the name of the document type to \a
6235 name.
6236*/
6237QDomDocument::QDomDocument(const QString& name)
6238{
6239 // We take over ownership
6240 impl = new QDomDocumentPrivate(name);
6241}
6242
6243/*!
6244 Creates a document with the document type \a doctype.
6245
6246 \sa QDomImplementation::createDocumentType()
6247*/
6248QDomDocument::QDomDocument(const QDomDocumentType& doctype)
6249{
6250 impl = new QDomDocumentPrivate(static_cast<QDomDocumentTypePrivate *>(doctype.impl));
6251}
6252
6253/*!
6254 Constructs a copy of \a document.
6255
6256 The data of the copy is shared (shallow copy): modifying one node
6257 will also change the other. If you want to make a deep copy, use
6258 cloneNode().
6259*/
6260QDomDocument::QDomDocument(const QDomDocument &document)
6261 : QDomNode(document)
6262{
6263}
6264
6265QDomDocument::QDomDocument(QDomDocumentPrivate *pimpl)
6266 : QDomNode(pimpl)
6267{
6268}
6269
6270/*!
6271 Assigns \a other to this DOM document.
6272
6273 The data of the copy is shared (shallow copy): modifying one node
6274 will also change the other. If you want to make a deep copy, use
6275 cloneNode().
6276*/
6277QDomDocument &QDomDocument::operator=(const QDomDocument &other) = default;
6278
6279/*!
6280 Destroys the object and frees its resources.
6281*/
6282QDomDocument::~QDomDocument()
6283{
6284}
6285
6286#if QT_DEPRECATED_SINCE(6, 8)
6287QT_WARNING_PUSH
6288QT_WARNING_DISABLE_DEPRECATED
6289/*!
6290 \overload
6291 \deprecated [6.8] Use the overloads taking ParseOptions instead.
6292
6293 This function reads the XML document from the string \a text, returning
6294 true if the content was successfully parsed; otherwise returns \c false.
6295 Since \a text is already a Unicode string, no encoding detection
6296 is done.
6297*/
6298bool QDomDocument::setContent(const QString& text, bool namespaceProcessing,
6299 QString *errorMsg, int *errorLine, int *errorColumn)
6300{
6301 QXmlStreamReader reader(text);
6302 reader.setNamespaceProcessing(namespaceProcessing);
6303 return setContent(&reader, namespaceProcessing, errorMsg, errorLine, errorColumn);
6304}
6305
6306/*!
6307 \deprecated [6.8] Use the overload taking ParseOptions instead.
6308 \overload
6309
6310 This function parses the XML document from the byte array \a
6311 data and sets it as the content of the document. It tries to
6312 detect the encoding of the document as required by the XML
6313 specification.
6314
6315 If \a namespaceProcessing is true, the parser recognizes
6316 namespaces in the XML file and sets the prefix name, local name
6317 and namespace URI to appropriate values. If \a namespaceProcessing
6318 is false, the parser does no namespace processing when it reads
6319 the XML file.
6320
6321 If a parse error occurs, this function returns \c false and the error
6322 message is placed in \c{*}\a{errorMsg}, the line number in
6323 \c{*}\a{errorLine} and the column number in \c{*}\a{errorColumn}
6324 (unless the associated pointer is set to \c nullptr); otherwise this
6325 function returns \c true.
6326
6327 If \a namespaceProcessing is true, the function QDomNode::prefix()
6328 returns a string for all elements and attributes. It returns an
6329 empty string if the element or attribute has no prefix.
6330
6331 Text nodes consisting only of whitespace are stripped and won't
6332 appear in the QDomDocument.
6333
6334 If \a namespaceProcessing is false, the functions
6335 QDomNode::prefix(), QDomNode::localName() and
6336 QDomNode::namespaceURI() return an empty string.
6337
6338//! [entity-refs]
6339 Entity references are handled as follows:
6340 \list
6341 \li References to internal general entities and character entities occurring in the
6342 content are included. The result is a QDomText node with the references replaced
6343 by their corresponding entity values. The declaration itself is not retained: it
6344 does not appear in QDomDocumentType::entities(), and toString() does not
6345 reproduce it, although QDomDocumentType::internalSubset() still returns the
6346 internal subset verbatim.
6347 \li References to parameter entities occurring in the internal subset are included.
6348 The result is a QDomDocumentType node which contains entity and notation declarations
6349 with the references replaced by their corresponding entity values.
6350 \li Any general parsed entity reference which is not defined in the internal subset and
6351 which occurs in the content is represented as a QDomEntityReference node.
6352 \li Any parsed entity reference which is not defined in the internal subset and which
6353 occurs outside of the content is replaced with an empty string.
6354 \li Any unparsed entity reference is replaced with an empty string.
6355 \endlist
6356//! [entity-refs]
6357
6358 \sa QDomNode::namespaceURI(), QDomNode::localName(),
6359 QDomNode::prefix(), QString::isNull(), QString::isEmpty()
6360*/
6361bool QDomDocument::setContent(const QByteArray &data, bool namespaceProcessing,
6362 QString *errorMsg, int *errorLine, int *errorColumn)
6363{
6364 QXmlStreamReader reader(data);
6365 reader.setNamespaceProcessing(namespaceProcessing);
6366 return setContent(&reader, namespaceProcessing, errorMsg, errorLine, errorColumn);
6367}
6368
6369static inline QDomDocument::ParseOptions toParseOptions(bool namespaceProcessing)
6370{
6371 return namespaceProcessing ? QDomDocument::ParseOption::UseNamespaceProcessing
6372 : QDomDocument::ParseOption::Default;
6373}
6374
6375static inline void unpackParseResult(const QDomDocument::ParseResult &parseResult,
6376 QString *errorMsg, int *errorLine, int *errorColumn)
6377{
6378 if (!parseResult) {
6379 if (errorMsg)
6380 *errorMsg = parseResult.errorMessage;
6381 if (errorLine)
6382 *errorLine = static_cast<int>(parseResult.errorLine);
6383 if (errorColumn)
6384 *errorColumn = static_cast<int>(parseResult.errorColumn);
6385 }
6386}
6387
6388/*!
6389 \overload
6390 \deprecated [6.8] Use the overload taking ParseOptions instead.
6391
6392 This function reads the XML document from the IO device \a dev, returning
6393 true if the content was successfully parsed; otherwise returns \c false.
6394
6395 \note This method will try to open \a dev in read-only mode if it is not
6396 already open. In that case, the caller is responsible for calling close.
6397 This will change in Qt 7, which will no longer open \a dev. Applications
6398 should therefore open the device themselves before calling setContent.
6399*/
6400bool QDomDocument::setContent(QIODevice* dev, bool namespaceProcessing,
6401 QString *errorMsg, int *errorLine, int *errorColumn)
6402{
6403 ParseResult result = setContent(dev, toParseOptions(namespaceProcessing));
6404 unpackParseResult(result, errorMsg, errorLine, errorColumn);
6405 return bool(result);
6406}
6407
6408/*!
6409 \overload
6410 \deprecated [6.8] Use the overload returning ParseResult instead.
6411
6412 This function reads the XML document from the string \a text, returning
6413 true if the content was successfully parsed; otherwise returns \c false.
6414 Since \a text is already a Unicode string, no encoding detection
6415 is performed.
6416
6417 No namespace processing is performed either.
6418*/
6419bool QDomDocument::setContent(const QString& text, QString *errorMsg, int *errorLine, int *errorColumn)
6420{
6421 return setContent(text, false, errorMsg, errorLine, errorColumn);
6422}
6423
6424/*!
6425 \overload
6426 \deprecated [6.8] Use the overload returning ParseResult instead.
6427
6428 This function reads the XML document from the byte array \a buffer,
6429 returning true if the content was successfully parsed; otherwise returns
6430 false.
6431
6432 No namespace processing is performed.
6433*/
6434bool QDomDocument::setContent(const QByteArray& buffer, QString *errorMsg, int *errorLine, int *errorColumn )
6435{
6436 return setContent(buffer, false, errorMsg, errorLine, errorColumn);
6437}
6438
6439/*!
6440 \overload
6441 \deprecated [6.8] Use the overload returning ParseResult instead.
6442
6443 This function reads the XML document from the IO device \a dev, returning
6444 true if the content was successfully parsed; otherwise returns \c false.
6445
6446 No namespace processing is performed.
6447*/
6448bool QDomDocument::setContent(QIODevice* dev, QString *errorMsg, int *errorLine, int *errorColumn )
6449{
6450 return setContent(dev, false, errorMsg, errorLine, errorColumn);
6451}
6452
6453/*!
6454 \overload
6455 \since 5.15
6456 \deprecated [6.8] Use the overload taking ParseOptions instead.
6457
6458 This function reads the XML document from the QXmlStreamReader \a reader
6459 and parses it. Returns \c true if the content was successfully parsed;
6460 otherwise returns \c false.
6461
6462 If \a namespaceProcessing is \c true, the parser recognizes namespaces in the XML
6463 file and sets the prefix name, local name and namespace URI to appropriate values.
6464 If \a namespaceProcessing is \c false, the parser does no namespace processing when
6465 it reads the XML file.
6466
6467 If a parse error occurs, the error message is placed in \c{*}\a{errorMsg}, the line
6468 number in \c{*}\a{errorLine} and the column number in \c{*}\a{errorColumn} (unless
6469 the associated pointer is set to \c nullptr).
6470
6471 \sa QXmlStreamReader
6472*/
6473bool QDomDocument::setContent(QXmlStreamReader *reader, bool namespaceProcessing,
6474 QString *errorMsg, int *errorLine, int *errorColumn)
6475{
6476 ParseResult result = setContent(reader, toParseOptions(namespaceProcessing));
6477 unpackParseResult(result, errorMsg, errorLine, errorColumn);
6478 return bool(result);
6479}
6480QT_WARNING_POP
6481#endif // QT_DEPRECATED_SINCE(6, 8)
6482
6483/*!
6484 \enum QDomDocument::ParseOption
6485 \since 6.5
6486
6487 This enum describes the possible options that can be used when
6488 parsing an XML document using the setContent() method.
6489
6490 \value Default No parse options are set.
6491 \value UseNamespaceProcessing Namespace processing is enabled.
6492 \value PreserveSpacingOnlyNodes Text nodes containing only spacing
6493 characters are preserved.
6494
6495 \sa setContent()
6496*/
6497
6498/*!
6499 \struct QDomDocument::ParseResult
6500 \since 6.5
6501 \inmodule QtXml
6502 \ingroup xml-tools
6503 \brief The struct is used to store the result of QDomDocument::setContent().
6504
6505 The QDomDocument::ParseResult struct is used for storing the result of
6506 QDomDocument::setContent(). If an error is found while parsing an XML
6507 document, the message, line and column number of an error are stored in
6508 \c ParseResult.
6509
6510 \sa QDomDocument::setContent()
6511*/
6512
6513/*!
6514 \variable QDomDocument::ParseResult::errorMessage
6515
6516 The field contains the text message of an error found by
6517 QDomDocument::setContent() while parsing an XML document.
6518
6519 \sa QDomDocument::setContent()
6520*/
6521
6522/*!
6523 \variable QDomDocument::ParseResult::errorLine
6524
6525 The field contains the line number of an error found by
6526 QDomDocument::setContent() while parsing an XML document.
6527
6528 \sa QDomDocument::setContent()
6529*/
6530
6531/*!
6532 \variable QDomDocument::ParseResult::errorColumn
6533
6534 The field contains the column number of an error found by
6535 QDomDocument::setContent() while parsing an XML document.
6536
6537 \sa QDomDocument::setContent()
6538*/
6539
6540/*!
6541 \fn QDomDocument::ParseResult::operator bool() const
6542
6543 Returns \c false if any error is found by QDomDocument::setContent();
6544 otherwise returns \c true.
6545
6546 \sa QDomDocument::setContent()
6547*/
6548
6549/*!
6550 \fn ParseResult QDomDocument::setContent(const QByteArray &data, ParseOptions options)
6551 \fn ParseResult QDomDocument::setContent(QAnyStringView text, ParseOptions options)
6552 \fn ParseResult QDomDocument::setContent(QIODevice *device, ParseOptions options)
6553 \fn ParseResult QDomDocument::setContent(QXmlStreamReader *reader, ParseOptions options)
6554
6555 \since 6.5
6556
6557 This function parses the XML document from the byte array \a
6558 data, string view \a text, IO \a device, or stream \a reader
6559 and sets it as the content of the document. It tries to
6560 detect the encoding of the document, in accordance with the
6561 XML specification. Returns the result of parsing in ParseResult,
6562 which explicitly converts to \c bool.
6563
6564 You can use the \a options parameter to specify different parsing
6565 options, for example, to enable namespace processing, etc.
6566
6567 By default, namespace processing is disabled. If it's disabled, the
6568 parser does no namespace processing when it reads the XML file. The
6569 functions QDomNode::prefix(), QDomNode::localName() and
6570 QDomNode::namespaceURI() return an empty string.
6571
6572 If namespace processing is enabled via the parse \a options, the parser
6573 recognizes namespaces in the XML file and sets the prefix name, local
6574 name and namespace URI to appropriate values. The functions
6575 QDomNode::prefix(), QDomNode::localName() and QDomNode::namespaceURI()
6576 return a string for all elements and attributes and return an empty
6577 string if the element or attribute has no prefix.
6578
6579 Text nodes consisting only of whitespace are stripped and won't
6580 appear in the QDomDocument. Since Qt 6.5, one can pass
6581 QDomDocument::ParseOption::PreserveSpacingOnlyNodes as a parse
6582 option, to specify that spacing-only text nodes must be preserved.
6583
6584 \include qdom.cpp entity-refs
6585
6586 \note The overload taking IO \a device will try to open it in read-only
6587 mode if it is not already open. In that case, the caller is responsible
6588 for calling close. This will change in Qt 7, which will no longer open
6589 the IO \a device. Applications should therefore open the device themselves
6590 before calling setContent().
6591
6592 \sa ParseResult, ParseOptions
6593*/
6594QDomDocument::ParseResult QDomDocument::setContentImpl(const QByteArray &data, ParseOptions options)
6595{
6596 QXmlStreamReader reader(data);
6597 reader.setNamespaceProcessing(options.testFlag(ParseOption::UseNamespaceProcessing));
6598 return setContent(&reader, options);
6599}
6600
6601QDomDocument::ParseResult QDomDocument::setContent(QAnyStringView data, ParseOptions options)
6602{
6603 QXmlStreamReader reader(data);
6604 reader.setNamespaceProcessing(options.testFlag(ParseOption::UseNamespaceProcessing));
6605 return setContent(&reader, options);
6606}
6607
6608QDomDocument::ParseResult QDomDocument::setContent(QIODevice *device, ParseOptions options)
6609{
6610#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
6611 if (!device->isOpen()) {
6612 qWarning("QDomDocument called with unopened QIODevice. "
6613 "This will not be supported in future Qt versions.");
6614 if (!device->open(QIODevice::ReadOnly)) {
6615 const auto error = u"QDomDocument::setContent: Failed to open device."_s;
6616 qWarning("%s", qPrintable(error));
6617 return { error };
6618 }
6619 }
6620#endif
6621
6622 QXmlStreamReader reader(device);
6623 reader.setNamespaceProcessing(options.testFlag(ParseOption::UseNamespaceProcessing));
6624 return setContent(&reader, options);
6625}
6626
6627QDomDocument::ParseResult QDomDocument::setContent(QXmlStreamReader *reader, ParseOptions options)
6628{
6629 if (!impl)
6630 impl = new QDomDocumentPrivate();
6631 return IMPL->setContent(reader, options);
6632}
6633
6634/*!
6635 Converts the parsed document back to its textual representation.
6636
6637 This function uses \a indent as the amount of space to indent
6638 subelements.
6639
6640 If \a indent is -1, no whitespace at all is added.
6641*/
6642QString QDomDocument::toString(int indent) const
6643{
6644 QString str;
6645 QTextStream s(&str, QIODevice::WriteOnly);
6646 save(s, indent);
6647 return str;
6648}
6649
6650/*!
6651 Converts the parsed document back to its textual representation
6652 and returns a QByteArray containing the data encoded as UTF-8.
6653
6654 This function uses \a indent as the amount of space to indent
6655 subelements.
6656
6657 \sa toString()
6658*/
6659QByteArray QDomDocument::toByteArray(int indent) const
6660{
6661 // ### if there is an encoding specified in the xml declaration, this
6662 // encoding declaration should be changed to utf8
6663 return toString(indent).toUtf8();
6664}
6665
6666
6667/*!
6668 Returns the document type of this document.
6669*/
6670QDomDocumentType QDomDocument::doctype() const
6671{
6672 if (!impl)
6673 return QDomDocumentType();
6674 return QDomDocumentType(IMPL->doctype());
6675}
6676
6677/*!
6678 Returns a QDomImplementation object.
6679*/
6680QDomImplementation QDomDocument::implementation() const
6681{
6682 if (!impl)
6683 return QDomImplementation();
6684 return QDomImplementation(IMPL->implementation());
6685}
6686
6687/*!
6688 Returns the root element of the document.
6689*/
6690QDomElement QDomDocument::documentElement() const
6691{
6692 if (!impl)
6693 return QDomElement();
6694 return QDomElement(IMPL->documentElement());
6695}
6696
6697/*!
6698 Creates a new element called \a tagName that can be inserted into
6699 the DOM tree, e.g. using QDomNode::appendChild().
6700
6701 If \a tagName is not a valid XML name, the behavior of this function is governed
6702 by QDomImplementation::InvalidDataPolicy.
6703
6704 \sa createElementNS(), QDomNode::appendChild(), QDomNode::insertBefore(),
6705 QDomNode::insertAfter()
6706*/
6707QDomElement QDomDocument::createElement(const QString& tagName)
6708{
6709 if (!impl)
6710 impl = new QDomDocumentPrivate();
6711 return QDomElement(IMPL->createElement(tagName));
6712}
6713
6714/*!
6715 Creates a new document fragment, that can be used to hold parts of
6716 the document, e.g. when doing complex manipulations of the
6717 document tree.
6718*/
6719QDomDocumentFragment QDomDocument::createDocumentFragment()
6720{
6721 if (!impl)
6722 impl = new QDomDocumentPrivate();
6723 return QDomDocumentFragment(IMPL->createDocumentFragment());
6724}
6725
6726/*!
6727 Creates a text node for the string \a value that can be inserted
6728 into the document tree, e.g. using QDomNode::appendChild().
6729
6730 If \a value contains characters which cannot be stored as character
6731 data of an XML document (even in the form of character references), the
6732 behavior of this function is governed by QDomImplementation::InvalidDataPolicy.
6733
6734 \sa QDomNode::appendChild(), QDomNode::insertBefore(), QDomNode::insertAfter()
6735*/
6736QDomText QDomDocument::createTextNode(const QString& value)
6737{
6738 if (!impl)
6739 impl = new QDomDocumentPrivate();
6740 return QDomText(IMPL->createTextNode(value));
6741}
6742
6743/*!
6744 Creates a new comment for the string \a value that can be inserted
6745 into the document, e.g. using QDomNode::appendChild().
6746
6747 If \a value contains characters which cannot be stored in an XML comment,
6748 the behavior of this function is governed by QDomImplementation::InvalidDataPolicy.
6749
6750 \sa QDomNode::appendChild(), QDomNode::insertBefore(), QDomNode::insertAfter()
6751*/
6752QDomComment QDomDocument::createComment(const QString& value)
6753{
6754 if (!impl)
6755 impl = new QDomDocumentPrivate();
6756 return QDomComment(IMPL->createComment(value));
6757}
6758
6759/*!
6760 Creates a new CDATA section for the string \a value that can be
6761 inserted into the document, e.g. using QDomNode::appendChild().
6762
6763 If \a value contains characters which cannot be stored in a CDATA section,
6764 the behavior of this function is governed by
6765 QDomImplementation::InvalidDataPolicy.
6766
6767 \sa QDomNode::appendChild(), QDomNode::insertBefore(), QDomNode::insertAfter()
6768*/
6769QDomCDATASection QDomDocument::createCDATASection(const QString& value)
6770{
6771 if (!impl)
6772 impl = new QDomDocumentPrivate();
6773 return QDomCDATASection(IMPL->createCDATASection(value));
6774}
6775
6776/*!
6777 Creates a new processing instruction that can be inserted into the
6778 document, e.g. using QDomNode::appendChild(). This function sets
6779 the target for the processing instruction to \a target and the
6780 data to \a data.
6781
6782 If \a target is not a valid XML name, or data if contains characters which cannot
6783 appear in a processing instruction, the behavior of this function is governed by
6784 QDomImplementation::InvalidDataPolicy.
6785
6786 \sa QDomNode::appendChild(), QDomNode::insertBefore(), QDomNode::insertAfter()
6787*/
6788QDomProcessingInstruction QDomDocument::createProcessingInstruction(const QString& target,
6789 const QString& data)
6790{
6791 if (!impl)
6792 impl = new QDomDocumentPrivate();
6793 return QDomProcessingInstruction(IMPL->createProcessingInstruction(target, data));
6794}
6795
6796
6797/*!
6798 Creates a new attribute called \a name that can be inserted into
6799 an element, e.g. using QDomElement::setAttributeNode().
6800
6801 If \a name is not a valid XML name, the behavior of this function is governed by
6802 QDomImplementation::InvalidDataPolicy.
6803
6804 \sa createAttributeNS()
6805*/
6806QDomAttr QDomDocument::createAttribute(const QString& name)
6807{
6808 if (!impl)
6809 impl = new QDomDocumentPrivate();
6810 return QDomAttr(IMPL->createAttribute(name));
6811}
6812
6813/*!
6814 Creates a new entity reference called \a name that can be inserted
6815 into the document, e.g. using QDomNode::appendChild().
6816
6817 If \a name is not a valid XML name, the behavior of this function is governed by
6818 QDomImplementation::InvalidDataPolicy.
6819
6820 \sa QDomNode::appendChild(), QDomNode::insertBefore(), QDomNode::insertAfter()
6821*/
6822QDomEntityReference QDomDocument::createEntityReference(const QString& name)
6823{
6824 if (!impl)
6825 impl = new QDomDocumentPrivate();
6826 return QDomEntityReference(IMPL->createEntityReference(name));
6827}
6828
6829/*!
6830 Returns a QDomNodeList, that contains all the elements in the
6831 document with the name \a tagname. The order of the node list is
6832 the order they are encountered in a preorder traversal of the
6833 element tree.
6834
6835 \sa elementsByTagNameNS(), QDomElement::elementsByTagName()
6836*/
6837QDomNodeList QDomDocument::elementsByTagName(const QString& tagname) const
6838{
6839 return QDomNodeList(new QDomNodeListPrivate(impl, tagname));
6840}
6841
6842/*!
6843 Imports the node \a importedNode from another document to this
6844 document. \a importedNode remains in the original document; this
6845 function creates a copy that can be used within this document.
6846
6847 This function returns the imported node that belongs to this
6848 document. The returned node has no parent. It is not possible to
6849 import QDomDocument and QDomDocumentType nodes. In those cases
6850 this function returns a \l{QDomNode::isNull()}{null node}.
6851
6852 If \a importedNode is a \l{QDomNode::isNull()}{null node},
6853 a null node is returned.
6854
6855 If \a deep is true, this function imports not only the node \a
6856 importedNode but its whole subtree; if it is false, only the \a
6857 importedNode is imported. The argument \a deep has no effect on
6858 QDomAttr and QDomEntityReference nodes, since the descendants of
6859 QDomAttr nodes are always imported and those of
6860 QDomEntityReference nodes are never imported.
6861
6862 The behavior of this function is slightly different depending on
6863 the node types:
6864 \table
6865 \header \li Node Type \li Behavior
6866 \row \li QDomAttr
6867 \li The owner element is set to 0 and the specified flag is
6868 set to true in the generated attribute. The whole subtree
6869 of \a importedNode is always imported for attribute nodes:
6870 \a deep has no effect.
6871 \row \li QDomDocument
6872 \li Document nodes cannot be imported.
6873 \row \li QDomDocumentFragment
6874 \li If \a deep is true, this function imports the whole
6875 document fragment; otherwise it only generates an empty
6876 document fragment.
6877 \row \li QDomDocumentType
6878 \li Document type nodes cannot be imported.
6879 \row \li QDomElement
6880 \li Attributes for which QDomAttr::specified() is true are
6881 also imported, other attributes are not imported. If \a
6882 deep is true, this function also imports the subtree of \a
6883 importedNode; otherwise it imports only the element node
6884 (and some attributes, see above).
6885 \row \li QDomEntity
6886 \li Entity nodes can be imported, but at the moment there is
6887 no way to use them since the document type is read-only in
6888 DOM level 2.
6889 \row \li QDomEntityReference
6890 \li Descendants of entity reference nodes are never imported:
6891 \a deep has no effect.
6892 \row \li QDomNotation
6893 \li Notation nodes can be imported, but at the moment there is
6894 no way to use them since the document type is read-only in
6895 DOM level 2.
6896 \row \li QDomProcessingInstruction
6897 \li The target and value of the processing instruction is
6898 copied to the new node.
6899 \row \li QDomText
6900 \li The text is copied to the new node.
6901 \row \li QDomCDATASection
6902 \li The text is copied to the new node.
6903 \row \li QDomComment
6904 \li The text is copied to the new node.
6905 \endtable
6906
6907 \sa QDomElement::setAttribute(), QDomNode::insertBefore(),
6908 QDomNode::insertAfter(), QDomNode::replaceChild(), QDomNode::removeChild(),
6909 QDomNode::appendChild()
6910*/
6911QDomNode QDomDocument::importNode(const QDomNode& importedNode, bool deep)
6912{
6913 if (importedNode.isNull())
6914 return QDomNode();
6915 if (!impl)
6916 impl = new QDomDocumentPrivate();
6917 return QDomNode(IMPL->importNode(importedNode.impl, deep));
6918}
6919
6920/*!
6921 Creates a new element with namespace support that can be inserted
6922 into the DOM tree. The name of the element is \a qName and the
6923 namespace URI is \a nsURI. This function also sets
6924 QDomNode::prefix() and QDomNode::localName() to appropriate values
6925 (depending on \a qName).
6926
6927 If \a qName is an empty string, returns a null element regardless of
6928 whether the invalid data policy is set.
6929
6930 \sa createElement()
6931*/
6932QDomElement QDomDocument::createElementNS(const QString& nsURI, const QString& qName)
6933{
6934 if (!impl)
6935 impl = new QDomDocumentPrivate();
6936 return QDomElement(IMPL->createElementNS(nsURI, qName));
6937}
6938
6939/*!
6940 Creates a new attribute with namespace support that can be
6941 inserted into an element. The name of the attribute is \a qName
6942 and the namespace URI is \a nsURI. This function also sets
6943 QDomNode::prefix() and QDomNode::localName() to appropriate values
6944 (depending on \a qName).
6945
6946 If \a qName is not a valid XML name, the behavior of this function is governed by
6947 QDomImplementation::InvalidDataPolicy.
6948
6949 \sa createAttribute()
6950*/
6951QDomAttr QDomDocument::createAttributeNS(const QString& nsURI, const QString& qName)
6952{
6953 if (!impl)
6954 impl = new QDomDocumentPrivate();
6955 return QDomAttr(IMPL->createAttributeNS(nsURI, qName));
6956}
6957
6958/*!
6959 Returns a QDomNodeList that contains all the elements in the
6960 document with the local name \a localName and a namespace URI of
6961 \a nsURI. The order of the node list is the order they are
6962 encountered in a preorder traversal of the element tree.
6963
6964 \sa elementsByTagName(), QDomElement::elementsByTagNameNS()
6965*/
6966QDomNodeList QDomDocument::elementsByTagNameNS(const QString& nsURI, const QString& localName)
6967{
6968 return QDomNodeList(new QDomNodeListPrivate(impl, nsURI, localName));
6969}
6970
6971/*!
6972 Returns the element whose ID is equal to \a elementId. If no
6973 element with the ID was found, this function returns a
6974 \l{QDomNode::isNull()}{null element}.
6975
6976 Since the QDomClasses do not know which attributes are element
6977 IDs, this function returns always a
6978 \l{QDomNode::isNull()}{null element}.
6979 This may change in a future version.
6980*/
6981QDomElement QDomDocument::elementById(const QString& /*elementId*/)
6982{
6983 qWarning("elementById() is not implemented and will always return a null node.");
6984 return QDomElement();
6985}
6986
6987/*!
6988 \fn QDomNode::NodeType QDomDocument::nodeType() const
6989
6990 Returns \c DocumentNode.
6991*/
6992
6993#undef IMPL
6994
6995/**************************************************************
6996 *
6997 * Node casting functions
6998 *
6999 **************************************************************/
7000
7001/*!
7002 Converts a QDomNode into a QDomAttr. If the node is not an
7003 attribute, the returned object will be \l{QDomNode::isNull()}{null}.
7004
7005 \sa isAttr()
7006*/
7007QDomAttr QDomNode::toAttr() const
7008{
7009 if (impl && impl->isAttr())
7010 return QDomAttr(static_cast<QDomAttrPrivate *>(impl));
7011 return QDomAttr();
7012}
7013
7014/*!
7015 Converts a QDomNode into a QDomCDATASection. If the node is not a
7016 CDATA section, the returned object will be \l{QDomNode::isNull()}{null}.
7017
7018 \sa isCDATASection()
7019*/
7020QDomCDATASection QDomNode::toCDATASection() const
7021{
7022 if (impl && impl->isCDATASection())
7023 return QDomCDATASection(static_cast<QDomCDATASectionPrivate *>(impl));
7024 return QDomCDATASection();
7025}
7026
7027/*!
7028 Converts a QDomNode into a QDomDocumentFragment. If the node is
7029 not a document fragment the returned object will be \l{QDomNode::isNull()}{null}.
7030
7031 \sa isDocumentFragment()
7032*/
7033QDomDocumentFragment QDomNode::toDocumentFragment() const
7034{
7035 if (impl && impl->isDocumentFragment())
7036 return QDomDocumentFragment(static_cast<QDomDocumentFragmentPrivate *>(impl));
7037 return QDomDocumentFragment();
7038}
7039
7040/*!
7041 Converts a QDomNode into a QDomDocument. If the node is not a
7042 document the returned object will be \l{QDomNode::isNull()}{null}.
7043
7044 \sa isDocument()
7045*/
7046QDomDocument QDomNode::toDocument() const
7047{
7048 if (impl && impl->isDocument())
7049 return QDomDocument(static_cast<QDomDocumentPrivate *>(impl));
7050 return QDomDocument();
7051}
7052
7053/*!
7054 Converts a QDomNode into a QDomDocumentType. If the node is not a
7055 document type the returned object will be \l{QDomNode::isNull()}{null}.
7056
7057 \sa isDocumentType()
7058*/
7059QDomDocumentType QDomNode::toDocumentType() const
7060{
7061 if (impl && impl->isDocumentType())
7062 return QDomDocumentType(static_cast<QDomDocumentTypePrivate *>(impl));
7063 return QDomDocumentType();
7064}
7065
7066/*!
7067 Converts a QDomNode into a QDomElement. If the node is not an
7068 element the returned object will be \l{QDomNode::isNull()}{null}.
7069
7070 \sa isElement()
7071*/
7072QDomElement QDomNode::toElement() const
7073{
7074 if (impl && impl->isElement())
7075 return QDomElement(static_cast<QDomElementPrivate *>(impl));
7076 return QDomElement();
7077}
7078
7079/*!
7080 Converts a QDomNode into a QDomEntityReference. If the node is not
7081 an entity reference, the returned object will be \l{QDomNode::isNull()}{null}.
7082
7083 \sa isEntityReference()
7084*/
7085QDomEntityReference QDomNode::toEntityReference() const
7086{
7087 if (impl && impl->isEntityReference())
7088 return QDomEntityReference(static_cast<QDomEntityReferencePrivate *>(impl));
7089 return QDomEntityReference();
7090}
7091
7092/*!
7093 Converts a QDomNode into a QDomText. If the node is not a text,
7094 the returned object will be \l{QDomNode::isNull()}{null}.
7095
7096 \sa isText()
7097*/
7098QDomText QDomNode::toText() const
7099{
7100 if (impl && impl->isText())
7101 return QDomText(static_cast<QDomTextPrivate *>(impl));
7102 return QDomText();
7103}
7104
7105/*!
7106 Converts a QDomNode into a QDomEntity. If the node is not an
7107 entity the returned object will be \l{QDomNode::isNull()}{null}.
7108
7109 \sa isEntity()
7110*/
7111QDomEntity QDomNode::toEntity() const
7112{
7113 if (impl && impl->isEntity())
7114 return QDomEntity(static_cast<QDomEntityPrivate *>(impl));
7115 return QDomEntity();
7116}
7117
7118/*!
7119 Converts a QDomNode into a QDomNotation. If the node is not a
7120 notation the returned object will be \l{QDomNode::isNull()}{null}.
7121
7122 \sa isNotation()
7123*/
7124QDomNotation QDomNode::toNotation() const
7125{
7126 if (impl && impl->isNotation())
7127 return QDomNotation(static_cast<QDomNotationPrivate *>(impl));
7128 return QDomNotation();
7129}
7130
7131/*!
7132 Converts a QDomNode into a QDomProcessingInstruction. If the node
7133 is not a processing instruction the returned object will be \l{QDomNode::isNull()}{null}.
7134
7135 \sa isProcessingInstruction()
7136*/
7137QDomProcessingInstruction QDomNode::toProcessingInstruction() const
7138{
7139 if (impl && impl->isProcessingInstruction())
7140 return QDomProcessingInstruction(static_cast<QDomProcessingInstructionPrivate *>(impl));
7141 return QDomProcessingInstruction();
7142}
7143
7144/*!
7145 Converts a QDomNode into a QDomCharacterData. If the node is not a
7146 character data node the returned object will be \l{QDomNode::isNull()}{null}.
7147
7148 \sa isCharacterData()
7149*/
7150QDomCharacterData QDomNode::toCharacterData() const
7151{
7152 if (impl && impl->isCharacterData())
7153 return QDomCharacterData(static_cast<QDomCharacterDataPrivate *>(impl));
7154 return QDomCharacterData();
7155}
7156
7157/*!
7158 Converts a QDomNode into a QDomComment. If the node is not a
7159 comment the returned object will be \l{QDomNode::isNull()}{null}.
7160
7161 \sa isComment()
7162*/
7163QDomComment QDomNode::toComment() const
7164{
7165 if (impl && impl->isComment())
7166 return QDomComment(static_cast<QDomCommentPrivate *>(impl));
7167 return QDomComment();
7168}
7169
7170/*!
7171 \variable QDomNode::impl
7172 \internal
7173 Pointer to private data structure.
7174*/
7175
7176QT_END_NAMESPACE
7177
7178#endif // feature dom