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 <QtCore/QBuffer> |
41 | #include <QtCore/QStringList> |
42 | #include <QtXmlPatterns/QXmlFormatter> |
43 | |
44 | #include "qacceltreeresourceloader_p.h" |
45 | #include "qcommonvalues_p.h" |
46 | #include "qxmlresultitems.h" |
47 | #include "qxmlresultitems_p.h" |
48 | #include "qxmlserializer.h" |
49 | #include "qxpathhelper_p.h" |
50 | |
51 | #include "qxmlquery.h" |
52 | #include "qxmlquery_p.h" |
53 | |
54 | QT_BEGIN_NAMESPACE |
55 | |
56 | /*! |
57 | \class QXmlQuery |
58 | |
59 | \brief The QXmlQuery class performs XQueries on XML data, or on non-XML data modeled to look like XML. |
60 | |
61 | \reentrant |
62 | \since 4.4 |
63 | \ingroup xml-tools |
64 | \inmodule QtXmlPatterns |
65 | |
66 | The QXmlQuery class compiles and executes queries written in the |
67 | \l {http://www.w3.org/TR/xquery/}{XQuery language}. QXmlQuery is |
68 | typically used to query XML data, but it can also query non-XML |
69 | data that has been modeled to look like XML. |
70 | |
71 | Using QXmlQuery to query XML data, as in the snippet below, is |
72 | simple because it can use the built-in \l {QAbstractXmlNodeModel} |
73 | {XML data model} as its delegate to the underlying query engine for |
74 | traversing the data. The built-in data model is specified in \l |
75 | {http://www.w3.org/TR/xpath-datamodel/} {XQuery 1.0 and XPath 2.0 |
76 | Data Model}. |
77 | |
78 | \snippet code/src_xmlpatterns_api_qabstractxmlreceiver.cpp 0 |
79 | |
80 | The example uses QXmlQuery to match the first paragraph of an XML |
81 | document and then \l {QXmlSerializer} {output the result} to a |
82 | device as XML. |
83 | |
84 | Using QXmlQuery to query \e {non-XML} data requires writing a |
85 | subclass of QAbstractXmlNodeModel to use as a replacement for the |
86 | built-in XML data model. The custom data model will be able to |
87 | traverse the non-XML data as required by the QAbstractXmlNodeModel |
88 | interface. An instance of this custom data model then becomes the |
89 | delegate used by the query engine to traverse the non-XML data. For |
90 | an example of how to use QXmlQuery to query non-XML data, see the |
91 | documentation for QAbstractXmlNodeModel. |
92 | |
93 | \section1 Running XQueries |
94 | |
95 | To run a query set up with QXmlQuery, call one of the evaluation |
96 | functions. |
97 | |
98 | \list |
99 | |
100 | \li evaluateTo(QAbstractXmlReceiver *) is called with a pointer to an |
101 | XML \l {QAbstractXmlReceiver} {receiver}, which receives the query |
102 | results as a sequence of callbacks. The receiver callback class is |
103 | like the callback class used for translating the output of a SAX |
104 | parser. QXmlSerializer, for example, is a receiver callback class |
105 | for translating the sequence of callbacks for output as unformatted |
106 | XML text. |
107 | |
108 | \endlist |
109 | |
110 | \list |
111 | |
112 | \li evaluateTo(QXmlResultItems *) is called with a pointer to an |
113 | iterator for an empty sequence of query \l {QXmlResultItems} {result |
114 | items}. The Java-like iterator allows the query results to be |
115 | accessed sequentially. |
116 | |
117 | \endlist |
118 | |
119 | \list |
120 | |
121 | \li evaluateTo(QStringList *) is like evaluateTo(QXmlResultItems *), |
122 | but the query must evaluate to a sequence of strings. |
123 | |
124 | \endlist |
125 | |
126 | \section1 Running XPath Expressions |
127 | |
128 | The XPath language is a subset of the XQuery language, so |
129 | running an XPath expression is the same as running an XQuery |
130 | query. Pass the XPath expression to QXmlQuery using setQuery(). |
131 | |
132 | \section1 Running XSLT Stylesheets |
133 | |
134 | Running an XSLT stylesheet is like running an XQuery, except that |
135 | when you construct your QXmlQuery, you must pass QXmlQuery::XSLT20 |
136 | to tell QXmlQuery to interpret whatever it gets from setQuery() as |
137 | an XSLT stylesheet instead of as an XQuery. You must also set the |
138 | input document by calling setFocus(). |
139 | |
140 | \snippet code/src_xmlpatterns_api_qxmlquery.cpp 7 |
141 | |
142 | \note Currently, setFocus() must be called \e before setQuery() when |
143 | using XSLT. |
144 | |
145 | Another way to run an XSLT stylesheet is to use the \c xmlpatterns |
146 | command line utility. |
147 | |
148 | \code |
149 | xmlpatterns myStylesheet.xsl myInput.xml |
150 | \endcode |
151 | |
152 | \note For the current release, XSLT support should be considered |
153 | experimental. See section \l{XQuery#XSLT 2.0} {XSLT conformance} for |
154 | details. |
155 | |
156 | Stylesheet parameters are bound using bindVariable(). |
157 | |
158 | \section1 Binding A Query To A Starting Node |
159 | |
160 | When a query is run on XML data, as in the snippet above, the |
161 | \c{doc()} function returns the node in the built-in data model where |
162 | the query evaluation will begin. But when a query is run on a custom |
163 | node model containing non-XML data, one of the bindVariable() |
164 | functions must be called to bind a variable name to a starting node |
165 | in the custom model. A $variable reference is used in the XQuery |
166 | text to access the starting node in the custom model. It is not |
167 | necessary to declare the variable name external in the query. See |
168 | the example in the documentation for QAbstractXmlNodeModel. |
169 | |
170 | \section1 Reentrancy and Thread-Safety |
171 | |
172 | QXmlQuery is reentrant but not thread-safe. It is safe to use the |
173 | QxmlQuery copy constructor to create a copy of a query and run the |
174 | same query multiple times. Behind the scenes, QXmlQuery will reuse |
175 | resources such as opened files and compiled queries to the extent |
176 | possible. But it is not safe to use the same instance of QXmlQuery |
177 | in multiple threads. |
178 | |
179 | \section1 Error Handling |
180 | |
181 | Errors can occur during query evaluation. Examples include type |
182 | errors and file loading errors. When an error occurs: |
183 | |
184 | \list |
185 | |
186 | \li The error message is sent to the messageHandler(). |
187 | |
188 | \li QXmlResultItems::hasError() will return \c{true}, or |
189 | evaluateTo() will return \c{false}; |
190 | |
191 | \li The results of the evaluation are undefined. |
192 | |
193 | \endlist |
194 | |
195 | \section1 Resource Management |
196 | |
197 | When a query runs, it parses documents, allocating internal data |
198 | structures to hold them, and it may load other resources over the |
199 | network. It reuses these allocated resources when possible, to |
200 | avoid having to reload and reparse them. |
201 | |
202 | When setQuery() is called, the query text is compiled into an |
203 | internal data structure and optimized. The optimized form can |
204 | then be reused for multiple evaluations of the query. Since the |
205 | compile-and-optimize process can be expensive, repeating it for |
206 | the same query should be avoided by using a separate instance of |
207 | QXmlQuery for each query text. |
208 | |
209 | Once a document has been parsed, its internal representation is |
210 | maintained in the QXmlQuery instance and shared among multiple |
211 | QXmlQuery instances. |
212 | |
213 | An instance of QCoreApplication must exist before QXmlQuery can be |
214 | used. |
215 | |
216 | \section1 Event Handling |
217 | |
218 | When QXmlQuery accesses resources (e.g., calling \c fn:doc() to load a file, |
219 | or accessing a device via a bound variable), the event loop is used, which |
220 | means events will be processed. To avoid processing events when QXmlQuery |
221 | accesses resources, create your QXmlQuery instance in a separate thread. |
222 | */ |
223 | |
224 | /*! |
225 | \enum QXmlQuery::QueryLanguage |
226 | \since 4.5 |
227 | |
228 | Specifies whether you want QXmlQuery to interpret the input to |
229 | setQuery() as an XQuery or as an XSLT stylesheet. |
230 | |
231 | \value XQuery10 XQuery 1.0. |
232 | \value XSLT20 XSLT 2.0 |
233 | \omitvalue XmlSchema11IdentityConstraintSelector The selector, the restricted |
234 | XPath pattern found in W3C XML Schema 1.1 for uniqueness |
235 | contraints. Apart from restricting the syntax, the type check stage |
236 | for the expression assumes a sequence of nodes to be the focus. |
237 | \omitvalue XmlSchema11IdentityConstraintField The field, the restricted |
238 | XPath pattern found in W3C XML Schema 1.1 for uniqueness |
239 | contraints. Apart from restricting the syntax, the type check stage |
240 | for the expression assumes a sequence of nodes to be the focus. |
241 | \omitvalue XPath20 Signifies XPath 2.0. Has no effect in the public API, it's |
242 | used internally. As With XmlSchema11IdentityConstraintSelector and |
243 | XmlSchema11IdentityConstraintField, the type check stage |
244 | for the expression assumes a sequence of nodes to be the focus. |
245 | |
246 | \sa setQuery() |
247 | */ |
248 | |
249 | // ### Qt5: Merge constructor overloads |
250 | /*! |
251 | Constructs an invalid, empty query that cannot be used until |
252 | setQuery() is called. |
253 | |
254 | \note This constructor must not be used if you intend to use |
255 | this QXmlQuery to process XSL-T stylesheets. The other constructor |
256 | must be used in that case. |
257 | */ |
258 | QXmlQuery::QXmlQuery() : d(new QXmlQueryPrivate()) |
259 | { |
260 | } |
261 | |
262 | /*! |
263 | Constructs a QXmlQuery that is a copy of \a other. The new |
264 | instance will share resources with the existing query |
265 | to the extent possible. |
266 | */ |
267 | QXmlQuery::QXmlQuery(const QXmlQuery &other) : d(new QXmlQueryPrivate(*other.d)) |
268 | { |
269 | /* First we have invoked QXmlQueryPrivate's synthesized copy constructor. |
270 | * Keep this section in sync with QXmlQuery::operator=(). */ |
271 | d->detach(); |
272 | } |
273 | |
274 | /*! |
275 | Constructs a query that will use \a np as its name pool. The query |
276 | cannot be evaluated until setQuery() has been called. |
277 | */ |
278 | QXmlQuery::QXmlQuery(const QXmlNamePool &np) : d(new QXmlQueryPrivate(np)) |
279 | { |
280 | } |
281 | |
282 | /*! |
283 | |
284 | Constructs a query that will be used to run Xqueries or XSL-T |
285 | stylesheets, depending on the value of \a queryLanguage. It will use |
286 | \a np as its name pool. |
287 | |
288 | \note If your QXmlQuery will process XSL-T stylesheets, this |
289 | constructor must be used. The default constructor can only |
290 | create instances of QXmlQuery for running XQueries. |
291 | |
292 | \note The XSL-T support in this release is considered experimental. |
293 | See the \l{XQuery#XSLT 2.0} {XSLT conformance} for details. |
294 | |
295 | \since 4.5 |
296 | \sa queryLanguage() |
297 | */ |
298 | QXmlQuery::QXmlQuery(QueryLanguage queryLanguage, |
299 | const QXmlNamePool &np) : d(new QXmlQueryPrivate(np)) |
300 | { |
301 | d->queryLanguage = queryLanguage; |
302 | } |
303 | |
304 | /*! |
305 | Destroys this QXmlQuery. |
306 | */ |
307 | QXmlQuery::~QXmlQuery() |
308 | { |
309 | delete d; |
310 | } |
311 | |
312 | /*! |
313 | Assigns \a other to this QXmlQuery instance. |
314 | */ |
315 | QXmlQuery &QXmlQuery::operator=(const QXmlQuery &other) |
316 | { |
317 | /* Keep this section in sync with QXmlQuery::QXmlQuery(const QXmlQuery &). |
318 | */ |
319 | if(d != other.d) |
320 | { |
321 | *d = *other.d; |
322 | d->detach(); |
323 | } |
324 | |
325 | return *this; |
326 | } |
327 | |
328 | /*! |
329 | Changes the \l {QAbstractMessageHandler}{message handler} for this |
330 | QXmlQuery to \a aMessageHandler. The query sends all compile and |
331 | runtime messages to this message handler. QXmlQuery does not take |
332 | ownership of \a aMessageHandler. |
333 | |
334 | Normally, the default message handler is sufficient. It writes |
335 | compile and runtime messages to \e stderr. The default message |
336 | handler includes color codes if \e stderr can render colors. |
337 | |
338 | Note that changing the message handler after the query has been |
339 | compiled has no effect, i.e. the query uses the same message handler |
340 | at runtime that it uses at compile time. |
341 | |
342 | When QXmlQuery calls QAbstractMessageHandler::message(), |
343 | the arguments are as follows: |
344 | |
345 | \table |
346 | \header |
347 | \li message() argument |
348 | \li Semantics |
349 | \row |
350 | \li QtMsgType type |
351 | \li Only QtWarningMsg and QtFatalMsg are used. The former |
352 | identifies a compile or runtime warning, while the |
353 | latter identifies a dynamic or static error. |
354 | \row |
355 | \li const QString & description |
356 | \li An XHTML document which is the actual message. It is translated |
357 | into the current language. |
358 | \row |
359 | \li const QUrl &identifier |
360 | \li Identifies the error with a URI, where the fragment is |
361 | the error code, and the rest of the URI is the error namespace. |
362 | \row |
363 | \li const QSourceLocation & sourceLocation |
364 | \li Identifies where the error occurred. |
365 | \endtable |
366 | |
367 | */ |
368 | void QXmlQuery::setMessageHandler(QAbstractMessageHandler *aMessageHandler) |
369 | { |
370 | d->messageHandler = aMessageHandler; |
371 | } |
372 | |
373 | /*! |
374 | Returns the message handler that handles compile and runtime |
375 | messages for this QXmlQuery. |
376 | */ |
377 | QAbstractMessageHandler *QXmlQuery::messageHandler() const |
378 | { |
379 | return d->messageHandler; |
380 | } |
381 | |
382 | /*! |
383 | Sets this QXmlQuery to an XQuery read from the \a sourceCode |
384 | device. The device must have been opened with at least |
385 | QIODevice::ReadOnly. |
386 | |
387 | \a documentURI represents the query obtained from the \a sourceCode |
388 | device. It is the base URI of the static context, as defined in the |
389 | \l {http://www.w3.org/TR/xquery/}{XQuery language}. It is used |
390 | internally to resolve relative URIs that appear in the query, and |
391 | for message reporting. \a documentURI can be empty. If it is empty, |
392 | the \l{QCoreApplication::applicationFilePath()} {application file |
393 | path} is used. If it is not empty, it may be either relative or |
394 | absolute. If it is relative, it is resolved itself against the |
395 | \l {QCoreApplication::applicationFilePath()} {application file |
396 | path} before it is used. If \a documentURI is neither a valid URI |
397 | nor empty, the result is undefined. |
398 | |
399 | If the query contains a static error (e.g. syntax error), an error |
400 | message is sent to the messageHandler(), and isValid() will return |
401 | \e false. |
402 | |
403 | Variables must be bound before setQuery() is called. |
404 | |
405 | The encoding of the XQuery in \a sourceCode is detected internally |
406 | using the rules for setting and detecting encoding of XQuery files, |
407 | which are explained in the \l {http://www.w3.org/TR/xquery/} |
408 | {XQuery language}. |
409 | |
410 | If \a sourceCode is \c null or not readable, or if \a documentURI is not |
411 | a valid URI, behavior is undefined. |
412 | \sa isValid() |
413 | */ |
414 | void QXmlQuery::setQuery(QIODevice *sourceCode, const QUrl &documentURI) |
415 | { |
416 | if(!sourceCode) |
417 | { |
418 | qWarning(msg: "A null QIODevice pointer cannot be passed." ); |
419 | return; |
420 | } |
421 | |
422 | if(!sourceCode->isReadable()) |
423 | { |
424 | qWarning(msg: "The device must be readable." ); |
425 | return; |
426 | } |
427 | |
428 | d->queryURI = QPatternist::XPathHelper::normalizeQueryURI(uri: documentURI); |
429 | d->expression(queryDevice: sourceCode); |
430 | } |
431 | |
432 | /*! |
433 | \overload |
434 | The behavior and requirements of this function are the same as for |
435 | setQuery(QIODevice*, const QUrl&), after the XQuery has been read |
436 | from the IO device into a string. Because \a sourceCode is already |
437 | a Unicode string, detection of its encoding is unnecessary. |
438 | */ |
439 | void QXmlQuery::setQuery(const QString &sourceCode, const QUrl &documentURI) |
440 | { |
441 | Q_ASSERT_X(documentURI.isEmpty() || documentURI.isValid(), Q_FUNC_INFO, |
442 | "The document URI must be valid." ); |
443 | |
444 | QByteArray query(sourceCode.toUtf8()); |
445 | QBuffer buffer(&query); |
446 | buffer.open(openMode: QIODevice::ReadOnly); |
447 | |
448 | setQuery(sourceCode: &buffer, documentURI); |
449 | } |
450 | |
451 | /*! |
452 | Sets this QXmlQuery to the XQuery read from the \a queryURI. Use |
453 | isValid() after calling this function. If an error occurred reading |
454 | \a queryURI, e.g., the query does not exist, cannot be read, or is |
455 | invalid, isValid() will return \e false. |
456 | |
457 | The supported URI schemes are the same as those in the XQuery |
458 | function \c{fn:doc}, except that queryURI can be the object of |
459 | a variable binding. |
460 | |
461 | \a baseURI is the Base URI of the static context, as defined in the |
462 | \l {http://www.w3.org/TR/xquery/}{XQuery language}. It is used |
463 | internally to resolve relative URIs that appear in the query, and |
464 | for message reporting. If \a baseURI is empty, \a queryURI is used. |
465 | Otherwise, \a baseURI is used, and it is resolved against the \l |
466 | {QCoreApplication::applicationFilePath()} {application file path} if |
467 | it is relative. |
468 | |
469 | If \a queryURI is empty or invalid, or if \a baseURI is invalid, |
470 | the behavior of this function is undefined. |
471 | */ |
472 | void QXmlQuery::setQuery(const QUrl &queryURI, const QUrl &baseURI) |
473 | { |
474 | Q_ASSERT_X(queryURI.isValid(), Q_FUNC_INFO, "The passed URI must be valid." ); |
475 | |
476 | const QUrl canonicalURI(QPatternist::XPathHelper::normalizeQueryURI(uri: queryURI)); |
477 | Q_ASSERT(canonicalURI.isValid()); |
478 | Q_ASSERT(!canonicalURI.isRelative()); |
479 | Q_ASSERT(baseURI.isValid() || baseURI.isEmpty()); |
480 | |
481 | d->queryURI = QPatternist::XPathHelper::normalizeQueryURI(uri: baseURI.isEmpty() ? queryURI : baseURI); |
482 | |
483 | QPatternist::AutoPtr<QIODevice> result; |
484 | |
485 | try |
486 | { |
487 | result.reset(other: QPatternist::AccelTreeResourceLoader::load(uri: canonicalURI, networkDelegator: d->m_networkAccessDelegator, |
488 | context: d->staticContext())); |
489 | } |
490 | catch(const QPatternist::Exception) |
491 | { |
492 | /* We do nothing, result will be 0. */ |
493 | } |
494 | |
495 | if(result) |
496 | { |
497 | setQuery(sourceCode: result.data(), documentURI: d->queryURI); |
498 | result->close(); |
499 | } |
500 | else |
501 | d->recompileRequired(); |
502 | } |
503 | |
504 | /*! |
505 | Binds the variable \a name to the \a value so that $\a name can be |
506 | used from within the query to refer to the \a value. |
507 | |
508 | \a name must not be \e null. \a {name}.isNull() must return false. |
509 | If \a name has already been bound by a previous bindVariable() call, |
510 | its previous binding will be overridden. |
511 | |
512 | If \a {value} is null so that \a {value}.isNull() returns true, and |
513 | \a {name} already has a binding, the effect is to remove the |
514 | existing binding for \a {name}. |
515 | |
516 | To bind a value of type QString or QUrl, wrap the value in a |
517 | QVariant such that QXmlItem's QVariant constructor is called. |
518 | |
519 | All strings processed by the query must be valid XQuery strings, |
520 | which means they must contain only XML 1.0 characters. However, |
521 | this requirement is not checked. If the query processes an invalid |
522 | string, the behavior is undefined. |
523 | |
524 | \sa QVariant::isValid(), {QtXDM}{How QVariant maps to XQuery's Data Model}, |
525 | QXmlItem::isNull() |
526 | */ |
527 | void QXmlQuery::bindVariable(const QXmlName &name, const QXmlItem &value) |
528 | { |
529 | if(name.isNull()) |
530 | { |
531 | qWarning(msg: "The variable name cannot be null." ); |
532 | return; |
533 | } |
534 | |
535 | const QPatternist::VariableLoader::Ptr vl(d->variableLoader()); |
536 | const QVariant variant(QVariant::fromValue(value)); |
537 | |
538 | /* If the type of the variable changed(as opposed to only the value), |
539 | * we will have to recompile. */ |
540 | if(vl->invalidationRequired(name, variant) || value.isNull()) |
541 | d->recompileRequired(); |
542 | |
543 | vl->addBinding(name, value: variant); |
544 | } |
545 | |
546 | /*! |
547 | \overload |
548 | |
549 | This function constructs a QXmlName from \a localName using the |
550 | query's \l {QXmlNamePool} {namespace}. The function then behaves as |
551 | the overloaded function. It is equivalent to the following snippet. |
552 | |
553 | \snippet code/src_xmlpatterns_api_qxmlquery.cpp 0 |
554 | */ |
555 | void QXmlQuery::bindVariable(const QString &localName, const QXmlItem &value) |
556 | { |
557 | bindVariable(name: QXmlName(d->namePool, localName), value); |
558 | } |
559 | |
560 | /*! |
561 | Binds the variable \a name to the \a device so that $\a name can be |
562 | used from within the query to refer to the \a device. The QIODevice |
563 | \a device is exposed to the query as a URI of type \c{xs:anyURI}, |
564 | which can be passed to the \c{fn:doc()} function to be read. E.g., |
565 | this function can be used to pass an XML document in memory to |
566 | \c{fn:doc}. |
567 | |
568 | \snippet code/src_xmlpatterns_api_qxmlquery.cpp 1 |
569 | |
570 | The caller must ensure that \a device has been opened with at least |
571 | QIODevice::ReadOnly prior to this binding. Otherwise, behavior is |
572 | undefined. |
573 | |
574 | If the query will access an XML document contained in a QString, use |
575 | a QBuffer as shown in the following snippet. Suppose \e myQString |
576 | contains \c{<document>content</document>} |
577 | |
578 | \snippet qxmlquery/bindingExample.cpp 0 |
579 | |
580 | \a name must not be \e null. \a {name}.isNull() must return false. |
581 | If \a name has already been bound, its previous binding will be |
582 | overridden. The URI that \a name evaluates to is arbitrary and may |
583 | change. |
584 | |
585 | If the type of the variable binding changes (e.g., if a previous |
586 | binding by the same name was a QVariant, or if there was no previous |
587 | binding), isValid() will return \c{false}, and recompilation of the |
588 | query text is required. To recompile the query, call setQuery(). For |
589 | this reason, bindVariable() should be called before setQuery(), if |
590 | possible. |
591 | |
592 | \note \a device must not be deleted while this QXmlQuery exists. |
593 | */ |
594 | void QXmlQuery::bindVariable(const QXmlName &name, QIODevice *device) |
595 | { |
596 | if(device && !device->isReadable()) |
597 | { |
598 | qWarning(msg: "A null, or readable QIODevice must be passed." ); |
599 | return; |
600 | } |
601 | |
602 | if(name.isNull()) |
603 | { |
604 | qWarning(msg: "The variable name cannot be null." ); |
605 | return; |
606 | } |
607 | |
608 | const QPatternist::VariableLoader::Ptr vl(d->variableLoader()); |
609 | |
610 | if(device) |
611 | { |
612 | const QVariant variant(QVariant::fromValue(value: device)); |
613 | |
614 | if(vl->invalidationRequired(name, variant)) |
615 | d->recompileRequired(); |
616 | |
617 | vl->addBinding(name, value: variant); |
618 | |
619 | /* We need to tell the resource loader to discard its document, because |
620 | * the underlying QIODevice has changed, but the variable name is the |
621 | * same which means that the URI is the same, and hence the resource |
622 | * loader will return the document for the old QIODevice. |
623 | */ |
624 | d->resourceLoader()->clear(uri: QUrl(QLatin1String("tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:" ) + d->namePool.d->stringForLocalName(code: name.localName()))); |
625 | } |
626 | else |
627 | { |
628 | vl->removeBinding(name); |
629 | d->recompileRequired(); |
630 | } |
631 | } |
632 | |
633 | /*! |
634 | \overload |
635 | |
636 | If \a localName is a valid \l {QXmlName::isNCName()} {NCName}, this |
637 | function is equivalent to the following snippet. |
638 | |
639 | \snippet code/src_xmlpatterns_api_qxmlquery.cpp 2 |
640 | |
641 | A QXmlName is constructed from \a localName, and is passed |
642 | to the appropriate overload along with \a device. |
643 | |
644 | \sa QXmlName::isNCName() |
645 | */ |
646 | void QXmlQuery::bindVariable(const QString &localName, QIODevice *device) |
647 | { |
648 | bindVariable(name: QXmlName(d->namePool, localName), device); |
649 | } |
650 | |
651 | /*! |
652 | Evaluates this query and sends the result as a sequence of callbacks |
653 | to the \l {QAbstractXmlReceiver} {receiver} \a callback. QXmlQuery |
654 | does not take ownership of \a callback. |
655 | |
656 | If an error occurs during the evaluation, error messages are sent to |
657 | messageHandler() and \c false is returned. |
658 | |
659 | If this query \l {isValid()} {is invalid}, \c{false} is returned |
660 | and the behavior is undefined. If \a callback is null, |
661 | behavior is undefined. |
662 | |
663 | \sa QAbstractXmlReceiver, isValid() |
664 | */ |
665 | bool QXmlQuery::evaluateTo(QAbstractXmlReceiver *callback) const |
666 | { |
667 | if(!callback) |
668 | { |
669 | qWarning(msg: "A non-null callback must be passed." ); |
670 | return false; |
671 | } |
672 | |
673 | if(isValid()) |
674 | { |
675 | try |
676 | { |
677 | /* |
678 | * This order is significant. expression() might cause |
679 | * query recompilation, and as part of that it recreates |
680 | * the static context. However, if we create the dynamic |
681 | * context before the query recompilation has been |
682 | * triggered, it will use the old static context, and |
683 | * hence old source locations. |
684 | */ |
685 | const QPatternist::Expression::Ptr expr(d->expression()); |
686 | const QPatternist::DynamicContext::Ptr dynContext(d->dynamicContext(callback)); |
687 | callback->startOfSequence(); |
688 | expr->evaluateToSequenceReceiver(context: dynContext); |
689 | callback->endOfSequence(); |
690 | return true; |
691 | } |
692 | catch(const QPatternist::Exception) |
693 | { |
694 | return false; |
695 | } |
696 | } |
697 | else |
698 | return false; |
699 | } |
700 | |
701 | /*! |
702 | Attempts to evaluate the query and returns the results in the |
703 | \a target \l {QStringList} {string list}. |
704 | |
705 | If the query \l {isValid()} {is valid} and the evaluation succeeds, |
706 | true is returned. Otherwise, false is returned and the contents of |
707 | \a target are undefined. |
708 | |
709 | The query must evaluate to a sequence of \c{xs:string} values. If |
710 | the query does not evaluate to a sequence of strings, the values can |
711 | often be converted by adding a call to \c{string()} at the end of |
712 | the XQuery. |
713 | |
714 | If \a target is null, the behavior is undefined. |
715 | */ |
716 | bool QXmlQuery::evaluateTo(QStringList *target) const |
717 | { |
718 | if(!target) |
719 | { |
720 | qWarning(msg: "A non-null callback must be passed." ); |
721 | return false; |
722 | } |
723 | |
724 | if(isValid()) |
725 | { |
726 | try |
727 | { |
728 | /* |
729 | * This order is significant. expression() might cause |
730 | * query recompilation, and as part of that it recreates |
731 | * the static context. However, if we create the dynamic |
732 | * context before the query recompilation has been |
733 | * triggered, it will use the old static context, and |
734 | * hence old source locations. |
735 | */ |
736 | const QPatternist::Expression::Ptr expr(d->expression()); |
737 | if(!expr) |
738 | return false; |
739 | |
740 | QPatternist::DynamicContext::Ptr dynContext(d->dynamicContext()); |
741 | |
742 | if(!QPatternist::BuiltinTypes::xsString->xdtTypeMatches(other: expr->staticType()->itemType())) |
743 | return false; |
744 | |
745 | const QPatternist::Item::Iterator::Ptr it(expr->evaluateSequence(context: dynContext)); |
746 | QPatternist::Item next(it->next()); |
747 | |
748 | while(!next.isNull()) |
749 | { |
750 | target->append(t: next.stringValue()); |
751 | next = it->next(); |
752 | } |
753 | |
754 | return true; |
755 | } |
756 | catch(const QPatternist::Exception) |
757 | { |
758 | return false; |
759 | } |
760 | } |
761 | else |
762 | return false; |
763 | } |
764 | |
765 | /*! |
766 | Evaluates the query or stylesheet, and writes the output to \a target. |
767 | |
768 | QXmlSerializer is used to write the output to \a target. In a future |
769 | release, it is expected that this function will be changed to |
770 | respect serialization options set in the stylesheet. |
771 | |
772 | If an error occurs during the evaluation, error messages are sent to |
773 | messageHandler() and \c false is returned. |
774 | |
775 | If \a target is \c null, or is not opened in at least |
776 | QIODevice::WriteOnly mode, the behavior is undefined. QXmlQuery |
777 | does not take ownership of \a target. |
778 | |
779 | \since 4.5 |
780 | \overload |
781 | */ |
782 | bool QXmlQuery::evaluateTo(QIODevice *target) const |
783 | { |
784 | if(!target) |
785 | { |
786 | qWarning(msg: "The pointer to the device cannot be null." ); |
787 | return false; |
788 | } |
789 | |
790 | if(!target->isWritable()) |
791 | { |
792 | qWarning(msg: "The device must be writable." ); |
793 | return false; |
794 | } |
795 | |
796 | QXmlSerializer serializer(*this, target); |
797 | return evaluateTo(callback: &serializer); |
798 | } |
799 | |
800 | /*! |
801 | Starts the evaluation and makes it available in \a result. If \a |
802 | result is null, the behavior is undefined. The evaluation takes |
803 | place incrementally (lazy evaluation), as the caller uses |
804 | QXmlResultItems::next() to get the next result. |
805 | |
806 | \sa QXmlResultItems::next() |
807 | */ |
808 | void QXmlQuery::evaluateTo(QXmlResultItems *result) const |
809 | { |
810 | if(!result) |
811 | { |
812 | qWarning(msg: "A null pointer cannot be passed." ); |
813 | return; |
814 | } |
815 | |
816 | if(isValid()) |
817 | { |
818 | try |
819 | { |
820 | /* |
821 | * We don't have the d->expression() calls and |
822 | * d->dynamicContext() calls in the same order as seen in |
823 | * QXmlQuery::evaluateTo(), and the reason to why |
824 | * that isn't a problem, is that we call isValid(). |
825 | */ |
826 | const QPatternist::DynamicContext::Ptr dynContext(d->dynamicContext()); |
827 | result->d_ptr->setDynamicContext(dynContext); |
828 | result->d_ptr->iterator = d->expression()->evaluateSequence(context: dynContext); |
829 | } |
830 | catch(const QPatternist::Exception) |
831 | { |
832 | result->d_ptr->iterator = QPatternist::CommonValues::emptyIterator; |
833 | result->d_ptr->hasError = true; |
834 | } |
835 | } |
836 | else |
837 | { |
838 | result->d_ptr->iterator= QPatternist::CommonValues::emptyIterator; |
839 | result->d_ptr->hasError = true; |
840 | } |
841 | } |
842 | |
843 | /*! |
844 | Evaluates the query, and serializes the output as XML to \a output. |
845 | |
846 | If an error occurs during the evaluation, error messages are sent to |
847 | messageHandler(), the content of \a output is undefined and \c false is |
848 | returned, otherwise \c true is returned. |
849 | |
850 | If \a output is \c null behavior is undefined. QXmlQuery |
851 | does not take ownership of \a output. |
852 | |
853 | Internally, the class QXmlFormatter is used for this. |
854 | \since 4.5 |
855 | */ |
856 | bool QXmlQuery::evaluateTo(QString *output) const |
857 | { |
858 | Q_ASSERT_X(output, Q_FUNC_INFO, |
859 | "The input cannot be null" ); |
860 | |
861 | QBuffer outputDevice; |
862 | outputDevice.open(openMode: QIODevice::ReadWrite); |
863 | |
864 | QXmlFormatter formatter(*this, &outputDevice); |
865 | const bool success = evaluateTo(callback: &formatter); |
866 | |
867 | outputDevice.close(); |
868 | *output = QString::fromUtf8(str: outputDevice.data().constData()); |
869 | |
870 | return success; |
871 | } |
872 | |
873 | /*! |
874 | Returns true if this query is valid. Examples of invalid queries |
875 | are ones that contain syntax errors or that have not had setQuery() |
876 | called for them yet. |
877 | */ |
878 | bool QXmlQuery::isValid() const |
879 | { |
880 | return d->isValid(); |
881 | } |
882 | |
883 | /*! |
884 | Sets the URI resolver to \a resolver. QXmlQuery does not take |
885 | ownership of \a resolver. |
886 | |
887 | \sa uriResolver() |
888 | */ |
889 | void QXmlQuery::setUriResolver(const QAbstractUriResolver *resolver) |
890 | { |
891 | d->uriResolver = resolver; |
892 | } |
893 | |
894 | /*! |
895 | Returns the query's URI resolver. If no URI resolver has been set, |
896 | Qt XML Patterns will use the URIs in queries as they are. |
897 | |
898 | The URI resolver provides a level of abstraction, or \e{polymorphic |
899 | URIs}. A resolver can rewrite \e{logical} URIs to physical ones, or |
900 | it can translate obsolete or invalid URIs to valid ones. |
901 | |
902 | Qt XML Patterns calls the URI resolver for all URIs it encounters, |
903 | except for namespaces. Specifically, all builtin functions that deal |
904 | with URIs (\c{fn:doc()}, and \c{fn:doc-available()}). |
905 | |
906 | In the case of \c{fn:doc()}, the absolute URI is the base URI in the |
907 | static context (which most likely is the location of the query). |
908 | Rather than use the URI the user specified, the return value of |
909 | QAbstractUriResolver::resolve() will be used. |
910 | |
911 | When Qt XML Patterns calls QAbstractUriResolver::resolve() the |
912 | absolute URI is the URI mandated by the XQuery language, and the |
913 | relative URI is the URI specified by the user. |
914 | |
915 | \sa setUriResolver() |
916 | */ |
917 | const QAbstractUriResolver *QXmlQuery::uriResolver() const |
918 | { |
919 | return d->uriResolver; |
920 | } |
921 | |
922 | /*! |
923 | Returns the name pool used by this QXmlQuery for constructing \l |
924 | {QXmlName} {names}. There is no setter for the name pool, because |
925 | mixing name pools causes errors due to name confusion. |
926 | */ |
927 | QXmlNamePool QXmlQuery::namePool() const |
928 | { |
929 | return d->namePool; |
930 | } |
931 | |
932 | /*! |
933 | Sets the focus to \a item. The focus is the set of items that the |
934 | context item expression and path expressions navigate from. For |
935 | example, in the expression \e p/span, the element that \e p |
936 | evaluates to is the focus for the following expression, \e span. |
937 | |
938 | The focus can be accessed using the context item expression, i.e., |
939 | dot ("."). |
940 | |
941 | By default, the focus is not set and is undefined. It will |
942 | therefore result in a dynamic error, \c XPDY0002, if the focus |
943 | is attempted to be accessed. The focus must be set before the |
944 | query is set with setQuery(). |
945 | |
946 | There is no behavior defined for setting an item which is null. |
947 | |
948 | */ |
949 | void QXmlQuery::setFocus(const QXmlItem &item) |
950 | { |
951 | d->contextItem = item; |
952 | } |
953 | |
954 | /** |
955 | * This function should be a private member function of QXmlQuery, |
956 | * but we don't dare that due to our weird compilers. |
957 | * @internal |
958 | * @relates QXmlQuery |
959 | */ |
960 | template<typename TInputType> |
961 | bool setFocusHelper(QXmlQuery *const queryInstance, |
962 | const TInputType &focusValue) |
963 | { |
964 | /* We call resourceLoader(), so we have ensured that we have a resourceLoader |
965 | * that we will share in our copy. */ |
966 | queryInstance->d->resourceLoader(); |
967 | |
968 | QXmlQuery focusQuery(*queryInstance); |
969 | |
970 | /* Now we use the same, so we own the loaded document. */ |
971 | focusQuery.d->m_resourceLoader = queryInstance->d->m_resourceLoader; |
972 | |
973 | /* The copy constructor doesn't allow us to copy an existing QXmlQuery and |
974 | * changing the language at the same time so we need to use private API. */ |
975 | focusQuery.d->queryLanguage = QXmlQuery::XQuery10; |
976 | |
977 | Q_ASSERT(focusQuery.queryLanguage() == QXmlQuery::XQuery10); |
978 | focusQuery.bindVariable(QChar::fromLatin1(c: 'u'), focusValue); |
979 | focusQuery.setQuery(sourceCode: QLatin1String("doc($u)" )); |
980 | Q_ASSERT(focusQuery.isValid()); |
981 | |
982 | QXmlResultItems focusResult; |
983 | |
984 | queryInstance->d->m_resourceLoader = focusQuery.d->m_resourceLoader; |
985 | |
986 | focusQuery.evaluateTo(result: &focusResult); |
987 | const QXmlItem focusItem(focusResult.next()); |
988 | |
989 | if(focusItem.isNull() || focusResult.hasError()) |
990 | return false; |
991 | else |
992 | { |
993 | queryInstance->setFocus(focusItem); |
994 | return true; |
995 | } |
996 | } |
997 | |
998 | /*! |
999 | \since 4.5 |
1000 | \overload |
1001 | |
1002 | Sets the focus to be the document located at \a documentURI and |
1003 | returns true. If \a documentURI cannot be loaded, false is returned. |
1004 | It is undefined at what time the document may be loaded. When |
1005 | loading the document, the message handler and URI resolver set on |
1006 | this QXmlQuery are used. |
1007 | |
1008 | If \a documentURI is empty or is not a valid URI, the behavior of |
1009 | this function is undefined. |
1010 | */ |
1011 | bool QXmlQuery::setFocus(const QUrl &documentURI) |
1012 | { |
1013 | Q_ASSERT_X(documentURI.isValid() && !documentURI.isEmpty(), |
1014 | Q_FUNC_INFO, |
1015 | "The URI passed must be valid." ); |
1016 | |
1017 | return setFocusHelper(queryInstance: this, focusValue: QVariant(documentURI)); |
1018 | } |
1019 | |
1020 | /*! |
1021 | |
1022 | Sets the focus to be the \a document read from the QIODevice and |
1023 | returns true. If \a document cannot be loaded, false is returned. |
1024 | |
1025 | QXmlQuery does not take ownership of \a document. The user |
1026 | guarantees that a document is available from the \a document device |
1027 | and that the document is not empty. The device must be opened in at |
1028 | least read-only mode. \a document must stay in scope as long as the |
1029 | current query is active. |
1030 | |
1031 | \since 4.5 |
1032 | \overload |
1033 | */ |
1034 | bool QXmlQuery::setFocus(QIODevice *document) |
1035 | { |
1036 | if(!document) |
1037 | { |
1038 | qWarning(msg: "A null QIODevice pointer cannot be passed." ); |
1039 | return false; |
1040 | } |
1041 | |
1042 | if(!document->isReadable()) |
1043 | { |
1044 | qWarning(msg: "The device must be readable." ); |
1045 | return false; |
1046 | } |
1047 | |
1048 | return setFocusHelper(queryInstance: this, focusValue: document); |
1049 | } |
1050 | |
1051 | /*! |
1052 | This function behaves identically to calling the setFocus() overload with a |
1053 | QIODevice whose content is \a focus encoded as UTF-8. That is, \a focus is |
1054 | treated as if it contained an XML document. |
1055 | |
1056 | Returns the same result as the overload. |
1057 | |
1058 | \overload |
1059 | \since 4.6 |
1060 | */ |
1061 | bool QXmlQuery::setFocus(const QString &focus) |
1062 | { |
1063 | QBuffer device; |
1064 | device.setData(focus.toUtf8()); |
1065 | device.open(openMode: QIODevice::ReadOnly); |
1066 | |
1067 | return setFocusHelper(queryInstance: this, focusValue: &device); |
1068 | } |
1069 | |
1070 | /*! |
1071 | Returns a value indicating what this QXmlQuery is being used for. |
1072 | The default is QXmlQuery::XQuery10, which means the QXmlQuery is |
1073 | being used for running XQuery and XPath queries. QXmlQuery::XSLT20 |
1074 | can also be returned, which indicates the QXmlQuery is for running |
1075 | XSL-T spreadsheets. |
1076 | |
1077 | \since 4.5 |
1078 | */ |
1079 | QXmlQuery::QueryLanguage QXmlQuery::queryLanguage() const |
1080 | { |
1081 | return d->queryLanguage; |
1082 | } |
1083 | |
1084 | /*! |
1085 | Sets the \a name of the initial template. The initial template is |
1086 | the one the processor calls first, instead of attempting to match a |
1087 | template to the context node (if any). If an initial template is not |
1088 | set, the standard order of template invocation will be used. |
1089 | |
1090 | This function only applies when using QXmlQuery to process XSL-T |
1091 | stylesheets. The name becomes part of the compiled stylesheet. |
1092 | Therefore, this function must be called before calling setQuery(). |
1093 | |
1094 | If the stylesheet has no template named \a name, the processor will |
1095 | use the standard order of template invocation. |
1096 | |
1097 | \since 4.5 |
1098 | \sa initialTemplateName() |
1099 | */ |
1100 | void QXmlQuery::setInitialTemplateName(const QXmlName &name) |
1101 | { |
1102 | d->initialTemplateName = name; |
1103 | } |
1104 | |
1105 | /*! |
1106 | \overload |
1107 | |
1108 | Sets the name of the initial template to \a localName, which must be |
1109 | a valid \l{QXmlName::localName}{local name}. The initial template |
1110 | is the one the processor calls first, instead of attempting to match |
1111 | a template to the context node (if any). If an initial template is |
1112 | not set, the standard order of template invocation will be used. |
1113 | |
1114 | This function only applies when using QXmlQuery to process XSL-T |
1115 | stylesheets. The name becomes part of the compiled stylesheet. |
1116 | Therefore, this function must be called before calling setQuery(). |
1117 | |
1118 | If \a localName is not a valid \l{QXmlName::localName} {local |
1119 | name}, the effect is undefined. If the stylesheet has no template |
1120 | named \a localName, the processor will use the standard order of |
1121 | template invocation. |
1122 | |
1123 | \since 4.5 |
1124 | \sa initialTemplateName() |
1125 | */ |
1126 | void QXmlQuery::setInitialTemplateName(const QString &localName) |
1127 | { |
1128 | Q_ASSERT_X(QXmlName::isNCName(localName), |
1129 | Q_FUNC_INFO, |
1130 | "The name passed must be a valid NCName." ); |
1131 | setInitialTemplateName(QXmlName(d->namePool, localName)); |
1132 | } |
1133 | |
1134 | /*! |
1135 | Returns the name of the XSL-T stylesheet template that the processor |
1136 | will call first when running an XSL-T stylesheet. This function only |
1137 | applies when using QXmlQuery to process XSL-T stylesheets. By |
1138 | default, no initial template is set. In that case, a default |
1139 | constructed QXmlName is returned. |
1140 | |
1141 | \since 4.5 |
1142 | */ |
1143 | QXmlName QXmlQuery::initialTemplateName() const |
1144 | { |
1145 | return d->initialTemplateName; |
1146 | } |
1147 | |
1148 | /*! |
1149 | Sets the network manager to \a newManager. |
1150 | QXmlQuery does not take ownership of \a newManager. |
1151 | |
1152 | \sa networkAccessManager() |
1153 | \since 4.5 |
1154 | */ |
1155 | void QXmlQuery::setNetworkAccessManager(QNetworkAccessManager *newManager) |
1156 | { |
1157 | d->m_networkAccessDelegator->m_genericManager = newManager; |
1158 | } |
1159 | |
1160 | /*! |
1161 | Returns the network manager, or 0 if it has not been set. |
1162 | |
1163 | \sa setNetworkAccessManager() |
1164 | \since 4.5 |
1165 | */ |
1166 | QNetworkAccessManager *QXmlQuery::networkAccessManager() const |
1167 | { |
1168 | return d->m_networkAccessDelegator->m_genericManager; |
1169 | } |
1170 | |
1171 | /*! |
1172 | Binds the result of the query \a query, to a variable by name \a name. |
1173 | |
1174 | Evaluation of \a query will be commenced when this function is called. |
1175 | |
1176 | If \a query is invalid, behavior is undefined. \a query will be copied. |
1177 | |
1178 | \since 4.5 |
1179 | \sa isValid() |
1180 | */ |
1181 | void QXmlQuery::bindVariable(const QXmlName &name, const QXmlQuery &query) |
1182 | { |
1183 | Q_ASSERT_X(query.isValid(), Q_FUNC_INFO, "The query being bound must be valid." ); |
1184 | |
1185 | const QPatternist::VariableLoader::Ptr vl(d->variableLoader()); |
1186 | const QVariant variant(QVariant::fromValue(value: query)); |
1187 | |
1188 | if(vl->invalidationRequired(name, variant)) |
1189 | d->recompileRequired(); |
1190 | |
1191 | vl->addBinding(name, value: variant); |
1192 | } |
1193 | |
1194 | /*! |
1195 | \overload |
1196 | |
1197 | Has the same behavior and effects as the function being overloaded, but takes |
1198 | the variable name \a localName as a QString. \a query is used as in the |
1199 | overloaded function. |
1200 | |
1201 | \since 4.5 |
1202 | */ |
1203 | void QXmlQuery::bindVariable(const QString &localName, const QXmlQuery &query) |
1204 | { |
1205 | return bindVariable(name: QXmlName(d->namePool, localName), query); |
1206 | } |
1207 | |
1208 | QT_END_NAMESPACE |
1209 | |