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