1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtXmlPatterns module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include <QVector> |
41 | |
42 | #include "qabstractxmlnodemodel_p.h" |
43 | #include "qabstractxmlreceiver.h" |
44 | #include "qcommonvalues_p.h" |
45 | #include "qemptyiterator_p.h" |
46 | #include "qitemmappingiterator_p.h" |
47 | #include "qitem_p.h" |
48 | #include "qnamespaceresolver_p.h" |
49 | #include "qsequencemappingiterator_p.h" |
50 | #include "qsingletoniterator_p.h" |
51 | |
52 | #include "qabstractxmlnodemodel.h" |
53 | |
54 | QT_BEGIN_NAMESPACE |
55 | |
56 | using namespace QPatternist; |
57 | |
58 | typedef QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<QXmlNodeModelIndex> > QXmlNodeModelIndexIteratorPointer; |
59 | |
60 | /** |
61 | * @file |
62 | * @short Contains the implementation of QAbstractXmlNodeModel. |
63 | */ |
64 | |
65 | bool QAbstractXmlNodeModel::isIgnorableInDeepEqual(const QXmlNodeModelIndex &n) |
66 | { |
67 | Q_ASSERT(!n.isNull()); |
68 | const QXmlNodeModelIndex::NodeKind nk = n.kind(); |
69 | return nk == QXmlNodeModelIndex::ProcessingInstruction || |
70 | nk == QXmlNodeModelIndex::Comment; |
71 | } |
72 | |
73 | |
74 | /*! |
75 | \class QAbstractXmlNodeModel |
76 | \brief The QAbstractXmlNodeModel class is an abstract base class for modeling non-XML data to look like XML for QXmlQuery. |
77 | \threadsafe |
78 | \since 4.4 |
79 | \ingroup xml-tools |
80 | \inmodule QtXmlPatterns |
81 | |
82 | The QAbstractXmlNodeModel specifies the interface that a node model |
83 | must implement for that node model be accessible to the query engine |
84 | for processing XQuery queries. A node model represents data as a |
85 | structure that can be queried as if the data were XML. |
86 | |
87 | The node model represented by a subclass of QAbstractXmlNodeModel is |
88 | meant to be accessed by the Qt XML Patterns query engine. If the API |
89 | seems a little strange in a few places, it is because the member |
90 | functions are called by the query engine as it evaluates an |
91 | XQuery. They aren't meant to be used programatically. |
92 | |
93 | \section1 Usage |
94 | |
95 | QAbstractXmlNodeModel bridges the gap between the arbitrary structure |
96 | of the non-XML data to be queried and the well-defined structure of |
97 | XML data understood by QXmlQuery. |
98 | |
99 | Consider a chemistry application that reads the file \c |
100 | chemistryData, which contains non-XML data that represents a |
101 | chemical structure composed of molecules and atoms. The application |
102 | will query this chemistry data with an XQuery it reads from file \c |
103 | queryFile. We write a custom subclass of QAbstractXmlNodeModel (\c |
104 | ChemistryNodeModel) that reads \c chemistryData and builds a data |
105 | structure, perhaps composed of objects of our own classes \c |
106 | molecule and \c atom. Clearly, this data structure is not XML. Our |
107 | custom subclass will know how to traverse this non-XML structure and |
108 | present it through the \l |
109 | {http://www.w3.org/TR/xpath-datamodel/}{XPath Data Model interface}. |
110 | |
111 | \snippet code/src_xmlpatterns_api_qabstractxmlnodemodel.cpp 1 |
112 | |
113 | The application first creates an instance of QXmlQuery and calls \l |
114 | {QXmlQuery::setQuery()}{setQuery()} to read \c queryFile containing |
115 | the XQuery we want to run. Then it creates an instance of our custom |
116 | node model class, \c ChemistryNodeModel, which is a subclass of |
117 | QAbstractXmlNodeModel. Its constructor is called with the \l |
118 | {QXmlNamePool} {name pool} obtained from our QXmlQuery, and with the |
119 | \c chemistryFile containing the structure of molecules and atoms to |
120 | be queried. The \l {QXmlNamePool} {name pool} is required because |
121 | our custom node model has the member function \l |
122 | {QAbstractXmlNodeModel::name()} {name()}, which returns the \l |
123 | {QXmlName} {name} of any node in the model. The \l {QXmlQuery} |
124 | {query} and the custom node model must use the same name pool for |
125 | constructing these \l {QXmlName} {names}. The constructor would then |
126 | read \c chemistryFile and build the custom node model structure. |
127 | |
128 | To connect the \c query to the custom node model, we must bind a |
129 | variable name used in the query to a node in the model. The variable |
130 | can then be used in the query as a starting node. First, an \l |
131 | {QXmlNodeModelIndex} {index} for the desired starting node is |
132 | retrieved by calling QAbstractXmlNodeModel::createIndex(). Then the |
133 | index is bound to a variable name, in this case \c queryRoot, by |
134 | passing the name and the index to QXmlQuery::bindVariable(). The |
135 | query can then use a variable reference \c $queryRoot to refer to |
136 | the starting node. Note that if the \l {QXmlQuery} {query} uses |
137 | multiple variable references, a call to QXmlQuery::bindVariable() |
138 | is required to bind each different variable name to a node in the |
139 | model. |
140 | |
141 | The query is executed when the application calls one of the |
142 | QXmlQuery evaluation functions. The application uses |
143 | QXmlQuery::evaluateTo(QAbstractXmlReceiver *), because it then uses |
144 | a \l {QXmlSerializer} {serializer} to out the query result as XML to |
145 | \c stdout. We could have used QXmlQuery::evaluateTo(QXmlResultItems |
146 | *) to get a list of result items, or |
147 | QXmlQuery::evaluateTo(QStringList *) if the query evaluated to a |
148 | sequence of \c {xs:string} values. |
149 | |
150 | During query execution, the engine iterates over the node model |
151 | using nextFromSimpleAxis() to get the \l {QXmlNodeModelIndex} |
152 | {index} of the next node to be visited. The engine can get the name |
153 | of a node by calling name() with the node's \l {QXmlNodeModelIndex} |
154 | {index}. stringValue(), baseUri(), documentUri() and kind() are also |
155 | called as needed with a node \l {QXmlNodeModelIndex} {index}. |
156 | |
157 | The example demonstrates the standard pattern for using a subclass |
158 | of QAbstractXmlNodeModel in combination with QXmlQuery to perform |
159 | an XQuery. |
160 | |
161 | \list 1 |
162 | |
163 | \li Instantiate QXmlQuery and give it the XQuery to be run; |
164 | |
165 | \li Instantiate a subclass of QAbstractXmlNodeModel or |
166 | QSimpleXmlNodeModel; |
167 | |
168 | \li Retrieve a QXmlNodeModelIndex for the node in the model where |
169 | the QXmlQuery should start the query; |
170 | |
171 | \li Use QXmlQuery::bindVariable() to bind the QXmlNodeModelIndex |
172 | to \c {$variable name}; |
173 | |
174 | \li Call one of the QXmlQuery evaluation functions to run the |
175 | query. |
176 | |
177 | \endlist |
178 | |
179 | \section1 Subclassing |
180 | |
181 | Because the \l {http://www.w3.org/TR/xpath-datamodel/}{XPath Data Model |
182 | interface} presented by QAbstractXmlNodeModel allows QXmlQuery to |
183 | operate on non-XML data as if it were XML, implementing subclasses |
184 | of QAbstractXmlNodeModel can involve a significant amount of |
185 | work. The QSimpleXmlNodeModel class is provided to simplify the |
186 | implementation for many common use cases. |
187 | |
188 | \section1 Thread Safety |
189 | |
190 | Because the node model can be accessed concurrently by threads in |
191 | the Qt XML Patterns module, subclasses of QAbstractXmlNodeModel must |
192 | be written to be \l{Reentrancy and Thread-Safety}{thread-safe}. |
193 | Classes that simplify implementing thread-safety include QReadLocker |
194 | and QWriteLocker. |
195 | |
196 | See the example \l{File System Example} for a demonstration. |
197 | */ |
198 | |
199 | /*! |
200 | \enum QXmlNodeModelIndex::Constants |
201 | |
202 | \value ForwardAxis All forward axes include this flag. |
203 | \value ReverseAxis All reverse axes include this flag. |
204 | */ |
205 | |
206 | /*! |
207 | \enum QXmlNodeModelIndex::DocumentOrder |
208 | |
209 | Identifies the specific node comparison operator that should be |
210 | used. |
211 | |
212 | \value Precedes Signifies the \c \<\< operator. Test whether the |
213 | first operand precedes the second in the document. |
214 | |
215 | \value Follows Signifies the \c \>\> operator. Test whether the |
216 | first operand follows the second in the document. |
217 | |
218 | \value Is Signifies the \c is operator. Test whether two nodes have |
219 | the same node identity. |
220 | */ |
221 | |
222 | /*! |
223 | \enum QAbstractXmlNodeModel::SimpleAxis |
224 | |
225 | Four axes that each contain one node only. |
226 | |
227 | \value Parent The parent of the context node |
228 | \value FirstChild The first child of the context node |
229 | \value PreviousSibling The previous child of the context node |
230 | \value NextSibling The next child of the context node |
231 | */ |
232 | |
233 | /*! |
234 | \enum QXmlNodeModelIndex::Axis |
235 | \internal |
236 | |
237 | Identify the axes emanating from a node. |
238 | |
239 | The axes AxisChild, AxisDescendant, AxisAttribute, AxisSelf, |
240 | AxisDescendantOrSelf, AxisFollowingSibling, and AxisFollowing are |
241 | forward axes. |
242 | |
243 | The axes AxisParent, AxisAncestor, AxisPrecedingSibling, |
244 | AxisPreceding and AxisAncestorOrSelf are reverse axes. |
245 | |
246 | \sa {http://www.w3.org/TR/xquery/#axes}{XQuery 1.0: An XML Query Language, 3.2.1.1 Axes} |
247 | |
248 | \value AxisChild The \c child axis. |
249 | |
250 | \value AxisDescendant The \c descendant axis. |
251 | |
252 | \value AxisAttribute The \c attribute axis. Note: There |
253 | is a node kind named \c{Attribute}. |
254 | |
255 | \value AxisSelf The \c self axis. |
256 | |
257 | \value AxisDescendantOrSelf The \c descendant-or-self axis. |
258 | |
259 | \value AxisFollowingSibling The \c following-sibling axis. |
260 | |
261 | \value AxisNamespace The \c namespace axis. Note: Does |
262 | not exist in XQuery; deprecated in |
263 | XPath 2.0 (optionally supported); |
264 | mandatory in XPath 1.0. |
265 | |
266 | \value AxisFollowing The \c following axis. |
267 | |
268 | \value AxisParent The \c parent axis. |
269 | |
270 | \value AxisAncestor The \c ancestor axis. |
271 | |
272 | \value AxisPrecedingSibling The \c preceding-sibling axis. |
273 | |
274 | \value AxisPreceding The \c preceding axis. |
275 | |
276 | \value AxisAncestorOrSelf The \c ancestor-or-self axis. |
277 | */ |
278 | |
279 | using namespace QPatternist; |
280 | |
281 | /*! |
282 | Default constructor. |
283 | */ |
284 | QAbstractXmlNodeModel::QAbstractXmlNodeModel() : d_ptr(0) |
285 | { |
286 | } |
287 | |
288 | /*! |
289 | \internal |
290 | |
291 | Takes the d-pointer. |
292 | |
293 | */ |
294 | QAbstractXmlNodeModel::QAbstractXmlNodeModel(QAbstractXmlNodeModelPrivate *d) : d_ptr(d) |
295 | { |
296 | } |
297 | |
298 | /*! |
299 | Destructor. |
300 | */ |
301 | QAbstractXmlNodeModel::~QAbstractXmlNodeModel() |
302 | { |
303 | } |
304 | |
305 | /*! |
306 | \typedef QAbstractXmlNodeModel::List |
307 | |
308 | A \l{QList}{list} of \l{QExplicitlySharedDataPointer} {smart |
309 | pointers} to instances of QAbstractXmlNodeModel. |
310 | |
311 | \sa QExplicitlySharedDataPointer |
312 | */ |
313 | |
314 | /*! |
315 | \typedef QAbstractXmlNodeModel::Ptr |
316 | |
317 | A \l {QExplicitlySharedDataPointer} {smart pointer} to an |
318 | instance of QAbstractXmlNodeModel. |
319 | |
320 | \sa QExplicitlySharedDataPointer |
321 | */ |
322 | |
323 | /*! |
324 | \fn QUrl QAbstractXmlNodeModel::baseUri(const QXmlNodeModelIndex &n) const |
325 | |
326 | Returns the base URI for the node whose index is \a n. The caller |
327 | guarantees that \a n is not \c null and that it belongs to a node |
328 | in this node model. |
329 | |
330 | The base URI of a node can be extracted using the \c fn:base-uri() |
331 | function. The base URI is typically used for resolving relative URIs |
332 | that appear in the node or its children. It is conformant to just |
333 | return the document URI, although that might not properly reflect |
334 | the underlying data. |
335 | |
336 | This function maps to the \c dm:base-uri accessor, which returns |
337 | a base URI according to the following: |
338 | |
339 | \list |
340 | |
341 | \li For document nodes, the base URI and the document URI are the same. |
342 | |
343 | \li For elements, the base URI is the URI appearing in the element's |
344 | \c xml:base attribute, if present, or it is resolved to the |
345 | parent element's base URI. |
346 | |
347 | \li Namespace nodes have no base URI. |
348 | |
349 | \li The base URI for a processing instruction, comment, attribute, |
350 | or text node is the base URI of the node's parent element. |
351 | |
352 | \endlist |
353 | |
354 | The implementation guarantees to return a valid QUrl, or a default |
355 | constructed QUrl. If a node has no base URI, as in the case where a |
356 | comment has no parent, a default constructed QUrl is returned. |
357 | |
358 | \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} |
359 | */ |
360 | |
361 | /*! |
362 | \fn QUrl QAbstractXmlNodeModel::documentUri(const QXmlNodeModelIndex &n) const |
363 | |
364 | Returns the document URI of \a n. The document URI identifies the |
365 | resource which is the document. For example, the document could be a |
366 | regular file, e.g., \c{file:/}, or it could be the \c{http://} URL of |
367 | the location of a file. The document URI is used for resolving URIs |
368 | and to simply know where the document is. |
369 | |
370 | If the node model maps to a URI in a natural way, return that URI. |
371 | Otherwise, return the company or product URI. The document URI can |
372 | be any URI as long as its valid and absolute. |
373 | |
374 | The caller guarantees that \a n is not \c null and that it belongs |
375 | to this QAbstractXmlNodeModel. |
376 | |
377 | This function maps to the \c dm:document-uri accessor, which |
378 | returns a document URI according to the following: |
379 | |
380 | \list |
381 | |
382 | \li If \a n is a document node, return an absolute QUrl containing |
383 | the document URI, or a default constructed QUrl. The latter |
384 | signals that no document URI is available for the document node. |
385 | |
386 | \li For all other nodes, return a default constructed QUrl. |
387 | |
388 | \endlist |
389 | |
390 | \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} |
391 | \sa QUrl::isValid(), QUrl::isRelative() |
392 | */ |
393 | |
394 | /* |
395 | ### Qt 5: |
396 | |
397 | Add the function: |
398 | |
399 | virtual QSourceLocation sourceLocation(const QXmlNodeModelIndex &nodeIndex) const = 0; |
400 | |
401 | Such that the data model can communicate back source locations. |
402 | */ |
403 | |
404 | /*! |
405 | \fn QXmlNodeModelIndex::NodeKind QAbstractXmlNodeModel::kind(const QXmlNodeModelIndex &ni) const |
406 | |
407 | Returns a value indicating the kind of node identified by \a ni. |
408 | The caller guarantees that \a ni is not null and that it identifies |
409 | a node in this node model. This function maps to the \c |
410 | dm:node-kind() accessor. |
411 | |
412 | \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} |
413 | */ |
414 | |
415 | /*! |
416 | \fn QXmlNodeModelIndex::DocumentOrder QAbstractXmlNodeModel::compareOrder(const QXmlNodeModelIndex &ni1, const QXmlNodeModelIndex &ni2) const |
417 | |
418 | This function returns the relative document order for the |
419 | nodes indexed by \a ni1 and \a ni2. It is used for the \c Is |
420 | operator and for sorting nodes in document order. |
421 | |
422 | The caller guarantees that \a ni1 and \a ni2 are not \c null and |
423 | that both identify nodes in this node model. |
424 | |
425 | If \a ni1 is identical to \a ni2, QXmlNodeModelIndex::Is is returned. |
426 | If \a ni1 precedes \a ni2 in document order, QXmlNodeModelIndex::Precedes |
427 | is returned. If \a ni1 follows \a ni2 in document order, |
428 | QXmlNodeModelIndex::Follows is returned. |
429 | |
430 | \sa {http://www.w3.org/TR/xpath-datamodel/#document-order}{XQuery 1.0 and XPath 2.0 Data Model (XDM), 2.4 Document Order} |
431 | */ |
432 | |
433 | /*! |
434 | \fn QXmlNodeModelIndex QAbstractXmlNodeModel::root(const QXmlNodeModelIndex &n) const |
435 | |
436 | Returns the root node of the tree that contains the node whose index |
437 | is \a n. The caller guarantees that \a n is not \c null and that it |
438 | identifies a node in this node model. |
439 | |
440 | If \a n identifies a node that is a direct child of the root, |
441 | parent() would return the same QXmlNodeModelIndex returned by |
442 | this function. |
443 | */ |
444 | |
445 | namespace QPatternist |
446 | { |
447 | class MergeIterator |
448 | { |
449 | public: |
450 | |
451 | inline |
452 | QXmlNodeModelIndexIteratorPointer |
453 | mapToSequence(const QXmlNodeModelIndexIteratorPointer &it, |
454 | const DynamicContext::Ptr &) const |
455 | { |
456 | return it; |
457 | } |
458 | }; |
459 | |
460 | static const MergeIterator mergeIterator = {}; |
461 | |
462 | /** |
463 | * One might wonder, why not use makeVectorIterator() directly on a QVector |
464 | * with iterators? |
465 | * |
466 | * A problem emerges QAbstractXmlForwardIterator::copy(). All "meta |
467 | * iterators" that contain other iterators and so forth, propagate the |
468 | * copy() call such that all involved iterators are copied. However, if we |
469 | * have a ListIterator of iterators it isn't aware of that it contains |
470 | * iterators. Hence, we have this class which is specialized(not in the |
471 | * template sense) on iterators, and hence copies them appropriately. |
472 | */ |
473 | class IteratorVector : public ListIterator<QXmlNodeModelIndexIteratorPointer, QVector<QXmlNodeModelIndexIteratorPointer> > |
474 | { |
475 | typedef QVector<QXmlNodeModelIndexIteratorPointer> ItVector; |
476 | public: |
477 | typedef QAbstractXmlForwardIterator<QXmlNodeModelIndexIteratorPointer>::Ptr Ptr; |
478 | |
479 | IteratorVector(const ItVector &in) : ListIterator<QXmlNodeModelIndexIteratorPointer, QVector<QXmlNodeModelIndexIteratorPointer> >(in) |
480 | { |
481 | } |
482 | |
483 | QAbstractXmlForwardIterator<QXmlNodeModelIndexIteratorPointer>::Ptr copy() const override |
484 | { |
485 | ItVector result; |
486 | const int count = m_list.count(); |
487 | result.reserve(asize: count); |
488 | for (int i = 0; i < count; ++i) |
489 | result.append(t: m_list.at(i)->copy()); |
490 | |
491 | return Ptr(new IteratorVector(result)); |
492 | } |
493 | }; |
494 | } |
495 | |
496 | /*! |
497 | \internal |
498 | This function is not a private member of QAbstractXmlNodeModel |
499 | because it would be messy to forward declare the required types. |
500 | */ |
501 | static inline QXmlNodeModelIndexIteratorPointer mergeIterators(const QXmlNodeModelIndex &node, |
502 | const QXmlNodeModelIndexIteratorPointer &it2) |
503 | { |
504 | QVector<QXmlNodeModelIndexIteratorPointer> iterators; |
505 | iterators.reserve(asize: 2); |
506 | iterators.append(t: makeSingletonIterator(item: node)); |
507 | iterators.append(t: it2); |
508 | |
509 | return makeSequenceMappingIterator<QXmlNodeModelIndex>(mapper: &mergeIterator, |
510 | source: IteratorVector::Ptr(new IteratorVector(iterators)), |
511 | context: DynamicContext::Ptr()); |
512 | } |
513 | |
514 | inline QAbstractXmlForwardIterator<QXmlNodeModelIndex>::Ptr |
515 | QAbstractXmlNodeModel::mapToSequence(const QXmlNodeModelIndex &ni, |
516 | const DynamicContext::Ptr &) const |
517 | { |
518 | Q_ASSERT(!ni.isNull()); |
519 | /* Since we pass in this here, mapToSequence is used recursively. */ |
520 | return mergeIterators(node: ni, it2: makeSequenceMappingIterator<QXmlNodeModelIndex>(mapper: this, |
521 | source: ni.iterate(axis: QXmlNodeModelIndex::AxisChild), |
522 | context: DynamicContext::Ptr())); |
523 | } |
524 | |
525 | /*! |
526 | \fn QVector<QXmlNodeModelIndex> QAbstractXmlNodeModel::attributes(const QXmlNodeModelIndex &element) const |
527 | |
528 | Returns the attributes of \a element. The caller guarantees |
529 | that \a element is an element in this node model. |
530 | */ |
531 | |
532 | /*! |
533 | \internal |
534 | |
535 | Performs navigation, starting from \a ni, by returning an |
536 | QAbstractXmlForwardIterator that returns nodes the \a axis emanating |
537 | from \a ni. |
538 | |
539 | The implementation returns the nodes on the \a axis, without |
540 | duplicates and in \a axis order. This means that if \a axis is a |
541 | reverse axis, which is the case for the \c parent, \c ancestor, \c |
542 | ancestor-or-self, \c preceding, and \c preceding-sibling, the nodes |
543 | are delivered in reverse document order. Otherwise the nodes are |
544 | delivered in document order. |
545 | |
546 | The implementor guarantees that the nodes delivered for the axes are |
547 | consistent with the XPath Data Model. This just implies common |
548 | sense, e.g., The child axis for a comment node can't contain any |
549 | children; a document node can't be a child of an element, etc. |
550 | Attributes aren't considered children of an element, but are only |
551 | available on AxisAttribute. |
552 | |
553 | The value past in \a axis is not guaranteed based on what is used in |
554 | a query. Qt XML Patterns may call this function arbitrarily with any |
555 | value for \a axis. This is because Qt XML Patterns may rewrite queries |
556 | to be more efficient, using axes in different ways from the original |
557 | query. |
558 | |
559 | QAbstractXmlNodeModel::Axis has a good overview of the axes and what |
560 | they select. |
561 | |
562 | The caller guarantees that \a ni is not \c null and that it belongs |
563 | to this QAbstractXmlNodeModel instance. |
564 | |
565 | Implementing iterate() can involve significant work, since it |
566 | requires different iterators for all the axes used. In the worst |
567 | case, it could require writing as many QAbstractXmlForwardIterator |
568 | subclasses as there are axes, but the number can often be reduced |
569 | with clever use of lists and template classes. It is better to use |
570 | or subclass QSimpleXmlNodeModel, which makes it easier to write the |
571 | node navigation code without loss of efficiency or flexibility. |
572 | |
573 | \sa QSimpleXmlNodeModel |
574 | \sa QXmlNodeModelIndex::Axis |
575 | \sa {http://www.w3.org/TR/xquery/#axes}{XQuery 1.0: An XML Query Language, 3.2.1.1 Axes} |
576 | \sa {http://www.w3.org/TR/xpath-datamodel/}{W3CXQuery 1.0 and XPath 2.0 Data Model (XDM)} |
577 | */ |
578 | QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<QXmlNodeModelIndex> > |
579 | QAbstractXmlNodeModel::iterate(const QXmlNodeModelIndex &ni, |
580 | QXmlNodeModelIndex::Axis axis) const |
581 | { |
582 | /* Returns iterators that track state and calls nextFromSimpleAxis() |
583 | * iteratively. Typically, when sub-classing QSimpleXmlNodeModel, |
584 | * you don't reimplement this function, but instead implement |
585 | * nextFromSimpleAxis(). */ |
586 | |
587 | switch(axis) |
588 | { |
589 | case QXmlNodeModelIndex::AxisSelf: |
590 | return makeSingletonIterator(item: ni); |
591 | case QXmlNodeModelIndex::AxisParent: |
592 | { |
593 | if(kind(ni) == QXmlNodeModelIndex::Document) |
594 | return makeEmptyIterator<QXmlNodeModelIndex>(); |
595 | else |
596 | return makeSingletonIterator(item: nextFromSimpleAxis(axis: Parent, origin: ni)); |
597 | } |
598 | case QXmlNodeModelIndex::AxisNamespace: |
599 | return makeEmptyIterator<QXmlNodeModelIndex>(); |
600 | case QXmlNodeModelIndex::AxisAncestor: |
601 | { |
602 | QList<QXmlNodeModelIndex> ancestors; |
603 | QXmlNodeModelIndex ancestor = nextFromSimpleAxis(axis: Parent, origin: ni); |
604 | |
605 | while(!ancestor.isNull()) |
606 | { |
607 | ancestors.append(t: ancestor); |
608 | ancestor = nextFromSimpleAxis(axis: Parent, origin: ancestor); |
609 | } |
610 | |
611 | return makeListIterator(list: ancestors); |
612 | } |
613 | case QXmlNodeModelIndex::AxisAncestorOrSelf: |
614 | { |
615 | QList<QXmlNodeModelIndex> ancestors; |
616 | ancestors.append(t: ni); |
617 | QXmlNodeModelIndex ancestor = nextFromSimpleAxis(axis: Parent, origin: ni); |
618 | |
619 | while(!ancestor.isNull()) |
620 | { |
621 | ancestors.append(t: ancestor); |
622 | ancestor = nextFromSimpleAxis(axis: Parent, origin: ancestor); |
623 | } |
624 | |
625 | return makeListIterator(list: ancestors); |
626 | } |
627 | case QXmlNodeModelIndex::AxisPrecedingSibling: |
628 | { |
629 | QList<QXmlNodeModelIndex> preceding; |
630 | QXmlNodeModelIndex sibling = nextFromSimpleAxis(axis: PreviousSibling, origin: ni); |
631 | |
632 | while(!sibling.isNull()) |
633 | { |
634 | preceding.append(t: sibling); |
635 | sibling = nextFromSimpleAxis(axis: PreviousSibling, origin: sibling); |
636 | } |
637 | |
638 | return makeListIterator(list: preceding); |
639 | } |
640 | case QXmlNodeModelIndex::AxisFollowingSibling: |
641 | { |
642 | QList<QXmlNodeModelIndex> preceding; |
643 | QXmlNodeModelIndex sibling = nextFromSimpleAxis(axis: NextSibling, origin: ni); |
644 | |
645 | while(!sibling.isNull()) |
646 | { |
647 | preceding.append(t: sibling); |
648 | sibling = nextFromSimpleAxis(axis: NextSibling, origin: sibling); |
649 | } |
650 | |
651 | return makeListIterator(list: preceding); |
652 | } |
653 | case QXmlNodeModelIndex::AxisChildOrTop: |
654 | { |
655 | if(nextFromSimpleAxis(axis: Parent, origin: ni).isNull()) |
656 | { |
657 | switch(kind(ni)) |
658 | { |
659 | case QXmlNodeModelIndex::Comment: |
660 | case QXmlNodeModelIndex::ProcessingInstruction: |
661 | case QXmlNodeModelIndex::Element: |
662 | case QXmlNodeModelIndex::Text: |
663 | return makeSingletonIterator(item: ni); |
664 | case QXmlNodeModelIndex::Attribute: |
665 | case QXmlNodeModelIndex::Document: |
666 | case QXmlNodeModelIndex::Namespace: |
667 | /* Do nothing. */; |
668 | } |
669 | } |
670 | |
671 | Q_FALLTHROUGH(); |
672 | } |
673 | case QXmlNodeModelIndex::AxisChild: |
674 | { |
675 | QList<QXmlNodeModelIndex> children; |
676 | QXmlNodeModelIndex child = nextFromSimpleAxis(axis: FirstChild, origin: ni); |
677 | |
678 | while(!child.isNull()) |
679 | { |
680 | children.append(t: child); |
681 | child = nextFromSimpleAxis(axis: NextSibling, origin: child); |
682 | } |
683 | |
684 | return makeListIterator(list: children); |
685 | } |
686 | case QXmlNodeModelIndex::AxisDescendant: |
687 | { |
688 | return makeSequenceMappingIterator<QXmlNodeModelIndex>(mapper: this, |
689 | source: ni.iterate(axis: QXmlNodeModelIndex::AxisChild), |
690 | context: DynamicContext::Ptr()); |
691 | } |
692 | case QXmlNodeModelIndex::AxisAttributeOrTop: |
693 | { |
694 | if(kind(ni) == QXmlNodeModelIndex::Attribute && nextFromSimpleAxis(axis: Parent, origin: ni).isNull()) |
695 | return makeSingletonIterator(item: ni); |
696 | |
697 | Q_FALLTHROUGH(); |
698 | } |
699 | case QXmlNodeModelIndex::AxisAttribute: |
700 | return makeVectorIterator(vector: attributes(element: ni)); |
701 | case QXmlNodeModelIndex::AxisDescendantOrSelf: |
702 | return mergeIterators(node: ni, it2: iterate(ni, axis: QXmlNodeModelIndex::AxisDescendant)); |
703 | case QXmlNodeModelIndex::AxisFollowing: |
704 | case QXmlNodeModelIndex::AxisPreceding: |
705 | { |
706 | /* We walk up along the ancestors, and for each parent, we grab its preceding/following |
707 | * siblings, and evaluate the descendant axis. The descendant axes gets added |
708 | * to a list and we then merge those iterators. */ |
709 | QVector<QXmlNodeModelIndexIteratorPointer> descendantIterators; |
710 | |
711 | QXmlNodeModelIndex current(ni); |
712 | while(!current.isNull()) |
713 | { |
714 | QXmlNodeModelIndex candidate(nextFromSimpleAxis(axis: axis == QXmlNodeModelIndex::AxisPreceding ? PreviousSibling : NextSibling, origin: current)); |
715 | if(candidate.isNull()) |
716 | { |
717 | /* current is an ancestor. We don't want it, so next iteration we |
718 | * will grab its preceding sibling. */ |
719 | current = nextFromSimpleAxis(axis: Parent, origin: current); |
720 | } |
721 | else |
722 | { |
723 | current = candidate; |
724 | descendantIterators.append(t: iterate(ni: current, axis: QXmlNodeModelIndex::AxisDescendantOrSelf)->toReversed()); |
725 | } |
726 | } |
727 | |
728 | return makeSequenceMappingIterator<QXmlNodeModelIndex>(mapper: &mergeIterator, |
729 | source: IteratorVector::Ptr(new IteratorVector(descendantIterators)), |
730 | context: DynamicContext::Ptr()); |
731 | } |
732 | } |
733 | |
734 | Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown axis, internal error." ); |
735 | return makeEmptyIterator<QXmlNodeModelIndex>(); |
736 | } |
737 | |
738 | /*! |
739 | \fn QXmlNodeModelIndex QAbstractXmlNodeModel::nextFromSimpleAxis(SimpleAxis axis, const QXmlNodeModelIndex &origin) const |
740 | |
741 | When Qt XML Patterns evaluate path expressions, it emulate them through a |
742 | combination of calls with QSimpleXmlNodeModel::SimpleAxis values. Therefore, |
743 | the implementation of this function must return the node, if any, that |
744 | appears on the \a axis emanating from the \a origin. |
745 | |
746 | If no such node is available, a default constructed |
747 | QXmlNodeModelIndex is returned. |
748 | |
749 | QSimpleXmlNodeModel eliminates the need to handle redundant corner |
750 | cases by guaranteeing that it will never ask for: |
751 | |
752 | \list |
753 | \li Children or siblings for attributes. |
754 | \li Children for comments, processing instructions, and text nodes. |
755 | \li Siblings or parents for document nodes. |
756 | \endlist |
757 | |
758 | A typical implementation performs a \c switch on the value of \a |
759 | axis: |
760 | |
761 | \code |
762 | QXmlNodeModelIndex MyTreeModel::nextFromSimpleAxis(SimpleAxis axis, const QXmlNodeModelIndex &origin) const |
763 | { |
764 | // Convert the QXmlNodeModelIndex to a value that is specific to what we represent. |
765 | const MyValue value = toMyValue(ni); |
766 | |
767 | switch(axis) |
768 | { |
769 | case Parent: |
770 | return toNodeIndex(value.parent()); |
771 | case FirstChild: |
772 | case PreviousSibling: |
773 | case NextSibling: |
774 | // and so on |
775 | } |
776 | } |
777 | \endcode |
778 | |
779 | */ |
780 | |
781 | /*! |
782 | \fn QXmlNodeModelIndex QAbstractXmlNodeModel::createIndex(qint64 data) const |
783 | |
784 | Creates a node index with \a data as its internal data. \a data is |
785 | not constrained. |
786 | */ |
787 | |
788 | /*! |
789 | \fn QXmlNodeModelIndex QAbstractXmlNodeModel::createIndex(void *pointer, qint64 additionalData) const |
790 | |
791 | Creates a node index with \a pointer and \a additionalData as |
792 | its internal data. |
793 | |
794 | What \a pointer and \a additionalData is, is not constrained. |
795 | */ |
796 | |
797 | /*! |
798 | \fn QXmlNodeModelIndex QAbstractXmlNodeModel::createIndex(qint64 data, qint64 additionalData) const; |
799 | \overload |
800 | |
801 | Creates a QXmlNodeModelIndex containing \a data and \a |
802 | additionalData. |
803 | */ |
804 | |
805 | /*! |
806 | \fn QXmlName QAbstractXmlNodeModel::name(const QXmlNodeModelIndex &ni) const |
807 | |
808 | Returns the name of \a ni. The caller guarantees that \a ni is not |
809 | \c null and that it belongs to this QAbstractXmlNodeModel. |
810 | |
811 | If a node does not have a name, e.g., comment nodes, a null QXmlName |
812 | is returned. QXmlNames must be created with the instance of |
813 | QXmlQuery that is being used for evaluating queries using this |
814 | QAbstractXmlNodeModel. |
815 | |
816 | This function maps to the \c dm:node-name() accessor. |
817 | |
818 | If \a ni is a processing instruction, a QXmlName is returned with |
819 | the local name as the target name and the namespace URI and prefix |
820 | both empty. |
821 | |
822 | \sa {http://www.w3.org/TR/xpath-datamodel/#dm-node-name}{XQuery 1.0 and XPath 2.0 Data Model (XDM), 5.11 node-name Accessor} |
823 | \sa QXmlName |
824 | */ |
825 | |
826 | /*! |
827 | \fn QVector<QXmlName> QAbstractXmlNodeModel::namespaceBindings(const QXmlNodeModelIndex &n) const |
828 | |
829 | Returns the in-scope namespaces of \a n. The caller guarantees that |
830 | \a n is not \c null and that it belongs to this QAbstractXmlNodeModel. |
831 | |
832 | This function corresponds to the \c dm:namespace-nodes accessor. |
833 | |
834 | The returned vector of namespace declarations includes namespaces |
835 | of the ancestors of \a n. |
836 | |
837 | The caller guarantees that \a n is an Element that belongs to this |
838 | QAbstractXmlNodeModel. |
839 | */ |
840 | |
841 | /*! |
842 | \internal |
843 | Sends the namespaces declared on \a n to \a receiver. |
844 | |
845 | As a consequence, no namespaces are sent unless this node is an |
846 | element and has namespaces declared. |
847 | |
848 | The caller guarantees that \a n is not \c null and that it belongs |
849 | to this QAbstractXmlNodeModel instance. |
850 | |
851 | Note that it is not the namespaces that are in scope on \a n, but |
852 | only the namespaces that are specifically declared on \a n. |
853 | |
854 | \a receiver is the receiver that this node is supposed to send its |
855 | namespaces to. This is guaranteed by the caller to be a valid |
856 | pointer. \a n is the index of the node whose namespaces are to |
857 | be sent. |
858 | */ |
859 | void QAbstractXmlNodeModel::sendNamespaces(const QXmlNodeModelIndex &n, |
860 | QAbstractXmlReceiver *const receiver) const |
861 | { |
862 | Q_ASSERT(receiver); |
863 | const QVector<QXmlName> nss(namespaceBindings(n)); |
864 | |
865 | /* This is by far the most common case. */ |
866 | if(nss.isEmpty()) |
867 | return; |
868 | |
869 | const int len = nss.size(); |
870 | for(int i = 0; i < len; ++i) |
871 | receiver->namespaceBinding(name: nss.at(i)); |
872 | } |
873 | |
874 | /*! |
875 | \fn QString QAbstractXmlNodeModel::stringValue(const QXmlNodeModelIndex &n) const |
876 | |
877 | Returns the string value for node \a n. |
878 | |
879 | The caller guarantees that \a n is not \c null and that it belong to |
880 | this QAbstractXmlNodeModel instance. |
881 | |
882 | This function maps to the \c dm:string-value() accessor, which the |
883 | specification completely specifies. Here's a summary: |
884 | |
885 | \list |
886 | |
887 | \li For processing instructions, the string value is the data |
888 | section(excluding any whitespace appearing between the name and the |
889 | data). |
890 | |
891 | \li For text nodes, the string value equals the text node. |
892 | |
893 | \li For comments, the content of the comment |
894 | |
895 | \li For elements, the concatenation of all text nodes that are |
896 | descendants. Note, this is not only the children, but the |
897 | childrens' childrens' text nodes, and so forth. |
898 | |
899 | \li For document nodes, the concatenation of all text nodes in the |
900 | document. |
901 | |
902 | \endlist |
903 | |
904 | \sa {http://www.w3.org/TR/xpath-datamodel/#dm-string-value}{XQuery 1.0 and XPath 2.0 Data Model (XDM), 5.13 string-value Accessor} |
905 | */ |
906 | |
907 | /*! |
908 | \fn QVariant QAbstractXmlNodeModel::typedValue(const QXmlNodeModelIndex &node) const |
909 | |
910 | Returns the typed value for node \a node. |
911 | |
912 | The typed value is an atomic value, which an element or attribute |
913 | contains. |
914 | |
915 | The caller guarantees that \a node is either an element or an |
916 | attribute. The implementor guarantees that the returned QVariant has |
917 | a value which is supported in XQuery. It cannot be an arbitrary |
918 | QVariant value. The implementor also guarantees that stringValue() |
919 | returns a lexical representation of typedValue() (this is guaranteed |
920 | by QSimpleXmlNodeModel::stringValue()). |
921 | |
922 | If the return QVariant is a default constructed variant, it signals |
923 | that \a node has no typed value. |
924 | */ |
925 | |
926 | /*! |
927 | \internal |
928 | */ |
929 | QPatternist::ItemIteratorPtr QAbstractXmlNodeModel::sequencedTypedValue(const QXmlNodeModelIndex &ni) const |
930 | { |
931 | const QVariant &candidate = typedValue(n: ni); |
932 | if(candidate.isNull()) |
933 | return QPatternist::CommonValues::emptyIterator; |
934 | else |
935 | return makeSingletonIterator(item: AtomicValue::toXDM(value: candidate)); |
936 | } |
937 | |
938 | /*! |
939 | \internal |
940 | */ |
941 | QPatternist::ItemTypePtr QAbstractXmlNodeModel::type(const QXmlNodeModelIndex &) const |
942 | { |
943 | Q_ASSERT_X(false, Q_FUNC_INFO, |
944 | "This function is internal and must not be called." ); |
945 | return QPatternist::ItemTypePtr(); |
946 | } |
947 | |
948 | /*! |
949 | \internal |
950 | |
951 | Returns the namespace URI on \a ni that corresponds to \a prefix. |
952 | |
953 | If \a prefix is StandardPrefixes::empty, the namespace URI for the |
954 | default namespace is returned. |
955 | |
956 | The default implementation use namespaceBindings(), in a straight |
957 | forward manner. |
958 | |
959 | If no namespace exists for \a prefix, NamespaceResolver::NoBinding |
960 | is returned. |
961 | |
962 | The caller guarantees to only call this function for element nodes. |
963 | */ |
964 | QXmlName::NamespaceCode QAbstractXmlNodeModel::namespaceForPrefix(const QXmlNodeModelIndex &ni, |
965 | const QXmlName::PrefixCode prefix) const |
966 | { |
967 | Q_ASSERT(kind(ni) == QXmlNodeModelIndex::Element); |
968 | |
969 | const QVector<QXmlName> nbs(namespaceBindings(n: ni)); |
970 | const int len = nbs.size(); |
971 | |
972 | for(int i = 0; i < len; ++i) |
973 | { |
974 | if(nbs.at(i).prefix() == prefix) |
975 | return nbs.at(i).namespaceURI(); |
976 | } |
977 | |
978 | return NamespaceResolver::NoBinding; |
979 | } |
980 | |
981 | |
982 | /*! |
983 | \internal |
984 | |
985 | Determines whether \a ni1 is deep equal to \a ni2. |
986 | |
987 | isDeepEqual() is defined as evaluating the expression \c |
988 | fn:deep-equal($n1, $n2) where \c $n1 is \a ni1 and \c $n1 is \a |
989 | ni2. This function is associative, meaning the same value is |
990 | returned regardless of if isDeepEqual() is invoked with \a ni1 as |
991 | first argument or second. It is guaranteed that \a ni1 and \a ni2 |
992 | are nodes, as opposed to the definition of \c fn:deep-equal(). |
993 | |
994 | Returns true if \a ni1 is deep-equal to \a ni2, otherwise false |
995 | |
996 | \sa {"http://www.w3.org/TR/xpath-functions/#func-deep-equal"}{XQuery 1.0 and XPath 2.0 Functions and Operators, 15.3.1 fn:deep-equal} |
997 | */ |
998 | bool QAbstractXmlNodeModel::isDeepEqual(const QXmlNodeModelIndex &n1, |
999 | const QXmlNodeModelIndex &n2) const |
1000 | { |
1001 | Q_ASSERT(!n1.isNull()); |
1002 | Q_ASSERT(!n2.isNull()); |
1003 | |
1004 | const QXmlNodeModelIndex::NodeKind nk = n1.kind(); |
1005 | |
1006 | if(nk != n2.kind()) |
1007 | return false; |
1008 | |
1009 | if(n1.name() != n2.name()) |
1010 | return false; |
1011 | |
1012 | switch(nk) |
1013 | { |
1014 | case QXmlNodeModelIndex::Element: |
1015 | { |
1016 | QXmlNodeModelIndexIteratorPointer atts1(n1.iterate(axis: QXmlNodeModelIndex::AxisAttribute)); |
1017 | QXmlNodeModelIndex node(atts1->next()); |
1018 | |
1019 | const QXmlNodeModelIndex::List atts2(n2.iterate(axis: QXmlNodeModelIndex::AxisAttribute)->toList()); |
1020 | const QXmlNodeModelIndex::List::const_iterator end(atts2.constEnd()); |
1021 | |
1022 | while(!node.isNull()) |
1023 | { |
1024 | bool equal = false; |
1025 | for(QXmlNodeModelIndex::List::const_iterator it = atts2.constBegin(); it != end; ++it) |
1026 | { |
1027 | if(isDeepEqual(n1: node, n2: (*it))) |
1028 | equal = true; |
1029 | } |
1030 | |
1031 | if(!equal) |
1032 | return false; |
1033 | |
1034 | node = atts1->next(); |
1035 | } |
1036 | |
1037 | /* Fallthrough, so we check the children. */ |
1038 | Q_FALLTHROUGH(); |
1039 | } |
1040 | case QXmlNodeModelIndex::Document: |
1041 | { |
1042 | QXmlNodeModelIndexIteratorPointer itn1(n1.iterate(axis: QXmlNodeModelIndex::AxisChild)); |
1043 | QXmlNodeModelIndexIteratorPointer itn2(n2.iterate(axis: QXmlNodeModelIndex::AxisChild)); |
1044 | |
1045 | while(true) |
1046 | { |
1047 | QXmlNodeModelIndex no1(itn1->next()); |
1048 | QXmlNodeModelIndex no2(itn2->next()); |
1049 | |
1050 | while(!no1.isNull() && isIgnorableInDeepEqual(n: no1)) |
1051 | no1 = itn1->next(); |
1052 | |
1053 | while(!no2.isNull() && isIgnorableInDeepEqual(n: no2)) |
1054 | no2 = itn2->next(); |
1055 | |
1056 | if(!no1.isNull() && !no2.isNull()) |
1057 | { |
1058 | if(!isDeepEqual(n1: no1, n2: no2)) |
1059 | return false; |
1060 | } |
1061 | else |
1062 | return no1.isNull() && no2.isNull(); |
1063 | } |
1064 | |
1065 | return true; |
1066 | } |
1067 | case QXmlNodeModelIndex::Attribute: |
1068 | case QXmlNodeModelIndex::ProcessingInstruction: |
1069 | case QXmlNodeModelIndex::Text: |
1070 | case QXmlNodeModelIndex::Comment: |
1071 | return n1.stringValue() == n2.stringValue(); |
1072 | case QXmlNodeModelIndex::Namespace: |
1073 | { |
1074 | Q_ASSERT_X(false, Q_FUNC_INFO, "Not implemented" ); |
1075 | return false; |
1076 | } |
1077 | } |
1078 | |
1079 | return false; |
1080 | } |
1081 | |
1082 | /*! |
1083 | \class QXmlItem |
1084 | \reentrant |
1085 | \since 4.4 |
1086 | \brief The QXmlItem class contains either an XML node or an atomic value. |
1087 | \ingroup xml-tools |
1088 | \inmodule QtXmlPatterns |
1089 | |
1090 | In XQuery, all expressions evaluate to a sequence of items, where |
1091 | each item is either an XML node or an atomic value. The query in the |
1092 | following snippet evaluates to sequence of five items. |
1093 | |
1094 | \quotefile patternist/items.xq |
1095 | |
1096 | The five items are: An element, an atomic value (binary data encoded |
1097 | in base64), a date, a float, and an attribute. |
1098 | |
1099 | QXmlItem is the class that represents these XQuery items in the |
1100 | Qt XML Patterns API. A non-null instance of QXmlItem is either a node |
1101 | or an atomic value. Calling isNode() or isAtomicValue() tells you |
1102 | which it is. Atomic values are represented elsewhere in the Qt API |
1103 | as instances of QVariant, and an instance of QXmlItem that |
1104 | represents an atomic value can be converted to a QVariant by calling |
1105 | toAtomicValue(). A QXmlItem that wraps a node is represented |
1106 | elsewhere as an instance of QXmlNodeModelIndex. A node QXmlItem can |
1107 | be converted to a QXmlNodeModelIndex by calling toNodeModelIndex(). |
1108 | |
1109 | A default constructed QXmlItem instance is neither a node nor an |
1110 | atomic value. It is considered null, in which case isNull() returns |
1111 | true. |
1112 | |
1113 | An instance of QXmlItem will be left dangling if the |
1114 | \l{QAbstractXmlNodeModel} {XML node model} it |
1115 | refers to is deleted, if it is a QXmlNodeModelIndex. |
1116 | */ |
1117 | |
1118 | /*! |
1119 | \typedef QXmlItem::Iterator |
1120 | A QAbstractXmlForwardIterator over QXmlItem. |
1121 | */ |
1122 | |
1123 | /*! |
1124 | Constructs a null QXmlItem that is neither a node nor an atomic |
1125 | value. isNull() returns true for a default constructed instance. |
1126 | */ |
1127 | QXmlItem::QXmlItem() |
1128 | { |
1129 | m_node.reset(); |
1130 | } |
1131 | |
1132 | bool QXmlItem::internalIsAtomicValue() const |
1133 | { |
1134 | return m_node.model == reinterpret_cast<QAbstractXmlNodeModel *>(~0); |
1135 | } |
1136 | |
1137 | /*! |
1138 | The copy constructor constructs a copy of \a other. |
1139 | */ |
1140 | QXmlItem::QXmlItem(const QXmlItem &other) : m_node(other.m_node) |
1141 | { |
1142 | if(internalIsAtomicValue()) |
1143 | m_atomicValue->ref.ref(); |
1144 | } |
1145 | |
1146 | /*! |
1147 | Constructs an atomic value QXmlItem with \a atomicValue. |
1148 | |
1149 | \sa isAtomicValue() |
1150 | */ |
1151 | QXmlItem::QXmlItem(const QVariant &atomicValue) |
1152 | { |
1153 | m_node.reset(); |
1154 | if(atomicValue.isNull()) |
1155 | { |
1156 | /* Then we behave just like the default constructor. */ |
1157 | return; |
1158 | } |
1159 | |
1160 | /* |
1161 | We can't assign directly to m_atomicValue, because the |
1162 | temporary will self-destruct before we've ref'd it. |
1163 | */ |
1164 | const QPatternist::Item temp(QPatternist::AtomicValue::toXDM(value: atomicValue)); |
1165 | |
1166 | if(temp) |
1167 | { |
1168 | temp.asAtomicValue()->ref.ref(); |
1169 | m_node.model = reinterpret_cast<const QAbstractXmlNodeModel *>(~0); |
1170 | m_atomicValue = temp.asAtomicValue(); |
1171 | } |
1172 | else |
1173 | { |
1174 | m_atomicValue = 0; |
1175 | } |
1176 | } |
1177 | |
1178 | /*! |
1179 | Constructs a node QXmlItem that is a copy of \a node. |
1180 | |
1181 | \sa isNode() |
1182 | */ |
1183 | QXmlItem::QXmlItem(const QXmlNodeModelIndex &node) : m_node(node.m_storage) |
1184 | { |
1185 | } |
1186 | |
1187 | |
1188 | /*! |
1189 | Destructor. |
1190 | */ |
1191 | QXmlItem::~QXmlItem() |
1192 | { |
1193 | if(internalIsAtomicValue() && !m_atomicValue->ref.deref()) |
1194 | delete m_atomicValue; |
1195 | } |
1196 | |
1197 | bool QPatternist::NodeIndexStorage::operator!=(const NodeIndexStorage &other) const |
1198 | { |
1199 | return data != other.data |
1200 | || additionalData != other.additionalData |
1201 | || model != other.model; |
1202 | } |
1203 | |
1204 | /*! |
1205 | Assigns \a other to \c this. |
1206 | */ |
1207 | QXmlItem &QXmlItem::operator=(const QXmlItem &other) |
1208 | { |
1209 | if(m_node != other.m_node) |
1210 | { |
1211 | if(internalIsAtomicValue() && !m_atomicValue->ref.deref()) |
1212 | delete m_atomicValue; |
1213 | |
1214 | m_node = other.m_node; |
1215 | |
1216 | if(internalIsAtomicValue()) |
1217 | m_atomicValue->ref.ref(); |
1218 | } |
1219 | |
1220 | return *this; |
1221 | } |
1222 | |
1223 | /*! |
1224 | Returns true if this item is a Node. Returns false if it |
1225 | is an atomic value or null. |
1226 | |
1227 | \sa isNull(), isAtomicValue() |
1228 | */ |
1229 | bool QXmlItem::isNode() const |
1230 | { |
1231 | return QPatternist::Item::fromPublic(i: *this).isNode(); |
1232 | } |
1233 | |
1234 | /*! |
1235 | Returns true if this item is an atomic value. Returns false |
1236 | if it is a node or null. |
1237 | |
1238 | \sa isNull(), isNode() |
1239 | */ |
1240 | bool QXmlItem::isAtomicValue() const |
1241 | { |
1242 | return internalIsAtomicValue(); |
1243 | } |
1244 | |
1245 | /*! |
1246 | If this QXmlItem represents an atomic value, it is converted |
1247 | to an appropriate QVariant and returned. If this QXmlItem is |
1248 | not an atomic value, the return value is a default constructed |
1249 | QVariant. You can call isAtomicValue() to test whether the |
1250 | item is an atomic value. |
1251 | |
1252 | \sa isAtomicValue() |
1253 | */ |
1254 | QVariant QXmlItem::toAtomicValue() const |
1255 | { |
1256 | if(isAtomicValue()) |
1257 | return QPatternist::AtomicValue::toQt(value: m_atomicValue); |
1258 | else |
1259 | return QVariant(); |
1260 | } |
1261 | |
1262 | /*! |
1263 | If this QXmlItem represents a node, it returns the item as a |
1264 | QXmlNodeModelIndex. If this QXmlItem is not a node, the return |
1265 | value is undefined. You can call isNode() to test whether the |
1266 | item is a node. |
1267 | |
1268 | \sa isNode() |
1269 | */ |
1270 | QXmlNodeModelIndex QXmlItem::toNodeModelIndex() const |
1271 | { |
1272 | if(isNode()) |
1273 | return reinterpret_cast<const QXmlNodeModelIndex &>(m_node); |
1274 | else |
1275 | return QXmlNodeModelIndex(); |
1276 | } |
1277 | |
1278 | /*! |
1279 | Returns true if this QXmlItem is neither a node nor an |
1280 | atomic value. Default constructed instances of QXmlItem |
1281 | are null. |
1282 | */ |
1283 | bool QXmlItem::isNull() const |
1284 | { |
1285 | return !m_node.model; |
1286 | } |
1287 | |
1288 | /*! |
1289 | \class QXmlNodeModelIndex |
1290 | \brief The QXmlNodeModelIndex class identifies a node in an XML node model subclassed from QAbstractXmlNodeModel. |
1291 | \reentrant |
1292 | \since 4.4 |
1293 | \ingroup xml-tools |
1294 | \inmodule QtXmlPatterns |
1295 | |
1296 | QXmlNodeModelIndex is an index into an \l{QAbstractXmlNodeModel} |
1297 | {XML node model}. It contains: |
1298 | |
1299 | \list |
1300 | \li A pointer to an \l{QAbstractXmlNodeModel} {XML node model}, |
1301 | which is returned by model(), and |
1302 | \li Some data, which is returned by data(), internalPointer(), |
1303 | and additionalData(). |
1304 | \endlist |
1305 | |
1306 | Because QXmlNodeModelIndex is intentionally a simple class, it |
1307 | doesn't have member functions for accessing the properties of |
1308 | nodes. For example, it doesn't have functions for getting a |
1309 | node's name or its list of attributes or child nodes. If you find |
1310 | that you need to retrieve this kind of information from your |
1311 | query results, there are two ways to proceed. |
1312 | |
1313 | \list |
1314 | |
1315 | \li Send the output of your XQuery to an \l{QAbstractXmlReceiver} |
1316 | {XML receiver}, or |
1317 | |
1318 | \li Let your XQuery do all the work to produce the desired result. |
1319 | |
1320 | \endlist |
1321 | |
1322 | The second case is explained by example. Suppose you want to |
1323 | populate a list widget with the values of certain attributes from a |
1324 | set of result elements. You could write an XQuery to return the set |
1325 | of elements, and then you would write the code to iterate over the |
1326 | result elements, get their attributes, and extract the desired |
1327 | string values. But the simpler way is to just augment your XQuery to |
1328 | finding the desired attribute values. Then all you have to do is |
1329 | evaluate the XQuery using the version of QXmlQuery::evaluateTo() |
1330 | that populates a QStringList, which you can send directly to your |
1331 | widget. |
1332 | |
1333 | QXmlNodeModelIndex doesn't impose any restrictions on the \c data |
1334 | value an QXmlNodeModelIndex should contain. The meaning of the data |
1335 | left to the associated \l {QAbstractXmlNodeModel} {node model}. |
1336 | Because QXmlNodeModelIndex depends on a particular subclass of |
1337 | QAbstractXmlNodeModel for its existence, the only way you can create |
1338 | an instance of QXmlNodeModelIndex is by asking the node model to |
1339 | create one for you with QAbstractXmlNodeModel::createIndex(). Since |
1340 | that function is protected, it is usually a good idea to write a |
1341 | public function that creates a QXmlNodeModelIndex from arguments that |
1342 | are appropriate for your particular node model. |
1343 | |
1344 | A default constructed node index is said to be null, i.e., isNull() |
1345 | returns true. |
1346 | |
1347 | QXmlNodeModelIndex and QAbstractXmlNodeModel follow the same design |
1348 | pattern used for QModelIndex and QAbstractItemModel. |
1349 | */ |
1350 | |
1351 | /*! |
1352 | \since 4.4 |
1353 | \relates QHash |
1354 | |
1355 | Computes a hash key from the QXmlNodeModelIndex \a index, and |
1356 | returns it. This function would be used by QHash if you wanted |
1357 | to build a hash table for instances of QXmlNodeModelIndex. |
1358 | |
1359 | The hash is computed on QXmlNodeModelIndex::data(), |
1360 | QXmlNodeModelIndex::additionalData(), and |
1361 | QXmlNodeModelIndex::model(). This means the hash key can be used for |
1362 | node indexes from different node models. |
1363 | */ |
1364 | uint qHash(const QXmlNodeModelIndex &index) |
1365 | { |
1366 | return uint(index.data() + index.additionalData() + quintptr(index.model())); |
1367 | } |
1368 | |
1369 | /*! |
1370 | \enum QXmlNodeModelIndex::NodeKind |
1371 | |
1372 | Identifies a kind of node. |
1373 | |
1374 | \value Attribute Identifies an attribute node |
1375 | \value Text Identifies a text node |
1376 | \value Comment Identifies a comment node |
1377 | \value Document Identifies a document node |
1378 | \value Element Identifies an element node |
1379 | \value Namespace Identifies a namespace node |
1380 | \value ProcessingInstruction Identifies a processing instruction. |
1381 | |
1382 | Note that the optional XML declaration at very beginning of the XML |
1383 | document is not a processing instruction |
1384 | |
1385 | \sa QAbstractXmlNodeModel::kind() |
1386 | */ |
1387 | |
1388 | /*! |
1389 | \typedef QXmlNodeModelIndex::List |
1390 | |
1391 | Typedef for QList<QXmlNodeModelIndex>. |
1392 | */ |
1393 | |
1394 | /*! |
1395 | Returns true if this node is the same as \a other. This operator |
1396 | does not compare values, children, or names of nodes. It compares |
1397 | node identities, i.e., whether two nodes are from the same document |
1398 | and are found at the exact same place. |
1399 | */ |
1400 | bool QXmlNodeModelIndex::operator==(const QXmlNodeModelIndex &other) const |
1401 | { |
1402 | return !(m_storage != other.m_storage); |
1403 | } |
1404 | |
1405 | /*! |
1406 | Returns true if \a other is the same node as this. |
1407 | */ |
1408 | bool QXmlNodeModelIndex::operator!=(const QXmlNodeModelIndex &other) const |
1409 | { |
1410 | return !(operator==(other)); |
1411 | } |
1412 | |
1413 | /*! |
1414 | \fn QXmlNodeModelIndex::QXmlNodeModelIndex() |
1415 | |
1416 | Default constructor. Creates an item that is \c null. |
1417 | |
1418 | \sa isNull() |
1419 | */ |
1420 | |
1421 | /*! |
1422 | \fn QXmlNodeModelIndex::QXmlNodeModelIndex(const QXmlNodeModelIndex &other) |
1423 | |
1424 | Standard copy constructor. Creates a QXmlNodeModelIndex instance that |
1425 | is a copy of \a other. |
1426 | */ |
1427 | |
1428 | /*! |
1429 | \fn bool QXmlNodeModelIndex::isNull() const |
1430 | |
1431 | Returns true if this QXmlNodeModelIndex is a default constructed |
1432 | value, otherwise false. |
1433 | |
1434 | A null QXmlNodeModelIndex doesn't represent any node and cannot |
1435 | be used in conjunction with QAbstractXmlNodeModel. |
1436 | */ |
1437 | |
1438 | /*! |
1439 | \fn const QAbstractXmlNodeModel *QXmlNodeModelIndex::model() const |
1440 | |
1441 | Returns the QAbstractXmlNodeModel that this node index refers to. |
1442 | QXmlNodeModelIndex does not own QAbstractXmlNodeModel and does not |
1443 | keep track of its lifetime, so this pointer will dangle if the |
1444 | QAbstractXmlNodeModel is deallocated first. |
1445 | |
1446 | There is no setter for the node model because instances of |
1447 | QXmlNodeModelIndex instances are only created with |
1448 | QAbstractXmlNodeModel::createIndex(). |
1449 | */ |
1450 | |
1451 | /*! |
1452 | \fn qint64 QXmlNodeModelIndex::data() const |
1453 | |
1454 | Returns the first data value. The node index holds two data values. |
1455 | additionalData() returns the second one. |
1456 | |
1457 | \sa additionalData() |
1458 | */ |
1459 | |
1460 | /*! |
1461 | \fn void *QXmlNodeModelIndex::internalPointer() const |
1462 | |
1463 | Returns the first data value as a void* pointer. |
1464 | |
1465 | \sa additionalData() |
1466 | */ |
1467 | |
1468 | /*! |
1469 | \fn qint64 QXmlNodeModelIndex::additionalData() const |
1470 | |
1471 | Returns the second data value. The node index holds two data values. |
1472 | data() returns the first one. |
1473 | |
1474 | \sa data() |
1475 | */ |
1476 | |
1477 | /*! |
1478 | \fn void QXmlNodeModelIndex::reset() |
1479 | \internal |
1480 | |
1481 | Resets this QXmlNodeModelIndex to be null. It is equivalent to |
1482 | writing: |
1483 | |
1484 | \snippet code/src_xmlpatterns_api_qabstractxmlnodemodel.cpp 0 |
1485 | */ |
1486 | |
1487 | /*! |
1488 | \fn QXmlName QXmlNodeModelIndex::name() const |
1489 | \internal |
1490 | */ |
1491 | |
1492 | /*! |
1493 | \typedef QXmlNodeModelIndex::Iterator |
1494 | \internal |
1495 | |
1496 | Typedef for QAbstractXmlForwardIterator<QXmlNodeModelIndex>. |
1497 | */ |
1498 | /*! |
1499 | \fn QXmlNodeModelIndex QXmlNodeModelIndex::root() const |
1500 | \internal |
1501 | */ |
1502 | |
1503 | /*! |
1504 | \fn QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<QXmlNodeModelIndex> > QXmlNodeModelIndex::iterate(const Axis axis) const |
1505 | \internal |
1506 | */ |
1507 | |
1508 | /*! |
1509 | \fn QExplicitlySharedDataPointer<QAbstractXmlForwardIterator<QPatternist::Item> > QXmlNodeModelIndex::sequencedTypedValue() const |
1510 | \internal |
1511 | */ |
1512 | |
1513 | /*! |
1514 | \fn QUrl QXmlNodeModelIndex::documentUri() const |
1515 | \internal |
1516 | */ |
1517 | |
1518 | /*! |
1519 | \fn QUrl QXmlNodeModelIndex::baseUri() const |
1520 | \internal |
1521 | */ |
1522 | |
1523 | /*! |
1524 | \fn NodeKind QXmlNodeModelIndex::kind() const |
1525 | \internal |
1526 | */ |
1527 | |
1528 | /*! |
1529 | \fn bool QXmlNodeModelIndex::isDeepEqual(const QXmlNodeModelIndex &other) const |
1530 | \internal |
1531 | */ |
1532 | |
1533 | /*! |
1534 | \fn DocumentOrder QXmlNodeModelIndex::compareOrder(const QXmlNodeModelIndex &other) const |
1535 | \internal |
1536 | */ |
1537 | |
1538 | /*! |
1539 | \fn void QXmlNodeModelIndex::sendNamespaces(QAbstractXmlReceiver *const receiver) const |
1540 | \internal |
1541 | */ |
1542 | |
1543 | /*! |
1544 | \fn QVector<QXmlName> QXmlNodeModelIndex::namespaceBindings() const |
1545 | \internal |
1546 | */ |
1547 | |
1548 | /*! |
1549 | \fn QXmlNodeModelIndex QAbstractXmlNodeModel::elementById(const QXmlName &id) const |
1550 | |
1551 | Returns the index of the element identified as \a id. XQuery's \c |
1552 | id() function calls this function. |
1553 | |
1554 | The node index returned will be the element node whose value is of |
1555 | type \c ID and equals \a id, or it will be the element node that has |
1556 | an attribute whose typed value is of type \c ID and equals \a id. If |
1557 | there is no such element, a default constructed QXmlNodeModelIndex |
1558 | instance is returned. The implementor guarantees that if the returned |
1559 | node index is not null, it identifies an element. |
1560 | |
1561 | It is not sufficient for an attribute or element to merely be called |
1562 | \c id. Its value type must also be \c ID. However, the reserved name |
1563 | \c xml:id is sufficient. |
1564 | |
1565 | In \a id, the \c{namespace URI} and the \c{prefix} are undefined, and |
1566 | the \c{local name} is the ID that should be looked up. |
1567 | |
1568 | \sa {http://www.w3.org/TR/xpath-functions/#func-id}{XQuery 1.0 and XPath 2.0 Functions and Operators, 15.5.2 fn:id} |
1569 | */ |
1570 | |
1571 | /*! |
1572 | \fn QVector<QXmlNodeModelIndex> QAbstractXmlNodeModel::nodesByIdref(const QXmlName &idref) const |
1573 | |
1574 | Returns the elements and/or attributes that have an \c IDREF value |
1575 | equal to \a idref. XQuery's \c idref() function calls this function. |
1576 | |
1577 | The implementor guarantees that the nodes identified by the returned |
1578 | indexes are elements or attributes. |
1579 | |
1580 | It is not sufficient for an attribute or element to merely be called |
1581 | \c idref. It must also be of type \c IDREF. Elements must be typed as |
1582 | \c xs:IDREF or \c xs:IDREFS, or, in the case of attributes, as \c |
1583 | IDREF or \c IDREFS in the schema. |
1584 | |
1585 | In \a idref, the \c{namespace URI} and the \c{prefix} are undefined, |
1586 | and the \c{local name} is the ID that should be looked up. |
1587 | |
1588 | \sa {http://www.w3.org/TR/xpath-functions/#func-idref}{XQuery 1.0 and XPath 2.0 Functions and Operators, 15.5.3 fn:idref} |
1589 | */ |
1590 | |
1591 | /*! |
1592 | \fn QXmlName::NamespaceCode QXmlNodeModelIndex::namespaceForPrefix(const QXmlName::PrefixCode prefix) const |
1593 | \internal |
1594 | */ |
1595 | |
1596 | /*! |
1597 | \fn QString QXmlNodeModelIndex::stringValue() const |
1598 | \internal |
1599 | */ |
1600 | |
1601 | /*! |
1602 | \fn QPatternist::ItemTypePtr QXmlNodeModelIndex::type() const |
1603 | \internal |
1604 | */ |
1605 | |
1606 | /*! |
1607 | \fn bool QXmlNodeModelIndex::is(const QXmlNodeModelIndex &other) const |
1608 | \internal |
1609 | */ |
1610 | |
1611 | /*! |
1612 | \enum QAbstractXmlNodeModel::NodeCopySetting |
1613 | \internal |
1614 | |
1615 | Controls how nodes are copied with copyNodeTo. |
1616 | |
1617 | \value InheritNamespaces Copies the node with the \c copy-namespaces |
1618 | setting being \c inherit. If not set, \c no-inherit is assumed. |
1619 | \value PreserveNamespaces Copies the node with the \c copy-namespaces |
1620 | settings being \c preserve. If not set, \c no-preserve is assumed. |
1621 | */ |
1622 | |
1623 | /*! |
1624 | \typedef QAbstractXmlNodeModel::NodeCopySettings |
1625 | \internal |
1626 | */ |
1627 | |
1628 | /*! |
1629 | \internal |
1630 | |
1631 | Copies node \a node to \a receiver, steered by \a copySettings. |
1632 | |
1633 | The caller guarantees that \a node is not \c null, and that is |
1634 | belongs to this QAbstractXmlNodeModel instance. |
1635 | |
1636 | The caller guarantees that \a receiver is not \c null. |
1637 | */ |
1638 | void QAbstractXmlNodeModel::copyNodeTo(const QXmlNodeModelIndex &node, |
1639 | QAbstractXmlReceiver *const receiver, |
1640 | const NodeCopySettings ©Settings) const |
1641 | { |
1642 | Q_UNUSED(node); |
1643 | Q_UNUSED(receiver); |
1644 | Q_UNUSED(copySettings); |
1645 | Q_ASSERT_X(false, Q_FUNC_INFO, |
1646 | "This function is not expected to be called." ); |
1647 | } |
1648 | |
1649 | /*! |
1650 | Returns the source location for the object with the given \a index |
1651 | or a default constructed QSourceLocation in case no location |
1652 | information is available. |
1653 | |
1654 | \since 4.6 |
1655 | */ |
1656 | QSourceLocation QAbstractXmlNodeModel::sourceLocation(const QXmlNodeModelIndex &index) const |
1657 | { |
1658 | // TODO: make this method virtual in Qt5 to allow source location support in custom models |
1659 | if (d_ptr) |
1660 | return d_ptr->sourceLocation(index); |
1661 | else |
1662 | return QSourceLocation(); |
1663 | } |
1664 | |
1665 | QT_END_NAMESPACE |
1666 | |