358603d79433185518c8314e18bda50c56ae1024
[profile/ivi/qtxmlpatterns.git] / src / xmlpatterns / acceltree / qacceltree.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QStack>
43
44 #include "qabstractxmlreceiver.h"
45 #include "qabstractxmlnodemodel_p.h"
46 #include "qacceliterators_p.h"
47 #include "qacceltree_p.h"
48 #include "qatomicstring_p.h"
49 #include "qcommonvalues_p.h"
50 #include "qcompressedwhitespace_p.h"
51 #include "qdebug_p.h"
52 #include "quntypedatomic_p.h"
53 #include "qxpathhelper_p.h"
54
55 QT_BEGIN_NAMESPACE
56
57 using namespace QPatternist;
58
59 namespace QPatternist {
60
61     class AccelTreePrivate : public QAbstractXmlNodeModelPrivate
62     {
63         public:
64             AccelTreePrivate(AccelTree *accelTree)
65                 : m_accelTree(accelTree)
66             {
67             }
68
69             virtual QSourceLocation sourceLocation(const QXmlNodeModelIndex &index) const
70             {
71                 return m_accelTree->sourceLocation(index);
72             }
73
74         private:
75             AccelTree *m_accelTree;
76     };
77 }
78
79 AccelTree::AccelTree(const QUrl &docURI, const QUrl &bURI)
80      : QAbstractXmlNodeModel(new AccelTreePrivate(this))
81      , m_documentURI(docURI)
82      , m_baseURI(bURI)
83 {
84     /* Pre-allocate at least a little bit. */
85     // TODO. Do it according to what an average 4 KB doc contains.
86     basicData.reserve(100);
87     data.reserve(30);
88 }
89
90 void AccelTree::printStats(const NamePool::Ptr &np) const
91 {
92     Q_ASSERT(np);
93 #ifdef QT_NO_DEBUG
94     Q_UNUSED(np); /* Needed when compiling in release mode. */
95 #else
96     const int len = basicData.count();
97
98     pDebug() << "AccelTree stats for" << (m_documentURI.isEmpty() ? QString::fromLatin1("<empty URI>") : m_documentURI.toString());
99     pDebug() << "Maximum pre number:" << maximumPreNumber();
100     pDebug() << "+---------------+-------+-------+---------------+-------+--------------+-------+";
101     pDebug() << "| Pre number    | Depth | Size  | Post Number   | Kind  | Name         | Value |";
102     pDebug() << "+---------------+-------+-------+---------------+-------+--------------+-------+";
103     for(int i = 0; i < len; ++i)
104     {
105         const BasicNodeData &v = basicData.at(i);
106         pDebug() << '|' << i
107                  << "\t\t|" << v.depth()
108                  << "\t|" << v.size()
109                  << "\t|" << postNumber(i)
110                  << "\t|" << v.kind()
111                  << "\t\t|" << (v.name().isNull() ? QString::fromLatin1("(none)") : np->displayName(v.name()))
112                  << "\t\t|" << ((v.kind() == QXmlNodeModelIndex::Text && isCompressed(i)) ? CompressedWhitespace::decompress(data.value(i))
113                                                                                           : data.value(i))
114                  << "\t|";
115         /*
116         pDebug() << '|' << QString().arg(i, 14)
117                  << '|' << QString().arg(v.depth(), 6)
118                  << '|' << QString().arg(v.size(), 6)
119                  << '|' << QString().arg(postNumber(i), 14)
120                  << '|' << QString().arg(v.kind(), 6)
121                  << '|';
122                  */
123     }
124     pDebug() << "+---------------+-------+-------+---------------+-------+--------------+";
125     pDebug() << "Namespaces(" << namespaces.count() << "):";
126
127     QHashIterator<PreNumber, QVector<QXmlName> > it(namespaces);
128     while(it.hasNext())
129     {
130         it.next();
131
132         pDebug() << "PreNumber: " << QString::number(it.key());
133         for(int i = 0; i < it.value().count(); ++i)
134             pDebug() << "\t\t" << np->stringForPrefix(it.value().at(i).prefix()) << " = " << np->stringForNamespace(it.value().at(i).namespaceURI());
135     }
136
137 #endif
138 }
139
140 QUrl AccelTree::baseUri(const QXmlNodeModelIndex &ni) const
141 {
142     switch(kind(toPreNumber(ni)))
143     {
144         case QXmlNodeModelIndex::Document:
145             return baseUri();
146         case QXmlNodeModelIndex::Element:
147         {
148             const QXmlNodeModelIndex::Iterator::Ptr it(iterate(ni, QXmlNodeModelIndex::AxisAttribute));
149             QXmlNodeModelIndex next(it->next());
150
151             while(!next.isNull())
152             {
153                 if(next.name() == QXmlName(StandardNamespaces::xml, StandardLocalNames::base))
154                 {
155                     const QUrl candidate(next.stringValue());
156                     //  TODO. The xml:base spec says to do URI escaping here.
157
158                     if(!candidate.isValid())
159                         return QUrl();
160                     else if(candidate.isRelative())
161                     {
162                         const QXmlNodeModelIndex par(parent(ni));
163
164                         if(par.isNull())
165                             return baseUri().resolved(candidate);
166                         else
167                             return par.baseUri().resolved(candidate);
168                     }
169                     else
170                         return candidate;
171                 }
172
173                 next = it->next();
174             }
175
176             /* We have no xml:base-attribute. Can any parent supply us a base URI? */
177             const QXmlNodeModelIndex par(parent(ni));
178
179             if(par.isNull())
180                 return baseUri();
181             else
182                 return par.baseUri();
183         }
184         case QXmlNodeModelIndex::ProcessingInstruction:
185         /* Fallthrough. */
186         case QXmlNodeModelIndex::Comment:
187         /* Fallthrough. */
188         case QXmlNodeModelIndex::Attribute:
189         /* Fallthrough. */
190         case QXmlNodeModelIndex::Text:
191         {
192             const QXmlNodeModelIndex par(ni.iterate(QXmlNodeModelIndex::AxisParent)->next());
193             if(par.isNull())
194                 return QUrl();
195             else
196                 return par.baseUri();
197         }
198         case QXmlNodeModelIndex::Namespace:
199             return QUrl();
200     }
201
202     Q_ASSERT_X(false, Q_FUNC_INFO, "This line is never supposed to be reached.");
203     return QUrl();
204 }
205
206 QUrl AccelTree::documentUri(const QXmlNodeModelIndex &ni) const
207 {
208     if(kind(toPreNumber(ni)) == QXmlNodeModelIndex::Document)
209         return documentUri();
210     else
211         return QUrl();
212 }
213
214 QXmlNodeModelIndex::NodeKind AccelTree::kind(const QXmlNodeModelIndex &ni) const
215 {
216     return kind(toPreNumber(ni));
217 }
218
219 QXmlNodeModelIndex::DocumentOrder AccelTree::compareOrder(const QXmlNodeModelIndex &ni1,
220                                                           const QXmlNodeModelIndex &ni2) const
221 {
222     Q_ASSERT_X(ni1.model() == ni2.model(), Q_FUNC_INFO,
223                "The API docs guarantees the two nodes are from the same model");
224
225     const PreNumber p1 = ni1.data();
226     const PreNumber p2 = ni2.data();
227
228     if(p1 == p2)
229         return QXmlNodeModelIndex::Is;
230     else if(p1 < p2)
231         return QXmlNodeModelIndex::Precedes;
232     else
233         return QXmlNodeModelIndex::Follows;
234 }
235
236 QXmlNodeModelIndex AccelTree::root(const QXmlNodeModelIndex &) const
237 {
238     return createIndex(qint64(0));
239 }
240
241 QXmlNodeModelIndex AccelTree::parent(const QXmlNodeModelIndex &ni) const
242 {
243     const AccelTree::PreNumber p = basicData.at(toPreNumber(ni)).parent();
244
245     if(p == -1)
246         return QXmlNodeModelIndex();
247     else
248         return createIndex(p);
249 }
250
251 QXmlNodeModelIndex::Iterator::Ptr AccelTree::iterate(const QXmlNodeModelIndex &ni,
252                                                      QXmlNodeModelIndex::Axis axis) const
253 {
254     const PreNumber preNumber = toPreNumber(ni);
255
256     switch(axis)
257     {
258         case QXmlNodeModelIndex::AxisChildOrTop:
259         {
260             if(!hasParent(preNumber))
261             {
262                 switch(kind(preNumber))
263                 {
264                     case QXmlNodeModelIndex::Comment:
265                     /* Fallthrough. */
266                     case QXmlNodeModelIndex::ProcessingInstruction:
267                     /* Fallthrough. */
268                     case QXmlNodeModelIndex::Element:
269                     /* Fallthrough. */
270                     case QXmlNodeModelIndex::Text:
271                         return makeSingletonIterator(ni);
272                     case QXmlNodeModelIndex::Attribute:
273                     /* Fallthrough. */
274                     case QXmlNodeModelIndex::Document:
275                     /* Fallthrough. */
276                     case QXmlNodeModelIndex::Namespace:
277                         /* Do nothing. */;
278                 }
279             }
280             /* Else, fallthrough to AxisChild. */
281         }
282         case QXmlNodeModelIndex::AxisChild:
283         {
284             if(hasChildren(preNumber))
285                 return QXmlNodeModelIndex::Iterator::Ptr(new ChildIterator(this, preNumber));
286             else
287                 return makeEmptyIterator<QXmlNodeModelIndex>();
288         }
289         case QXmlNodeModelIndex::AxisAncestor:
290         {
291             if(hasParent(preNumber))
292                 return QXmlNodeModelIndex::Iterator::Ptr(new AncestorIterator<false>(this, preNumber));
293             else
294                 return makeEmptyIterator<QXmlNodeModelIndex>();
295         }
296         case QXmlNodeModelIndex::AxisAncestorOrSelf:
297             return QXmlNodeModelIndex::Iterator::Ptr(new AncestorIterator<true>(this, preNumber));
298         case QXmlNodeModelIndex::AxisParent:
299         {
300             if(hasParent(preNumber))
301                 return makeSingletonIterator(createIndex(parent(preNumber)));
302             else
303                 return makeEmptyIterator<QXmlNodeModelIndex>();
304         }
305         case QXmlNodeModelIndex::AxisDescendant:
306         {
307             if(hasChildren(preNumber))
308                 return QXmlNodeModelIndex::Iterator::Ptr(new DescendantIterator<false>(this, preNumber));
309             else
310                 return makeEmptyIterator<QXmlNodeModelIndex>();
311         }
312         case QXmlNodeModelIndex::AxisDescendantOrSelf:
313             return QXmlNodeModelIndex::Iterator::Ptr(new DescendantIterator<true>(this, preNumber));
314         case QXmlNodeModelIndex::AxisFollowing:
315         {
316             if(preNumber == maximumPreNumber())
317                 return makeEmptyIterator<QXmlNodeModelIndex>();
318             else
319                 return QXmlNodeModelIndex::Iterator::Ptr(new FollowingIterator(this, preNumber));
320         }
321         case QXmlNodeModelIndex::AxisAttributeOrTop:
322         {
323             if(!hasParent(preNumber) && kind(preNumber) == QXmlNodeModelIndex::Attribute)
324                 return makeSingletonIterator(ni);
325             /* Else, falthrough to AxisAttribute. */
326         }
327         case QXmlNodeModelIndex::AxisAttribute:
328         {
329             if(hasChildren(preNumber) && kind(preNumber + 1) == QXmlNodeModelIndex::Attribute)
330                 return QXmlNodeModelIndex::Iterator::Ptr(new AttributeIterator(this, preNumber));
331             else
332                 return makeEmptyIterator<QXmlNodeModelIndex>();
333         }
334         case QXmlNodeModelIndex::AxisPreceding:
335         {
336             if(preNumber == 0)
337                 return makeEmptyIterator<QXmlNodeModelIndex>();
338             else
339                 return QXmlNodeModelIndex::Iterator::Ptr(new PrecedingIterator(this, preNumber));
340         }
341         case QXmlNodeModelIndex::AxisSelf:
342             return makeSingletonIterator(createIndex(toPreNumber(ni)));
343         case QXmlNodeModelIndex::AxisFollowingSibling:
344         {
345             if(preNumber == maximumPreNumber())
346                 return makeEmptyIterator<QXmlNodeModelIndex>();
347             else
348                 return QXmlNodeModelIndex::Iterator::Ptr(new SiblingIterator<true>(this, preNumber));
349         }
350         case QXmlNodeModelIndex::AxisPrecedingSibling:
351         {
352             if(preNumber == 0)
353                 return makeEmptyIterator<QXmlNodeModelIndex>();
354             else
355                 return QXmlNodeModelIndex::Iterator::Ptr(new SiblingIterator<false>(this, preNumber));
356         }
357         case QXmlNodeModelIndex::AxisNamespace:
358             return makeEmptyIterator<QXmlNodeModelIndex>();
359     }
360
361     Q_ASSERT(false);
362     return QXmlNodeModelIndex::Iterator::Ptr();
363 }
364
365 QXmlNodeModelIndex AccelTree::nextFromSimpleAxis(QAbstractXmlNodeModel::SimpleAxis,
366                                                  const QXmlNodeModelIndex&) const
367 {
368     Q_ASSERT_X(false, Q_FUNC_INFO, "This function is not supposed to be called.");
369     return QXmlNodeModelIndex();
370 }
371
372 QVector<QXmlNodeModelIndex> AccelTree::attributes(const QXmlNodeModelIndex &element) const
373 {
374     Q_ASSERT_X(false, Q_FUNC_INFO, "This function is not supposed to be called.");
375     Q_UNUSED(element);
376     return QVector<QXmlNodeModelIndex>();
377 }
378
379 QXmlName AccelTree::name(const QXmlNodeModelIndex &ni) const
380 {
381     /* If this node type does not have a name(for instance, it's a comment)
382      * we will return the default constructed value, which is conformant with
383      * this function's contract. */
384     return name(toPreNumber(ni));
385 }
386
387 QVector<QXmlName> AccelTree::namespaceBindings(const QXmlNodeModelIndex &ni) const
388 {
389     /* We get a hold of the ancestor, and loop them in reverse document
390      * order(first the parent, then the parent's parent, etc). As soon
391      * we find a binding that hasn't already been added, we add it to the
392      * result list. In that way, declarations appearing further down override
393      * those further up. */
394
395     const PreNumber preNumber = toPreNumber(ni);
396
397     const QXmlNodeModelIndex::Iterator::Ptr it(new AncestorIterator<true>(this, preNumber));
398     QVector<QXmlName> result;
399     QXmlNodeModelIndex n(it->next());
400
401     /* Whether xmlns="" has been encountered. */
402     bool hasUndeclaration = false;
403
404     while(!n.isNull())
405     {
406         const QVector<QXmlName> &forNode = namespaces.value(toPreNumber(n));
407         const int len = forNode.size();
408         bool stopInheritance = false;
409
410         for(int i = 0; i < len; ++i)
411         {
412             const QXmlName &nsb = forNode.at(i);
413
414             if(nsb.namespaceURI() == StandardNamespaces::StopNamespaceInheritance)
415             {
416                 stopInheritance = true;
417                 continue;
418             }
419
420             if(nsb.prefix() == StandardPrefixes::empty &&
421                nsb.namespaceURI() == StandardNamespaces::empty)
422             {
423                 hasUndeclaration = true;
424                 continue;
425             }
426
427             if(!hasPrefix(result, nsb.prefix()))
428             {
429                 /* We've already encountered an undeclaration, so we're supposed to skip
430                  * them. */
431                 if(hasUndeclaration && nsb.prefix() == StandardPrefixes::empty)
432                     continue;
433                 else
434                     result.append(nsb);
435             }
436         }
437
438         if(stopInheritance)
439             break;
440         else
441             n = it->next();
442     }
443
444     result.append(QXmlName(StandardNamespaces::xml, StandardLocalNames::empty, StandardPrefixes::xml));
445
446     return result;
447 }
448
449 void AccelTree::sendNamespaces(const QXmlNodeModelIndex &n,
450                                QAbstractXmlReceiver *const receiver) const
451 {
452     Q_ASSERT(n.kind() == QXmlNodeModelIndex::Element);
453
454     const QXmlNodeModelIndex::Iterator::Ptr it(iterate(n, QXmlNodeModelIndex::AxisAncestorOrSelf));
455     QXmlNodeModelIndex next(it->next());
456     QVector<QXmlName::PrefixCode> alreadySent;
457
458     while(!next.isNull())
459     {
460         const PreNumber preNumber = toPreNumber(next);
461
462         const QVector<QXmlName> &nss = namespaces.value(preNumber);
463
464         /* This is by far the most common case. */
465         if(nss.isEmpty())
466         {
467             next = it->next();
468             continue;
469         }
470
471         const int len = nss.count();
472         bool stopInheritance = false;
473
474         for(int i = 0; i < len; ++i)
475         {
476             const QXmlName &name = nss.at(i);
477
478             if(name.namespaceURI() == StandardNamespaces::StopNamespaceInheritance)
479             {
480                 stopInheritance = true;
481                 continue;
482             }
483
484             if(!alreadySent.contains(name.prefix()))
485             {
486                 alreadySent.append(name.prefix());
487                 receiver->namespaceBinding(name);
488             }
489         }
490
491         if(stopInheritance)
492             break;
493         else
494             next = it->next();
495     }
496 }
497
498 QString AccelTree::stringValue(const QXmlNodeModelIndex &ni) const
499 {
500     const PreNumber preNumber = toPreNumber(ni);
501
502     switch(kind(preNumber))
503     {
504         case QXmlNodeModelIndex::Element:
505         {
506             /* Concatenate all text nodes that are descendants of this node. */
507             if(!hasChildren(preNumber))
508                 return QString();
509
510             const AccelTree::PreNumber stop = preNumber + size(preNumber);
511             AccelTree::PreNumber pn = preNumber + 1; /* Jump over ourselves. */
512             QString result;
513
514             for(; pn <= stop; ++pn)
515             {
516                 if(kind(pn) == QXmlNodeModelIndex::Text)
517                 {
518                     if(isCompressed(pn))
519                         result += CompressedWhitespace::decompress(data.value(pn));
520                     else
521                         result += data.value(pn);
522                 }
523             }
524
525             return result;
526         }
527         case QXmlNodeModelIndex::Text:
528         {
529             if(isCompressed(preNumber))
530                 return CompressedWhitespace::decompress(data.value(preNumber));
531             /* Else, fallthrough. It's not compressed so use it as it is. */
532         }
533         case QXmlNodeModelIndex::Attribute:
534         /* Fallthrough */
535         case QXmlNodeModelIndex::ProcessingInstruction:
536         /* Fallthrough */
537         case QXmlNodeModelIndex::Comment:
538             return data.value(preNumber);
539         case QXmlNodeModelIndex::Document:
540         {
541             /* Concatenate all text nodes in the whole document. */
542
543             QString result;
544             // Perhaps we can QString::reserve() the result based on the size?
545             const AccelTree::PreNumber max = maximumPreNumber();
546
547             for(AccelTree::PreNumber i = 0; i <= max; ++i)
548             {
549                 if(kind(i) == QXmlNodeModelIndex::Text)
550                 {
551                     if(isCompressed(i))
552                         result += CompressedWhitespace::decompress(data.value(i));
553                     else
554                         result += data.value(i);
555                 }
556             }
557
558             return result;
559         }
560         default:
561         {
562             Q_ASSERT_X(false, Q_FUNC_INFO,
563                        "A node type that doesn't exist in the XPath Data Model was encountered.");
564             return QString(); /* Dummy, silence compiler warning. */
565         }
566     }
567 }
568
569 QVariant AccelTree::typedValue(const QXmlNodeModelIndex &n) const
570 {
571     return stringValue(n);
572 }
573
574 bool AccelTree::hasPrefix(const QVector<QXmlName> &nbs, const QXmlName::PrefixCode prefix)
575 {
576     const int size = nbs.size();
577
578     for(int i = 0; i < size; ++i)
579     {
580         if(nbs.at(i).prefix() == prefix)
581             return true;
582     }
583
584     return false;
585 }
586
587 ItemType::Ptr AccelTree::type(const QXmlNodeModelIndex &ni) const
588 {
589     /* kind() is manually inlined here to avoid a virtual call. */
590     return XPathHelper::typeFromKind(basicData.at(toPreNumber(ni)).kind());
591 }
592
593 Item::Iterator::Ptr AccelTree::sequencedTypedValue(const QXmlNodeModelIndex &n) const
594 {
595     const PreNumber preNumber = toPreNumber(n);
596
597     switch(kind(preNumber))
598     {
599         case QXmlNodeModelIndex::Element:
600         /* Fallthrough. */
601         case QXmlNodeModelIndex::Document:
602         /* Fallthrough. */
603         case QXmlNodeModelIndex::Attribute:
604             return makeSingletonIterator(Item(UntypedAtomic::fromValue(stringValue(n))));
605
606         case QXmlNodeModelIndex::Text:
607         /* Fallthrough. */
608         case QXmlNodeModelIndex::ProcessingInstruction:
609         /* Fallthrough. */
610         case QXmlNodeModelIndex::Comment:
611             return makeSingletonIterator(Item(AtomicString::fromValue(stringValue(n))));
612         default:
613         {
614             Q_ASSERT_X(false, Q_FUNC_INFO,
615                        qPrintable(QString::fromLatin1("A node type that doesn't exist "
616                                                       "in the XPath Data Model was encountered.").arg(kind(preNumber))));
617             return Item::Iterator::Ptr(); /* Dummy, silence compiler warning. */
618         }
619     }
620 }
621
622 void AccelTree::copyNodeTo(const QXmlNodeModelIndex &node,
623                            QAbstractXmlReceiver *const receiver,
624                            const NodeCopySettings &settings) const
625 {
626     /* This code piece can be seen as a customized version of
627      * QAbstractXmlReceiver::item/sendAsNode(). */
628     Q_ASSERT(receiver);
629     Q_ASSERT(!node.isNull());
630
631     typedef QHash<QXmlName::PrefixCode, QXmlName::NamespaceCode> Binding;
632     QStack<Binding> outputted;
633
634     switch(node.kind())
635     {
636         case QXmlNodeModelIndex::Element:
637         {
638             outputted.push(Binding());
639
640             /* Add the namespace for our element name. */
641             const QXmlName elementName(node.name());
642
643             receiver->startElement(elementName);
644
645             if(!settings.testFlag(InheritNamespaces))
646                 receiver->namespaceBinding(QXmlName(StandardNamespaces::StopNamespaceInheritance, 0,
647                                                     StandardPrefixes::StopNamespaceInheritance));
648
649             if(settings.testFlag(PreserveNamespaces))
650                 node.sendNamespaces(receiver);
651             else
652             {
653                 /* Find the namespaces that we actually use and add them to outputted. These are drawn
654                  * from the element name, and the node's attributes. */
655                 outputted.top().insert(elementName.prefix(), elementName.namespaceURI());
656
657                 const QXmlNodeModelIndex::Iterator::Ptr attributes(iterate(node, QXmlNodeModelIndex::AxisAttribute));
658                 QXmlNodeModelIndex attr(attributes->next());
659
660                 while(!attr.isNull())
661                 {
662                     const QXmlName &attrName = attr.name();
663                     outputted.top().insert(attrName.prefix(), attrName.namespaceURI());
664                     attr = attributes->next();
665                 }
666
667                 Binding::const_iterator it(outputted.top().constBegin());
668                 const Binding::const_iterator end(outputted.top().constEnd());
669
670                 for(; it != end; ++it)
671                     receiver->namespaceBinding(QXmlName(it.value(), 0, it.key()));
672             }
673
674             /* Send the attributes of the element. */
675             {
676                 QXmlNodeModelIndex::Iterator::Ptr attributes(node.iterate(QXmlNodeModelIndex::AxisAttribute));
677                 QXmlNodeModelIndex attribute(attributes->next());
678
679                 while(!attribute.isNull())
680                 {
681                     const QString &v = attribute.stringValue();
682                     receiver->attribute(attribute.name(), QStringRef(&v));
683                     attribute = attributes->next();
684                 }
685             }
686
687             /* Send the children of the element. */
688             copyChildren(node, receiver, settings);
689
690             receiver->endElement();
691             outputted.pop();
692             break;
693         }
694         case QXmlNodeModelIndex::Document:
695         {
696             /* We need to intercept and grab the elements of the document node, such
697              * that we preserve/inherit preference applies to them. */
698             receiver->startDocument();
699             copyChildren(node, receiver, settings);
700             receiver->endDocument();
701             break;
702         }
703         default:
704             receiver->item(node);
705     }
706
707 }
708
709 QSourceLocation AccelTree::sourceLocation(const QXmlNodeModelIndex &index) const
710 {
711     const PreNumber key = toPreNumber(index);
712     if (sourcePositions.contains(key)) {
713         const QPair<qint64, qint64> position = sourcePositions.value(key);
714         return QSourceLocation(m_documentURI, position.first, position.second);
715     } else {
716         return QSourceLocation();
717     }
718 }
719
720 void AccelTree::copyChildren(const QXmlNodeModelIndex &node,
721                              QAbstractXmlReceiver *const receiver,
722                              const NodeCopySettings &settings) const
723 {
724     QXmlNodeModelIndex::Iterator::Ptr children(node.iterate(QXmlNodeModelIndex::AxisChild));
725     QXmlNodeModelIndex child(children->next());
726
727     while(!child.isNull())
728     {
729         copyNodeTo(child, receiver, settings);
730         child = children->next();
731     }
732 }
733
734 QXmlNodeModelIndex AccelTree::elementById(const QXmlName &id) const
735 {
736     const PreNumber pre = m_IDs.value(id.localName(), -1);
737     if(pre == -1)
738         return QXmlNodeModelIndex();
739     else
740         return createIndex(pre);
741 }
742
743 QVector<QXmlNodeModelIndex> AccelTree::nodesByIdref(const QXmlName &) const
744 {
745     return QVector<QXmlNodeModelIndex>();
746 }
747
748 QT_END_NAMESPACE
749