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