Coverage Report

Created: 2026-08-11 07:29

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