1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the documentation of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:FDL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Free Documentation License
17 ** Alternatively, this file may be used under the terms of the GNU Free
18 ** Documentation License version 1.3 as published by the Free Software
19 ** Foundation and appearing in the file included in the packaging of this
22 ** If you have questions regarding the use of this file, please contact
23 ** Nokia at qt-info@nokia.com.
26 ****************************************************************************/
29 \example xmlpatterns/filetree
30 \title File System Example
32 This example shows how to use QtXmlPatterns for querying non-XML
33 data that is modeled to look like XML.
37 \section1 Introduction
39 The example models your computer's file system to look like XML and
40 allows you to query the file system with XQuery. Suppose we want to
41 find all the \c{cpp} files in the subtree beginning at
44 \image filetree_1-example.png
46 \section2 The User Inteface
48 The example is shown below. First, we use \c{File->Open Directory}
49 (not shown) to select the \c{/filetree} directory. Then we use the
50 combobox on the right to select the XQuery that searches for \c{cpp}
51 files (\c{listCPPFiles.xq}). Selecting an XQuery runs the query,
52 which in this case traverses the model looking for all the \c{cpp}
53 files. The XQuery text and the query results are shown on the right:
55 \image filetree_2-example.png
57 Don't be mislead by the XML representation of the \c{/filetree}
58 directory shown on the left. This is not the node model itself but
59 the XML obtained by traversing the node model and outputting it as
60 XML. Constructing and using the custom node model is explained in
61 the code walk-through.
63 \section2 Running your own XQueries
65 You can write your own XQuery files and run them in the example
66 program. The file \c{xmlpatterns/filetree/queries.qrc} is the \l{The
67 Qt Resource System} {resource file} for this example. It is used in
68 \c{main.cpp} (\c{Q_INIT_RESOURCE(queries);}). It lists the XQuery
69 files (\c{.xq}) that can be selected in the combobox.
71 \quotefromfile examples/xmlpatterns/filetree/queries.qrc
74 To add your own queries to the example's combobox, store your
75 \c{.xq} files in the \c{examples/xmlpatterns/filetree/queries}
76 directory and add them to \c{queries.qrc} as shown above.
78 \section1 Code Walk-Through
80 The strategy is to create a custom node model that represents the
81 directory tree of the computer's file system. That tree structure is
82 non-XML data. The custom node model must have the same callback
83 interface as the XML node models that the QtXmlPatterns query engine
84 uses to execute queries. The query engine can then traverse the
85 custom node model as if it were traversing the node model built from
88 The required callback interface is in QAbstractXmlNodeModel, so we
89 create a custom node model by subclassing QAbstractXmlNodeModel and
90 providing implementations for its pure virtual functions. For many
91 cases, the implementations of several of the virtual functions are
92 always the same, so QtXmlPatterns also provides QSimpleXmlNodeModel,
93 which subclasses QAbstractXmlNodeModel and provides implementations
94 for the callback functions that you can ignore. By subclassing
95 QSimpleXmlNodeModel instead of QAbstractXmlNodeModel, you can reduce
98 \section2 The Custom Node Model Class: FileTree
100 The custom node model for this example is class \c{FileTree}, which
101 is derived from QSimpleXmlNodeModel. \c{FileTree} implements all the
102 callback functions that don't have standard implementations in
103 QSimpleXmlNodeModel. When you implement your own custom node model,
104 you must provide implementations for these callback functions:
106 \snippet examples/xmlpatterns/filetree/filetree.h 0
107 \snippet examples/xmlpatterns/filetree/filetree.h 1
109 The \c{FileTree} class declares four data members:
111 \snippet examples/xmlpatterns/filetree/filetree.h 2
113 The QVector \c{m_fileInfos} will contain the node model. Each
114 QFileInfo in the vector will represent a file or a directory in the
115 file system. At this point it is instructive to note that although
116 the node model class for this example (\c{FileTree}) actually builds
117 and contains the custom node model, building the custom node model
118 isn't always required. The node model class for the \l{QObject XML
119 Model Example} {QObject node model example} does not build its node
120 model but instead uses an already existing QObject tree as its node
121 model and just implements the callback interface for that already
122 existing data structure. In this file system example, however,
123 although we have an already existing data structure, i.e. the file
124 system, that data structure is not in memory and is not in a form we
125 can use. So we must build an analog of the file system in memory
126 from instances of QFileInfo, and we use that analog as the custom
129 The two sets of flags, \c{m_filterAllowAll} and \c{m_sortFlags},
130 contain OR'ed flags from QDir::Filters and QDir::SortFlags
131 respectively. They are set by the \c{FileTree} constructor and used
132 in calls to QDir::entryInfoList() for getting the child list for a
133 directory node, i.e. a QFileInfoList containing the file and
134 directory nodes for all the immediate children of a directory.
136 The QVector \c{m_names} is an auxiliary component of the node
137 model. It holds the XML element and attribute names (QXmlName) for
138 all the node types that will be found in the node model. \c{m_names}
139 is indexed by the enum \c{FileTree::Type}, which specifies the node
143 \snippet examples/xmlpatterns/filetree/filetree.h 4
145 \c{Directory} and \c{File} will represent the XML element nodes for
146 directories and files respectively, and the other enum values will
147 represent the XML attribute nodes for a file's path, name, suffix,
148 its size in bytes, and its mime type. The \c{FileTree} constructor
149 initializes \c{m_names} with an appropriate QXmlName for each
150 element and attribute type:
152 \snippet examples/xmlpatterns/filetree/filetree.cpp 2
154 Note that the constructor does \e{not} pre-build the entire node
155 model. Instead, the node model is built \e{incrementally} as the
156 query engine evaluates a query. To see how the query engine causes
157 the node model to be built incrementally, see \l{Building And
158 Traversing The Node Model}. To see how the query engine accesses the
159 node model, see \l{Accessing the node model}. See also: \l{Node
160 Model Building Strategy}.
162 \section3 Accessing The Node Model
164 Since the node model is stored outside the query engine in the
165 \c{FileTree} class, the query engine knows nothing about it and can
166 only access it by calling functions in the callback interface. When
167 the query engine calls any callback function to access data in the
168 node model, it passes a QXmlNodeModelIndex to identify the node in
169 the node model that it wants to access. Hence all the virtual
170 functions in the callback interface use a QXmlNodeModelIndex to
171 uniquely identify a node in the model.
173 We use the index of a QFileInfo in \c{m_fileInfos} to uniquely
174 identify a node in the node model. To get the QXmlNodeModelIndex for
175 a QFileInfo, the class uses the private function \c{toNodeIndex()}:
177 \target main toNodeIndex
178 \snippet examples/xmlpatterns/filetree/filetree.cpp 1
180 It searches the \c{m_fileInfos} vector for a QFileInfo that matches
181 \c{fileInfo}. If a match is found, its array index is passed to
182 QAbstractXmlNodeModel::createIndex() as the \c data value for the
183 QXmlNodeIndex. If no match is found, the unmatched QFileInfo is
184 appended to the vector, so this function is also doing the actual
185 incremental model building (see \l{Building And Traversing The Node
188 Note that \c{toNodeIndex()} gets a \l{Node_Type} {node type} as the
189 second parameter, which it just passes on to
190 \l{QAbstractXmlNodeModel::createIndex()} {createIndex()} as the
191 \c{additionalData} value. Logically, this second parameter
192 represents a second dimension in the node model, where the first
193 dimension represents the \e element nodes, and the second dimension
194 represents each element's attribute nodes. The meaning is that each
195 QFileInfo in the \c{m_fileInfos} vector can represent an \e{element}
196 node \e{and} one or more \e{attribute} nodes. In particular, the
197 QFileInfo for a file will contain the values for the attribute nodes
198 path, name, suffix, size, and mime type (see
199 \c{FileTree::attributes()}). Since the attributes are contained in
200 the QFileInfo of the file element, there aren't actually any
201 attribute nodes in the node model. Hence, we can use a QVector for
204 A convenience overloading of \l{toNodeIndex of convenience}
205 {toNodeIndex()} is also called in several places, wherever it is
206 known that the QXmlNodeModelIndex being requested is for a directory
207 or a file and not for an attribute. The convenience function takes
208 only the QFileInfo parameter and calls the other \l{main toNodeIndex}
209 {toNodeIndex()}, after obtaining either the Directory or File node
210 type directly from the QFileInfo:
212 \target toNodeIndex of convenience
213 \snippet examples/xmlpatterns/filetree/filetree.cpp 0
215 Note that the auxiliary vector \c{m_names} is accessed using the
216 \l{Node_Type} {node type}, for example:
218 \snippet examples/xmlpatterns/filetree/filetree.cpp 3
220 Most of the virtual functions in the callback interface are as
221 simple as the ones described so far, but the callback function used
222 for traversing (and building) the node model is more complex.
224 \section3 Building And Traversing The Node Model
226 The node model in \c{FileTree} is not fully built before the query
227 engine begins evaluating the query. In fact, when the query engine
228 begins evaluating its first query, the only node in the node model
229 is the one representing the root directory for the selected part of
230 the file system. See \l{The UI Class: MainWindow} below for details
231 about how the UI triggers creation of the model.
233 The query engine builds the node model incrementally each time it
234 calls the \l{next node on axis} {nextFromSimpleAxis()} callback
235 function, as it traverses the node model to evaluate a query. Thus
236 the query engine only builds the region of the node model that it
237 needs for evaluating the query.
239 \l{next node on axis} {nextFromSimpleAxis()} takes an
240 \l{QAbstractXmlNodeModel::SimpleAxis} {axis identifier} and a
241 \l{QXmlNodeModelIndex} {node identifier} as parameters. The
242 \l{QXmlNodeModelIndex} {node identifier} represents the \e{context
243 node} (i.e. the query engine's current location in the model), and
244 the \l{QAbstractXmlNodeModel::SimpleAxis} {axis identifier}
245 represents the direction we want to move from the context node. The
246 function finds the appropriate next node and returns its
249 \l{next node on axis} {nextFromSimpleAxis()} is where most of the
250 work of implementing a custom node model will be required. The
251 obvious way to do it is to use a switch statement with a case for
252 each \l{QAbstractXmlNodeModel::SimpleAxis} {axis}.
254 \target next node on axis
255 \snippet examples/xmlpatterns/filetree/filetree.cpp 4
257 The first thing this function does is call \l{to file info}
258 {toFileInfo()} to get the QFileInfo of the context node. The use of
259 QVector::at() here is guaranteed to succeed because the context node
260 must already be in the node model, and hence must have a QFileInfo
264 \snippet examples/xmlpatterns/filetree/filetree.cpp 6
266 The \l{QAbstractXmlNodeModel::Parent} {Parent} case looks up the
267 context node's parent by constructing a QFileInfo from the context
268 node's \l{QFileInfo::absoluteFilePath()} {path} and passing it to
269 \l{main toNodeIndex} {toNodeIndex()} to find the QFileInfo in
272 The \l{QAbstractXmlNodeModel::FirstChild} {FirstChild} case requires
273 that the context node must be a directory, because a file doesn't
274 have children. If the context node is not a directory, a default
275 constructed QXmlNodeModelIndex is returned. Otherwise,
276 QDir::entryInfoList() constructs a QFileInfoList of the context
277 node's children. The first QFileInfo in the list is passed to
278 \l{toNodeIndex of convenience} {toNodeIndex()} to get its
279 QXmlNodeModelIndex. Note that this will add the child to the node
280 model, if it isn't in the model yet.
282 The \l{QAbstractXmlNodeModel::PreviousSibling} {PreviousSibling} and
283 \l{QAbstractXmlNodeModel::NextSibling} {NextSibling} cases call the
284 \l{nextSibling helper} {nextSibling() helper function}. It takes the
285 QXmlNodeModelIndex of the context node, the QFileInfo of the context
286 node, and an offest of +1 or -1. The context node is a child of some
287 parent, so the function gets the parent and then gets the child list
288 for the parent. The child list is searched to find the QFileInfo of
289 the context node. It must be there. Then the offset is applied, -1
290 for the previous sibling and +1 for the next sibling. The resulting
291 index is passed to \l{toNodeIndex of convenience} {toNodeIndex()} to
292 get its QXmlNodeModelIndex. Note again that this will add the
293 sibling to the node model, if it isn't in the model yet.
295 \target nextSibling helper
296 \snippet examples/xmlpatterns/filetree/filetree.cpp 5
298 \section2 The UI Class: MainWindow
300 The example's UI is a conventional Qt GUI application inheriting
301 QMainWindow and the Ui_MainWindow base class generated by
302 \l{Qt Designer Manual} {Qt Designer}.
304 \snippet examples/xmlpatterns/filetree/mainwindow.h 0
306 It contains the custom node model (\c{m_fileTree}) and an instance
307 of QXmlNodeModelIndex (\c{m_fileNode}) used for holding the node
308 index for the root of the file system subtree. \c{m_fileNode} will
309 be bound to a $variable in the XQuery to be evaluated.
311 Two actions of interest are handled by slot functions: \l{Selecting
312 A Directory To Model} and \l{Selecting And Running An XQuery}.
314 \section3 Selecting A Directory To Model
316 The user selects \c{File->Open Directory} to choose a directory to
317 be loaded into the custom node model. Choosing a directory signals
318 the \c{on_actionOpenDirectory_triggered()} slot:
320 \snippet examples/xmlpatterns/filetree/mainwindow.cpp 1
322 The slot function simply calls the private function
323 \c{loadDirectory()} with the path of the chosen directory:
325 \target the standard code pattern
326 \snippet examples/xmlpatterns/filetree/mainwindow.cpp 4
328 \c{loadDirectory()} demonstrates a standard code pattern for using
329 QtXmlPatterns programatically. First it gets the node model index
330 for the root of the selected directory. Then it creates an instance
331 of QXmlQuery and calls QXmlQuery::bindVariable() to bind the node
332 index to the XQuery variable \c{$fileTree}. It then calls
333 QXmlQuery::setQuery() to load the XQuery text.
335 \note QXmlQuery::bindVariable() must be called \e before calling
336 QXmlQuery::setQuery(), which loads and parses the XQuery text and
337 must have access to the variable binding as the text is parsed.
339 The next lines create an output device for outputting the query
340 result, which is then used to create a QXmlFormatter to format the
341 query result as XML. QXmlQuery::evaluateTo() is called to run the
342 query, and the formatted XML output is displayed in the left panel
345 Finally, the private function \l{Selecting And Running An XQuery}
346 {evaluateResult()} is called to run the currently selected XQuery
347 over the custom node model.
349 \note As described in \l{Building And Traversing The Node Model},
350 the \c FileTree class wants to build the custom node model
351 incrementally as it evaluates the XQuery. But, because the
352 \c{loadDirectory()} function runs the \c{wholeTree.xq} XQuery, it
353 actually builds the entire node model anyway. See \l{Node Model
354 Building Strategy} for a discussion about building your custom node
357 \section3 Selecting And Running An XQuery
359 The user chooses an XQuery from the menu in the combobox on the
360 right. Choosing an XQuery signals the
361 \c{on_queryBox_currentIndexChanged()} slot:
363 \snippet examples/xmlpatterns/filetree/mainwindow.cpp 2
365 The slot function opens and loads the query file and then calls the
366 private function \c{evaluateResult()} to run the query:
368 \snippet examples/xmlpatterns/filetree/mainwindow.cpp 3
370 \c{evaluateResult()} is a second example of the same code pattern
371 shown in \l{the standard code pattern} {loadDirectory()}. In this
372 case, it runs the XQuery currently selected in the combobox instead
373 of \c{qrc:/queries/wholeTree.xq}, and it outputs the query result to
374 the panel on the lower right of the UI window.
376 \section2 Node Model Building Strategy
378 We saw that the \l{The Custom Node Model Class: FileTree} {FileTree}
379 tries to build its custom node model incrementally, but we also saw
380 that the \l{the standard code pattern} {MainWindow::loadDirectory()}
381 function in the UI class immediately subverts the incremental build
382 by running the \c{wholeTree.xq} XQuery, which traverses the entire
383 selected directory, thereby causing the entire node model to be
386 If we want to preserve the incremental build capability of the
387 \c{FileTree} class, we can strip the running of \c{wholeTree.xq} out
388 of \l{the standard code pattern} {MainWindow::loadDirectory()}:
390 \snippet examples/xmlpatterns/filetree/mainwindow.cpp 5
391 \snippet examples/xmlpatterns/filetree/mainwindow.cpp 6
393 Note, however, that \c{FileTree} doesn't have the capability of
394 deleting all or part of the node model. The node model, once built,
395 is only deleted when the \c{FileTree} instance goes out of scope.
397 In this example, each element node in the node model represents a
398 directory or a file in the computer's file system, and each node is
399 represented by an instance of QFileInfo. An instance of QFileInfo is
400 not costly to produce, but you might imagine a node model where
401 building new nodes is very costly. In such cases, the capability to
402 build the node model incrementally is important, because it allows
403 us to only build the region of the model we need for evaluating the
404 query. In other cases, it will be simpler to just build the entire