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