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

source code of qtbase/src/xml/dom/qdom.cpp