Home · All Classes · Main Classes · Grouped Classes · Modules · Functions

[Previous: QtXml Module] [Qt's Modules] [Next: QtDesigner Module]

QtXmlPatterns Module

An overview of Qt's XQuery support. More...

Classes

QAbstractMessageHandlerCallback interface for receiving messages
QAbstractUriResolverCallback interface that is used to rewrite one URI as another
QAbstractXmlForwardIteratorAbstract forward iterator
QAbstractXmlNodeModelAbstract interface for representing arbitrary data as XML
QAbstractXmlReceiverCallback interface for transforming the output of a QXmlQuery
QSimpleXmlNodeModelSimple yet powerful way of implementing QAbstractXmlNodeModel
QSourceLocationUsed to identify a location in a resource, using a URI, line number and column number
QXmlFormatterIndents and pretty-formats XML events
QXmlItemRepresents an item in XQuery and XPath, which is either a node or an atomic value
QXmlNameRepresents a name for an XML node in a namespace-aware and efficient way
QXmlNamePoolPool of XML names
QXmlNodeModelIndexUsed to represent a node in a node model
QXmlQueryUsed to evaluate XQuery queries
QXmlResultItemsRepresents the items that are the result of an XQuery query
QXmlSerializerReceives QAbstractXmlReceiver events and produces XML that is sent to a QIODevice

Detailed Description

XQuery is a pragmatic language that allows XML to be queried and created in fast, concise and safe ways.

Introduction

 <bibliography>
 {
     doc("library.xml")/bib/book[publisher = "Addison-Wesley" and @year > 1991]/
     <book year="{@year}">{title}</book>
 }
 </bibliography>

The query opens the file library.xml, and for each book element that is a child of the top element bib, and whose attribute by name year is larger than 1991 and has Addison-Wesley as a publisher, it constructs a book element and attaches it to the parent element called bibliography. Phew!

Why use XQuery?

XQuery is tailor made for selecting and aggregating information in safe and efficient ways. Hence, if an application selects and navigates data, XQuery could be a possible candidate for implementing that in a quick and bug-free manner. With QAbstractXmlNodeModel, these advantages are not constrained to XML files, but can be applied to other data as well.

Maybe XQuery can be summarized as follows:

On top of that the language is designed to be high level such that it is easy to analyze what the user is computing. With this, it is easier to optimize both speed and memory use of XML operations.

Using Patternist

Evaluating queries can be done via an ordinary Qt C++ API and using a command line interface.

C++ API

Configuring the Build Process

Applications that use Patternist's classes need to be configured to be built against the QtXmlPatterns module. To include the definitions of the module's classes, use the following directive:

 #include <QtXmlPatterns>

To link against the module, add this line to your qmake .pro file:

 QT += xmlpatterns

Patternist is part of the Qt Desktop Edition, Qt Open Source Edition and the Qt Console Edition. Note that Patternist is disabled when building Qt, if exceptions are disabled or if a compiler that doesn't support member templates, such as MSVC 6, is used.

See QXmlQuery for how to use the C++ API.

Command line utility

A command line utility called patternist is installed and available like the other command line utilities such as moc or uic. It takes a single argument that is the filename of the query to execute:

patternist myQuery.xq

The query will be run and the output written to stdout.

Pass in the -help switch to get a brief description printed to the console, such as how to bind variables using the command line.

XQuery HOWTO

See A Short Path to XQuery for a round of XQuery.

Qt's and XQuery's Data Model

XQuery and Qt has different data models. All data in XQuery takes the form of sequences of items, where an item is either a node, or an atomic value. Atomic values are the primitives found in W3C XML Schema, and nodes are usual XML nodes, although they might represent other things using QXmlNodeModelIndex and QAbstractXmlNodeModel.

Atomic values, when not being serialized, are represented with QVariant. The mappings are as follows.

From XQueryTo Qt
xs:integerQVariant::LongLong
xs:stringQVariant::String
xs:doubleQVariant::Double
xs:floatQVariant::Double
xs:booleanQVariant::Bool
xs:decimalQVariant::Double
xs:hexBinaryQVariant::ByteArray
xs:base64BinaryQVariant::ByteArray
xs:timeNot supported because xs:time has a zone offset, and QTime does not. Use xs:dateTime, or convert the value to xs:string.
xs:dateQVariant::DateTime
xs:dateTimeQVariant::DateTime
xs:gYearQVariant::DateTime
xs:gYearMonthQVariant::DateTime
xs:gMonthDayQVariant::DateTime
xs:gDayQVariant::DateTime
xs:gMonthQVariant::DateTime
xs:string*QVariant::StringList
xs:anyURIQVariant::Url
xs:untypedAtomicQVariant::String
xs:ENTITYQVariant::String
xs:QNameQXmlName. Note that the returned QXmlName can only be used with the QXmlQuery instance that it was created with.

From QtTo XQuery
QVariant::LongLongxs:integer
QVariant::Intxs:integer
QVariant::UIntxs:nonNegativeInteger
QVariant::ULongLongxs:unsignedLong
QVariant::Stringxs:string
QVariant::Doublexs:double
QVariant::Boolxs:boolean
QVariant::Doublexs:decimal
QVariant::ByteArrayxs:base64Binary
QVariant::Datexs:date. The QDate is assumed to be in timezone UTC.
QVariant::TimeQTime cannot properly represent xs:time. Convert QTime to a QDateTime with a valid arbitrary date, and bind the time as a QDateTime instead.
QVariant::DateTimexs:dateTime
QVariant::StringListxs:string*
QVariant::Urlxs:string
QVariantListA sequence of atomic values, whose type is the same as the first item in the QVariantList instance. If all the items in the QVariantList is not of the same type, behavior is undefined.
Any other typeIt is not supported and will either lead to undefined behavior, or an unexisting variable binding, depending on context.

Integrating with Custom Data

XQuery is a language designed for, and modeled on XML. However, it doesn't have to be constrained to that. By sub-classing QAbstractXmlNodeModel one can write queries on top of any data that can be modeled as XML.

By default when Patternist is asked to open files or to produce content, this is done using an internal representation. For instance, in this query:

 <result>
     <para>The following Acne removers have shipped, ordered by shipping date(oldest first):</para>
     {
         for $i in doc("myOrders.xml")/orders/order[@product = "Acme's Acne Remover"]
         order by xs:date($i/@shippingDate) descending
         return $i
     }
 </result>

an efficient internal representation is used for the file myOrders.xml. However, by sub-classing QAbstractXmlNodeModel one can write a query on any data, by mapping XML elements and attributes to the custom data model. For instance, one could write a QAbstractXmlNodeModel sub-class that mirrors the file system hierarchy like this:

 <?xml version="1.0" encoding="UTF-8"?>
 <directory name="home">

     <file name="myNote.txt" mimetype="text/plain" size="8" extension="txt" uri="file:///home/frans/myNote.txt">
         <content asBase64Binary="TXkgTm90ZSE=" asStringFromUTF-8="My Note!"/>
     </file>

     <directory name="src">
         ...
     </directory>

     ...

 </directory>

and hence have a convenient way to navigate the file system:

 <html>
     <body>
         {
             $myRoot//file[@mimetype = 'text/xml' or @mimetype = 'application/xml']
             /
             (if(doc-available(@uri))
              then ()
              else <p>Failed to parse file {@uri}.</p>)
         }
     </body>
 </html>

Converting a data model to XML(text) and then read it in with an XML tool has been one approach to this, but that has disadvantages such as being inefficient. The XML representation is separated from the actual data model, and that two representations needs to be maintained simultaneously in memory.

With QAbstractXmlNodeModel this conversion is not necessary, nor are two representation kept at the same time, since QXmlNodeModelIndex is a small, efficient, stack allocated value. Also, since the XQuery engine asks the QAbstractXmlNodeModel for the actual data, the model can create elements, attributes and data on demand, depending on what the query actually requests. For instance, in the file system model above, the model doesn't have to read in the whole file system or encoded the content of a file until it is actually asked for.

In other words, with QAbstractXmlNodeModel it's possible to have one data model, and then use the power of the XQuery language on top.

Some examples of possible data models could be:

The documentation for QAbstractXmlNodeModel has the details for implementing this.

More on Custom Data

Since Patternist isn't constrained to XML but can use custom data directly, it turns XQuery into a mapping layer between different custom models or custom models and XML. Once Patternist can understand the data, simple queries can be used to select in it, or to simply write it out as XML using QXmlQuery::serialize().

Consider a word processor application that needs to be able to import and export different formats. Instead of having to write C++ code that converts between the different formats, one writes a query that goes from on type of XML, such as MathML, to another XML format: the one for the document representation that the DocumentRepresentation class below exposes.

In the case of CSV files, which are text, a QAbstractXmlNodeModel sub-class is used again in order to expose the comma-separated file as XML, such that a query can operate on it.

Security Considerations

Query Injection

XQuery is subject to query injection in the same manner that SQL is. If a query is constructed by concatenating strings where some of the strings are from user input, the query can be altered by carefully crafting malicious strings, unless they are properly escaped.

The best solution against these attacks is typically to never construct queries from user-written strings, but instead input the user's data using variable bindings. This avoids all query injection attacks.

See Avoid the dangers of XPath injection, Robi Sen or Blind XPath Injection, Amit Klein for deeper discussions.

Denial of Service Attacks

Patternist has, as all other systems, limits. Generally, these are not checked. This is not a problem for regular use, but it does mean that a malicious query can relatively easy be constructed that causes code to crash or to exercise undefined behavior.

Features and Conformance

Conformance

Patternist aims at being a conformant XQuery implementation. In addition to supporting minimal conformance, the serialization and full-axis features are supported. 95% of the tests in W3C's test suite for XQuery passes, as of this writing.

XML 1.0 and XML Namespaces 1.0 are supported, as opposed to the 1.1 versions.

Since XPath 2.0 is a subset of XQuery 1.0, that is supported too.

The specifications discusses conformance further: XQuery 1.0: An XML Query Language. W3C's XQuery testing effort can be of interest as well, XML Query Test Suite.

Resource Loading

When Patternist attempts to load XML resources, such as via XQuery's fn:doc() function, the following schemes are supported:

Scheme NameDescription
fileLocal files.
dataThe bytes are encoded in the URI itself. For instance, data:application/xml,%3Ce%2F%3E is <e/>.
ftpResources retrieved via FTP.
httpResources retrieved via HTTP.
httpsResources retrieved via HTTPS. This will succeed if no SSL errors are encountered.

URIs are first passed to QAbstractUriResolver(see QXmlQuery::setUriResolver()) for possible rewrites.

[Previous: QtXml Module] [Qt's Modules] [Next: QtDesigner Module]


Copyright © 2007 Trolltech Trademarks
Qt 4.4.0-tp1