source: trunk/src/xmlpatterns/api/qabstractxmlnodemodel.cpp@ 878

Last change on this file since 878 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 54.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtXmlPatterns module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <QVector>
43
44#include "qabstractxmlnodemodel_p.h"
45#include "qabstractxmlreceiver.h"
46#include "qcommonvalues_p.h"
47#include "qemptyiterator_p.h"
48#include "qitemmappingiterator_p.h"
49#include "qitem_p.h"
50#include "qnamespaceresolver_p.h"
51#include "qsequencemappingiterator_p.h"
52#include "qsingletoniterator_p.h"
53
54#include "qabstractxmlnodemodel.h"
55
56QT_BEGIN_NAMESPACE
57
58using namespace QPatternist;
59
60typedef QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<QXmlNodeModelIndex> > QXmlNodeModelIndexIteratorPointer;
61
62/**
63 * @file
64 * @short Contains the implementation of QAbstractXmlNodeModel.
65 */
66
67bool QAbstractXmlNodeModel::isIgnorableInDeepEqual(const QXmlNodeModelIndex &n)
68{
69 Q_ASSERT(!n.isNull());
70 const QXmlNodeModelIndex::NodeKind nk = n.kind();
71 return nk == QXmlNodeModelIndex::ProcessingInstruction ||
72 nk == QXmlNodeModelIndex::Comment;
73}
74
75
76/*!
77 \class QAbstractXmlNodeModel
78 \brief The QAbstractXmlNodeModel class is an abstract base class for modeling non-XML data to look like XML for QXmlQuery.
79 \threadsafe
80 \since 4.4
81 \ingroup xml-tools
82
83 The QAbstractXmlNodeModel specifies the interface that a node model
84 must implement for that node model be accessible to the query engine
85 for processing XQuery queries. A node model represents data as a
86 structure that can be queried as if the data were XML.
87
88 The node model represented by a subclass of QAbstractXmlNodeModel is
89 meant to be accessed by the QtXmlPatterns query engine. If the API
90 seems a little strange in a few places, it is because the member
91 functions are called by the query engine as it evaluates an
92 XQuery. They aren't meant to be used programatically.
93
94 \section1 Usage
95
96 QAbstractXmlNodeModel bridges the gap between the arbitrary structure
97 of the non-XML data to be queried and the well-defined structure of
98 XML data understood by QXmlQuery.
99
100 Consider a chemistry application that reads the file \c
101 chemistryData, which contains non-XML data that represents a
102 chemical structure composed of molecules and atoms. The application
103 will query this chemistry data with an XQuery it reads from file \c
104 queryFile. We write a custom subclass of QAbstractXmlNodeModel (\c
105 ChemistryNodeModel) that reads \c chemistryData and builds a data
106 structure, perhaps composed of objects of our own classes \c
107 molecule and \c atom. Clearly, this data structure is not XML. Our
108 custom subclass will know how to traverse this non-XML structure and
109 present it through the \l
110 {http://www.w3.org/TR/xpath-datamodel/}{XPath Data Model interface}.
111
112 \snippet doc/src/snippets/code/src_xmlpatterns_api_qabstractxmlnodemodel.cpp 1
113
114 The application first creates an instance of QXmlQuery and calls \l
115 {QXmlQuery::setQuery()}{setQuery()} to read \c queryFile containing
116 the XQuery we want to run. Then it creates an instance of our custom
117 node model class, \c ChemistryNodeModel, which is a subclass of
118 QAbstractXmlNodeModel. Its constructor is called with the \l
119 {QXmlNamePool} {name pool} obtained from our QXmlQuery, and with the
120 \c chemistryFile containing the structure of molecules and atoms to
121 be queried. The \l {QXmlNamePool} {name pool} is required because
122 our custom node model has the member function \l
123 {QAbstractXmlNodeModel::name()} {name()}, which returns the \l
124 {QXmlName} {name} of any node in the model. The \l {QXmlQuery}
125 {query} and the custom node model must use the same name pool for
126 constructing these \l {QXmlName} {names}. The constructor would then
127 read \c chemistryFile and build the custom node model structure.
128
129 To connect the \c query to the custom node model, we must bind a
130 variable name used in the query to a node in the model. The variable
131 can then be used in the query as a starting node. First, an \l
132 {QXmlNodeModelIndex} {index} for the desired starting node is
133 retrieved by calling QAbstractXmlNodeModel::createIndex(). Then the
134 index is bound to a variable name, in this case \c queryRoot, by
135 passing the name and the index to QXmlQuery::bindVariable(). The
136 query can then use a variable reference \c $queryRoot to refer to
137 the starting node. Note that if the \l {QXmlQuery} {query} uses
138 multiple variable references, a call to QXmlQuery::bindVariable()
139 is required to bind each different variable name to a node in the
140 model.
141
142 The query is executed when the application calls one of the
143 QXmlQuery evaluation functions. The application uses
144 QXmlQuery::evaluateTo(QAbstractXmlReceiver *), because it then uses
145 a \l {QXmlSerializer} {serializer} to out the query result as XML to
146 \c stdout. We could have used QXmlQuery::evaluateTo(QXmlResultItems
147 *) to get a list of result items, or
148 QXmlQuery::evaluateTo(QStringList *) if the query evaluated to a
149 sequence of \c {xs:string} values.
150
151 During query execution, the engine iterates over the node model
152 using nextFromSimpleAxis() to get the \l {QXmlNodeModelIndex}
153 {index} of the next node to be visited. The engine can get the name
154 of a node by calling name() with the node's \l {QXmlNodeModelIndex}
155 {index}. stringValue(), baseUri(), documentUri() and kind() are also
156 called as needed with a node \l {QXmlNodeModelIndex} {index}.
157
158 The example demonstrates the standard pattern for using a subclass
159 of QAbstractXmlNodeModel in combination with QXmlQuery to perform
160 an XQuery.
161
162 \list 1
163
164 \o Instantiate QXmlQuery and give it the XQuery to be run;
165
166 \o Instantiate a subclass of QAbstractXmlNodeModel or
167 QSimpleXmlNodeModel;
168
169 \o Retrieve a QXmlNodeModelIndex for the node in the model where
170 the QXmlQuery should start the query;
171
172 \o Use QXmlQuery::bindVariable() to bind the QXmlNodeModelIndex
173 to \c {$variable name};
174
175 \o Call one of the QXmlQuery evaluation functions to run the
176 query.
177
178 \endlist
179
180 \section1 Subclassing
181
182 Because the \l {http://www.w3.org/TR/xpath-datamodel/}{XPath Data Model
183 interface} presented by QAbstractXmlNodeModel allows QXmlQuery to
184 operate on non-XML data as if it were XML, implementing subclasses
185 of QAbstractXmlNodeModel can involve a significant amount of
186 work. The QSimpleXmlNodeModel class is provided to simplify the
187 implementation for many common use cases.
188
189 \section1 Thread Safety
190
191 Because the node model can be accessed concurrently by threads in
192 the QtXmlPatterns module, subclasses of QAbstractXmlNodeModel must
193 be written to be \l{Reentrancy and Thread-Safety}{thread-safe}.
194 Classes that simplify implementing thread-safety include QReadLocker
195 and QWriteLocker.
196
197 See the example \l{File System Example} for a demonstration.
198 */
199
200/*!
201 \enum QXmlNodeModelIndex::Constants
202
203 \value ForwardAxis All forward axes include this flag.
204 \value ReverseAxis All reverse axes include this flag.
205 */
206
207/*!
208 \enum QXmlNodeModelIndex::DocumentOrder
209
210 Identifies the specific node comparison operator that should be
211 used.
212
213 \value Precedes Signifies the \c \<\< operator. Test whether the
214 first operand precedes the second in the document.
215
216 \value Follows Signifies the \c \>\> operator. Test whether the
217 first operand follows the second in the document.
218
219 \value Is Signifies the \c is operator. Test whether two nodes have
220 the same node identity.
221 */
222
223/*!
224 \enum QAbstractXmlNodeModel::SimpleAxis
225
226 Four axes that each contain one node only.
227
228 \value Parent The parent of the context node
229 \value FirstChild The first child of the context node
230 \value PreviousSibling The previous child of the context node
231 \value NextSibling The next child of the context node
232*/
233
234/*!
235 \enum QXmlNodeModelIndex::Axis
236 \internal
237
238 Identify the axes emanating from a node.
239
240 The axes AxisChild, AxisDescendant, AxisAttribute, AxisSelf,
241 AxisDescendantOrSelf, AxisFollowingSibling, and AxisFollowing are
242 forward axes.
243
244 The axes AxisParent, AxisAncestor, AxisPrecedingSibling,
245 AxisPreceding and AxisAncestorOrSelf are reverse axes.
246
247 \sa {http://www.w3.org/TR/xquery/#axes}{XQuery 1.0: An XML Query Language, 3.2.1.1 Axes}
248
249 \value AxisChild The \c child axis.
250
251 \value AxisDescendant The \c descendant axis.
252
253 \value AxisAttribute The \c attribute axis. Note: There
254 is a node kind named \c{Attribute}.
255
256 \value AxisSelf The \c self axis.
257
258 \value AxisDescendantOrSelf The \c descendant-or-self axis.
259
260 \value AxisFollowingSibling The \c following-sibling axis.
261
262 \value AxisNamespace The \c namespace axis. Note: Does
263 not exist in XQuery; deprecated in
264 XPath 2.0 (optionally supported);
265 mandatory in XPath 1.0.
266
267 \value AxisFollowing The \c following axis.
268
269 \value AxisParent The \c parent axis.
270
271 \value AxisAncestor The \c ancestor axis.
272
273 \value AxisPrecedingSibling The \c preceding-sibling axis.
274
275 \value AxisPreceding The \c preceding axis.
276
277 \value AxisAncestorOrSelf The \c ancestor-or-self axis.
278*/
279
280using namespace QPatternist;
281
282/*!
283 Default constructor.
284 */
285QAbstractXmlNodeModel::QAbstractXmlNodeModel() : d_ptr(0)
286{
287}
288
289/*!
290 \internal
291
292 Takes the d-pointer.
293
294 */
295QAbstractXmlNodeModel::QAbstractXmlNodeModel(QAbstractXmlNodeModelPrivate *d) : d_ptr(d)
296{
297}
298
299/*!
300 Destructor.
301 */
302QAbstractXmlNodeModel::~QAbstractXmlNodeModel()
303{
304}
305
306/*!
307 \typedef QAbstractXmlNodeModel::List
308
309 A \l{QList}{list} of \l{QExplicitlySharedDataPointer} {smart
310 pointers} to instances of QAbstractXmlNodeModel.
311
312 \sa QExplicitlySharedDataPointer
313 */
314
315/*!
316 \typedef QAbstractXmlNodeModel::Ptr
317
318 A \l {QExplicitlySharedDataPointer} {smart pointer} to an
319 instance of QAbstractXmlNodeModel.
320
321 \sa QExplicitlySharedDataPointer
322 */
323
324/*!
325 \fn QUrl QAbstractXmlNodeModel::baseUri(const QXmlNodeModelIndex &n) const
326
327 Returns the base URI for the node whose index is \a n. The caller
328 guarantees that \a n is not \c null and that it belongs to a node
329 in this node model.
330
331 The base URI of a node can be extracted using the \c fn:base-uri()
332 function. The base URI is typically used for resolving relative URIs
333 that appear in the node or its children. It is conformant to just
334 return the document URI, although that might not properly reflect
335 the underlying data.
336
337 This function maps to the \c dm:base-uri accessor, which returns
338 a base URI according to the following:
339
340 \list
341
342 \o For document nodes, the base URI and the document URI are the same.
343
344 \o For elements, the base URI is the URI appearing in the element's
345 \c xml:base attribute, if present, or it is resolved to the
346 parent element's base URI.
347
348 \o Namespace nodes have no base URI.
349
350 \o The base URI for a processing instruction, comment, attribute,
351 or text node is the base URI of the node's parent element.
352
353 \endlist
354
355 The implementation guarantees to return a valid QUrl, or a default
356 constructed QUrl. If a node has no base URI, as in the case where a
357 comment has no parent, a default constructed QUrl is returned.
358
359 \sa {http://www.w3.org/TR/xpath-datamodel/#dm-base-uri}{XQuery 1.0 and XPath 2.0 Data Model (XDM), 5.2 base-uri Accessor}
360 */
361
362/*!
363 \fn QUrl QAbstractXmlNodeModel::documentUri(const QXmlNodeModelIndex &n) const
364
365 Returns the document URI of \a n. The document URI identifies the
366 resource which is the document. For example, the document could be a
367 regular file, e.g., \c{file:/}, or it could be the \c{http://} URL of
368 the location of a file. The document URI is used for resolving URIs
369 and to simply know where the document is.
370
371 If the node model maps to a URI in a natural way, return that URI.
372 Otherwise, return the company or product URI. The document URI can
373 be any URI as long as its valid and absolute.
374
375 The caller guarantees that \a n is not \c null and that it belongs
376 to this QAbstractXmlNodeModel.
377
378 This function maps to the \c dm:document-uri accessor, which
379 returns a document URI according to the following:
380
381 \list
382
383 \o If \a n is a document node, return an absolute QUrl containing
384 the document URI, or a default constructed QUrl. The latter
385 signals that no document URI is available for the document node.
386
387 \o For all other nodes, return a default constructed QUrl.
388
389 \endlist
390
391 \sa {http://www.w3.org/TR/xpath-datamodel/#dm-document-uri}{XQuery 1.0 and XPath 2.0 Data Model (XDM), 5.4 document-uri Accessor}
392 \sa QUrl::isValid(), QUrl::isRelative()
393 */
394
395/*
396### Qt 5:
397
398Add the function:
399
400 virtual QSourceLocation sourceLocation(const QXmlNodeModelIndex &nodeIndex) const = 0;
401
402Such that the data model can communicate back source locations.
403 */
404
405/*!
406 \fn QXmlNodeModelIndex::NodeKind QAbstractXmlNodeModel::kind(const QXmlNodeModelIndex &ni) const
407
408 Returns a value indicating the kind of node identified by \a ni.
409 The caller guarantees that \a ni is not null and that it identifies
410 a node in this node model. This function maps to the \c
411 dm:node-kind() accessor.
412
413 \sa {http://www.w3.org/TR/xpath-datamodel/#dm-node-kind}{XQuery 1.0 and XPath 2.0 Data Model (XDM), 5.10 node-kind Accessor}
414 */
415
416/*!
417 \fn QXmlNodeModelIndex::DocumentOrder QAbstractXmlNodeModel::compareOrder(const QXmlNodeModelIndex &ni1, const QXmlNodeModelIndex &ni2) const
418
419 This function returns the relative document order for the
420 nodes indexed by \a ni1 and \a ni2. It is used for the \c Is
421 operator and for sorting nodes in document order.
422
423 The caller guarantees that \a ni1 and \a ni2 are not \c null and
424 that both identify nodes in this node model.
425
426 If \a ni1 is identical to \a ni2, QXmlNodeModelIndex::Is is returned.
427 If \a ni1 precedes \a ni2 in document order, QXmlNodeModelIndex::Precedes
428 is returned. If \a ni1 follows \a ni2 in document order,
429 QXmlNodeModelIndex::Follows is returned.
430
431 \sa {http://www.w3.org/TR/xpath-datamodel/#document-order}{XQuery 1.0 and XPath 2.0 Data Model (XDM), 2.4 Document Order}
432 */
433
434/*!
435 \fn QXmlNodeModelIndex QAbstractXmlNodeModel::root(const QXmlNodeModelIndex &n) const
436
437 Returns the root node of the tree that contains the node whose index
438 is \a n. The caller guarantees that \a n is not \c null and that it
439 identifies a node in this node model.
440
441 If \a n identifies a node that is a direct child of the root,
442 parent() would return the same QXmlNodeModelIndex returned by
443 this function.
444 */
445
446namespace QPatternist
447{
448 class MergeIterator
449 {
450 public:
451 inline MergeIterator()
452 {
453 }
454
455 inline
456 QXmlNodeModelIndexIteratorPointer
457 mapToSequence(const QXmlNodeModelIndexIteratorPointer &it,
458 const DynamicContext::Ptr &) const
459 {
460 return it;
461 }
462
463 private:
464 Q_DISABLE_COPY(MergeIterator)
465 };
466
467 static const MergeIterator mergeIterator;
468
469 /**
470 * One might wonder, why not use makeVectorIterator() directly on a QVector
471 * with iterators?
472 *
473 * A problem emerges QAbstractXmlForwardIterator::copy(). All "meta
474 * iterators" that contain other iterators and so forth, propagate the
475 * copy() call such that all involved iterators are copied. However, if we
476 * have a ListIterator of iterators it isn't aware of that it contains
477 * iterators. Hence, we have this class which is specialized(not in the
478 * template sense) on iterators, and hence copies them appropriately.
479 */
480 class IteratorVector : public ListIterator<QXmlNodeModelIndexIteratorPointer, QVector<QXmlNodeModelIndexIteratorPointer> >
481 {
482 typedef QVector<QXmlNodeModelIndexIteratorPointer> ItVector;
483 public:
484 typedef QAbstractXmlForwardIterator<QXmlNodeModelIndexIteratorPointer>::Ptr Ptr;
485
486 IteratorVector(const ItVector &in) : ListIterator<QXmlNodeModelIndexIteratorPointer, QVector<QXmlNodeModelIndexIteratorPointer> >(in)
487 {
488 }
489
490 virtual QAbstractXmlForwardIterator<QXmlNodeModelIndexIteratorPointer>::Ptr copy() const
491 {
492 ItVector result;
493
494 for(int i = 0; i < m_list.count(); ++i)
495 result.append(m_list.at(i)->copy());
496
497 return Ptr(new IteratorVector(result));
498 }
499 };
500}
501
502/*!
503 \internal
504 This function is not a private member of QAbstractXmlNodeModel
505 because it would be messy to forward declare the required types.
506*/
507static inline QXmlNodeModelIndexIteratorPointer mergeIterators(const QXmlNodeModelIndex &node,
508 const QXmlNodeModelIndexIteratorPointer &it2)
509{
510 QVector<QXmlNodeModelIndexIteratorPointer> iterators;
511 iterators.append(makeSingletonIterator(node));
512 iterators.append(it2);
513
514 return makeSequenceMappingIterator<QXmlNodeModelIndex>(&mergeIterator,
515 IteratorVector::Ptr(new IteratorVector(iterators)),
516 DynamicContext::Ptr());
517}
518
519inline QAbstractXmlForwardIterator<QXmlNodeModelIndex>::Ptr
520QAbstractXmlNodeModel::mapToSequence(const QXmlNodeModelIndex &ni,
521 const DynamicContext::Ptr &) const
522{
523 Q_ASSERT(!ni.isNull());
524 /* Since we pass in this here, mapToSequence is used recursively. */
525 return mergeIterators(ni, makeSequenceMappingIterator<QXmlNodeModelIndex>(this,
526 ni.iterate(QXmlNodeModelIndex::AxisChild),
527 DynamicContext::Ptr()));
528}
529
530/*!
531 \fn QVector<QXmlNodeModelIndex> QAbstractXmlNodeModel::attributes(const QXmlNodeModelIndex &element) const
532
533 Returns the attributes of \a element. The caller guarantees
534 that \a element is an element in this node model.
535 */
536
537/*!
538 \internal
539
540 Performs navigation, starting from \a ni, by returning an
541 QAbstractXmlForwardIterator that returns nodes the \a axis emanating
542 from \a ni.
543
544 The implementation returns the nodes on the \a axis, without
545 duplicates and in \a axis order. This means that if \a axis is a
546 reverse axis, which is the case for the \c parent, \c ancestor, \c
547 ancestor-or-self, \c preceding, and \c preceding-sibling, the nodes
548 are delivered in reverse document order. Otherwise the nodes are
549 delivered in document order.
550
551 The implementor guarantees that the nodes delivered for the axes are
552 consistent with the XPath Data Model. This just implies common
553 sense, e.g., The child axis for a comment node can't contain any
554 children; a document node can't be a child of an element, etc.
555 Attributes aren't considered children of an element, but are only
556 available on AxisAttribute.
557
558 The value past in \a axis is not guaranteed based on what is used in
559 a query. QtXmlPatterns may call this function arbitrarily with any
560 value for \a axis. This is because QtXmlPatterns may rewrite queries
561 to be more efficient, using axes in different ways from the original
562 query.
563
564 QAbstractXmlNodeModel::Axis has a good overview of the axes and what
565 they select.
566
567 The caller guarantees that \a ni is not \c null and that it belongs
568 to this QAbstractXmlNodeModel instance.
569
570 Implementing iterate() can involve significant work, since it
571 requires different iterators for all the axes used. In the worst
572 case, it could require writing as many QAbstractXmlForwardIterator
573 subclasses as there are axes, but the number can often be reduced
574 with clever use of lists and template classes. It is better to use
575 or subclass QSimpleXmlNodeModel, which makes it easier to write the
576 node navigation code without loss of efficiency or flexibility.
577
578 \sa QSimpleXmlNodeModel
579 \sa QXmlNodeModelIndex::Axis
580 \sa {http://www.w3.org/TR/xquery/#axes}{XQuery 1.0: An XML Query Language, 3.2.1.1 Axes}
581 \sa {http://www.w3.org/TR/xpath-datamodel/}{W3CXQuery 1.0 and XPath 2.0 Data Model (XDM)}
582 */
583QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<QXmlNodeModelIndex> >
584QAbstractXmlNodeModel::iterate(const QXmlNodeModelIndex &ni,
585 QXmlNodeModelIndex::Axis axis) const
586{
587 /* Returns iterators that track state and calls nextFromSimpleAxis()
588 * iteratively. Typically, when sub-classing QSimpleXmlNodeModel,
589 * you don't reimplement this function, but instead implement
590 * nextFromSimpleAxis(). */
591
592 switch(axis)
593 {
594 case QXmlNodeModelIndex::AxisSelf:
595 return makeSingletonIterator(ni);
596 case QXmlNodeModelIndex::AxisParent:
597 {
598 if(kind(ni) == QXmlNodeModelIndex::Document)
599 return makeEmptyIterator<QXmlNodeModelIndex>();
600 else
601 return makeSingletonIterator(nextFromSimpleAxis(Parent, ni));
602 }
603 case QXmlNodeModelIndex::AxisNamespace:
604 return makeEmptyIterator<QXmlNodeModelIndex>();
605 case QXmlNodeModelIndex::AxisAncestor:
606 {
607 QList<QXmlNodeModelIndex> ancestors;
608 QXmlNodeModelIndex ancestor = nextFromSimpleAxis(Parent, ni);
609
610 while(!ancestor.isNull())
611 {
612 ancestors.append(ancestor);
613 ancestor = nextFromSimpleAxis(Parent, ancestor);
614 }
615
616 return makeListIterator(ancestors);
617 }
618 case QXmlNodeModelIndex::AxisAncestorOrSelf:
619 {
620 QList<QXmlNodeModelIndex> ancestors;
621 ancestors.append(ni);
622 QXmlNodeModelIndex ancestor = nextFromSimpleAxis(Parent, ni);
623
624 while(!ancestor.isNull())
625 {
626 ancestors.append(ancestor);
627 ancestor = nextFromSimpleAxis(Parent, ancestor);
628 }
629
630 return makeListIterator(ancestors);
631 }
632 case QXmlNodeModelIndex::AxisPrecedingSibling:
633 {
634 QList<QXmlNodeModelIndex> preceding;
635 QXmlNodeModelIndex sibling = nextFromSimpleAxis(PreviousSibling, ni);
636
637 while(!sibling.isNull())
638 {
639 preceding.append(sibling);
640 sibling = nextFromSimpleAxis(PreviousSibling, sibling);
641 }
642
643 return makeListIterator(preceding);
644 }
645 case QXmlNodeModelIndex::AxisFollowingSibling:
646 {
647 QList<QXmlNodeModelIndex> preceding;
648 QXmlNodeModelIndex sibling = nextFromSimpleAxis(NextSibling, ni);
649
650 while(!sibling.isNull())
651 {
652 preceding.append(sibling);
653 sibling = nextFromSimpleAxis(NextSibling, sibling);
654 }
655
656 return makeListIterator(preceding);
657 }
658 case QXmlNodeModelIndex::AxisChildOrTop:
659 {
660 if(nextFromSimpleAxis(Parent, ni).isNull())
661 {
662 switch(kind(ni))
663 {
664 case QXmlNodeModelIndex::Comment:
665 /* Fallthrough. */
666 case QXmlNodeModelIndex::ProcessingInstruction:
667 /* Fallthrough. */
668 case QXmlNodeModelIndex::Element:
669 /* Fallthrough. */
670 case QXmlNodeModelIndex::Text:
671 return makeSingletonIterator(ni);
672 case QXmlNodeModelIndex::Attribute:
673 /* Fallthrough. */
674 case QXmlNodeModelIndex::Document:
675 /* Fallthrough. */
676 case QXmlNodeModelIndex::Namespace:
677 /* Do nothing. */;
678 }
679 }
680
681 /* Else, fallthrough to AxisChild. */
682 }
683 case QXmlNodeModelIndex::AxisChild:
684 {
685 QList<QXmlNodeModelIndex> children;
686 QXmlNodeModelIndex child = nextFromSimpleAxis(FirstChild, ni);
687
688 while(!child.isNull())
689 {
690 children.append(child);
691 child = nextFromSimpleAxis(NextSibling, child);
692 }
693
694 return makeListIterator(children);
695 }
696 case QXmlNodeModelIndex::AxisDescendant:
697 {