|
|
|
/****************************************************************************
|
|
|
|
**
|
|
|
|
** Documentation on the sax interface of the xml module
|
|
|
|
**
|
|
|
|
** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
|
|
|
|
**
|
|
|
|
** This file is part of the Qt GUI Toolkit.
|
|
|
|
**
|
|
|
|
** This file may be used under the terms of the GNU General
|
|
|
|
** Public License versions 2.0 or 3.0 as published by the Free
|
|
|
|
** Software Foundation and appearing in the files LICENSE.GPL2
|
|
|
|
** and LICENSE.GPL3 included in the packaging of this file.
|
|
|
|
** Alternatively you may (at your option) use any later version
|
|
|
|
** of the GNU General Public License if such license has been
|
|
|
|
** publicly approved by Trolltech ASA (or its successors, if any)
|
|
|
|
** and the KDE Free Qt Foundation.
|
|
|
|
**
|
|
|
|
** Please review the following information to ensure GNU General
|
|
|
|
** Public Licensing requirements will be met:
|
|
|
|
** http://trolltech.com/products/qt/licenses/licensing/opensource/.
|
|
|
|
** If you are unsure which license is appropriate for your use, please
|
|
|
|
** review the following information:
|
|
|
|
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
|
|
|
|
** or contact the sales department at sales@trolltech.com.
|
|
|
|
**
|
|
|
|
** This file may be used under the terms of the Q Public License as
|
|
|
|
** defined by Trolltech ASA and appearing in the file LICENSE.QPL
|
|
|
|
** included in the packaging of this file. Licensees holding valid Qt
|
|
|
|
** Commercial licenses may use this file in accordance with the Qt
|
|
|
|
** Commercial License Agreement provided with the Software.
|
|
|
|
**
|
|
|
|
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
|
|
|
|
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
|
|
|
|
** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
|
|
|
|
** herein.
|
|
|
|
**
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
/*! \page xml-sax-features-walkthrough.html
|
|
|
|
|
|
|
|
\ingroup step-by-step-examples
|
|
|
|
|
|
|
|
\title Walkthrough: Using SAX2 features with the Qt XML classes
|
|
|
|
|
|
|
|
This document assumes that you are familiar with \link xml.html#namespaces
|
|
|
|
namespaces \endlink in XML and the concept of a \link xml.html#sax2 SAX2
|
|
|
|
parser \endlink.
|
|
|
|
If features of SAX2 readers are new to you please read
|
|
|
|
\link xml.html#sax2Features the feature section \endlink of the SAX2 document.
|
|
|
|
|
|
|
|
As a novice to the Qt XML classes it is advisable to have a look at the
|
|
|
|
\link xml-sax-walkthrough.html tiny SAX2 parser walkthrough \endlink before
|
|
|
|
reading on.
|
|
|
|
|
|
|
|
This walkthrough covers two topics: First of all it shows how to
|
|
|
|
set SAX2 features and secondly how to integrate the Qt XML functionality
|
|
|
|
into a Qt GUI application.
|
|
|
|
|
|
|
|
The resulting application allows you to compare the output of the reader
|
|
|
|
depending on how the two features
|
|
|
|
\e http://xml.org/sax/features/namespace-prefixes
|
|
|
|
and \e http://xml.org/sax/features/namespaces are set.
|
|
|
|
To do this it shows tree views of the read XML file
|
|
|
|
listing the qualified names of elements and attributes and the respective
|
|
|
|
namespace URIs.
|
|
|
|
|
|
|
|
<h3>Setting features</h3>
|
|
|
|
|
|
|
|
\quotefile xml/tagreader-with-features/tagreader.cpp
|
|
|
|
|
|
|
|
Let's begin with the main program of the application. First the boring
|
|
|
|
part: we include all the classes we need:
|
|
|
|
|
|
|
|
\skipto include
|
|
|
|
\printline structureparser.h
|
|
|
|
\printuntil ntqlabel.h
|
|
|
|
|
|
|
|
\link #structureparser.h structureparser.h \endlink contains the API of
|
|
|
|
the XML parser that we implement in \link #structureparser.cpp
|
|
|
|
structureparser.cpp. \endlink
|
|
|
|
|
|
|
|
\printline main
|
|
|
|
\printuntil QApplication
|
|
|
|
|
|
|
|
As usual we then create a Qt application object and hand command line arguments
|
|
|
|
over to it.
|
|
|
|
|
|
|
|
\printline xmlFile(
|
|
|
|
|
|
|
|
If the user runs the program with one filename as
|
|
|
|
an argument we process this file, otherwise we use the \e fnord.xml file from
|
|
|
|
the example directory for demonstration purposes.
|
|
|
|
|
|
|
|
\printline QXmlInputSource
|
|
|
|
|
|
|
|
We use \e xmlFile as the XML Input Source...
|
|
|
|
|
|
|
|
\printline QXmlSimpleReader
|
|
|
|
|
|
|
|
... and instantiate a \e reader object. Later we will manipulate its features
|
|
|
|
and thus influence how the XML data are read.
|
|
|
|
|
|
|
|
\printline container
|
|
|
|
|
|
|
|
Now let's think about presenting the output: As described in the
|
|
|
|
\link xml.html#sax2Features Qt SAX2 documentation \endlink
|
|
|
|
there are three valid combinations of \e
|
|
|
|
http://xml.org/sax/features/namespace-prefixes
|
|
|
|
and \e http://xml.org/sax/features/namespaces: TRUE/TRUE, TRUE/FALSE and
|
|
|
|
FALSE/TRUE. To show the relevant output side by side of each other
|
|
|
|
and mark them with three labels makes up for a grid layout consisting
|
|
|
|
of three columns (and thus two lines).
|
|
|
|
|
|
|
|
\printline nameSpace
|
|
|
|
|
|
|
|
The most natural way of presenting XML elements is in a tree.
|
|
|
|
Thus we use a listview. Its name \e nameSpace indicates that this
|
|
|
|
one will be used to present the combination of \e
|
|
|
|
http://xml.org/sax/features/namespaces being TRUE and
|
|
|
|
\e http://xml.org/sax/features/namespace-prefixes
|
|
|
|
being FALSE -- the default configuration of a \l QXmlSimpleReader.
|
|
|
|
|
|
|
|
Being the first grid entry the \e nameSpace listview will
|
|
|
|
appear in the upper left corner of the virtual grid.
|
|
|
|
|
|
|
|
\printline handler
|
|
|
|
|
|
|
|
Then we create a handler that deals with the XML data read by the reader.
|
|
|
|
As the provided handler class \l QXmlDefaultHandler simply does nothing
|
|
|
|
with the data from the reader,
|
|
|
|
we can't use it right away. Instead we have to subclass our
|
|
|
|
own \link #structureparser.cpp StructureParser \endlink from it.
|
|
|
|
|
|
|
|
\printline setContentHandler
|
|
|
|
|
|
|
|
The \e handler serves as content handler for the reader. Note that
|
|
|
|
for simplicity reasons we don't register e.g. an error handler. Thus
|
|
|
|
our program will not complain about for example missing closing tags
|
|
|
|
in the parsed XML document.
|
|
|
|
|
|
|
|
\printline parse
|
|
|
|
|
|
|
|
Finally we parse the document with the reader's default feature settings.
|
|
|
|
|
|
|
|
\printline namespacePrefix
|
|
|
|
\printline table_namespace_prefix
|
|
|
|
|
|
|
|
Now we prepare for the parsing of the same XML input source with
|
|
|
|
different reader settings. The output will be presented in
|
|
|
|
a second \l QListView, \e namespacePrefix. As it is the second
|
|
|
|
member of the \e container grid it will appear in the middle of
|
|
|
|
the upper grid row.
|
|
|
|
|
|
|
|
\printline setListView
|
|
|
|
|
|
|
|
Then we ask the \e handler to present the data in the \e namespacePrefix
|
|
|
|
listview.
|
|
|
|
|
|
|
|
\printline namespace-prefixes
|
|
|
|
\printline TRUE
|
|
|
|
|
|
|
|
Now we modify the behaviour of the \e reader and change
|
|
|
|
\e http://xml.org/sax/features/namespace-prefixes from the default FALSE
|
|
|
|
to TRUE. The \e http://xml.org/sax/features/namespaces feature has
|
|
|
|
still its default setting TRUE.
|
|
|
|
|
|
|
|
\printline reset
|
|
|
|
|
|
|
|
We have to reset the input source to make the new parsing start from the
|
|
|
|
beginning of the document again.
|
|
|
|
|
|
|
|
\printline parse
|
|
|
|
|
|
|
|
Finally we parse the XML file a second time with the changed reader
|
|
|
|
settings (TRUE/TRUE).
|
|
|
|
|
|
|
|
\printline prefix
|
|
|
|
\printuntil parse
|
|
|
|
|
|
|
|
Next we prepare and use the upper right listview to show the reader results
|
|
|
|
with the feature setting \e http://xml.org/sax/features/namespaces
|
|
|
|
FALSE and \e http://xml.org/sax/features/namespace-prefixes TRUE.
|
|
|
|
|
|
|
|
\printline namespace label
|
|
|
|
\printuntil namespace prefix label
|
|
|
|
\printuntil prefix label
|
|
|
|
\printuntil container
|
|
|
|
|
|
|
|
The second row of the \e container grid is filled with three labels
|
|
|
|
denoting the reader settings that belong to the above listview.
|
|
|
|
|
|
|
|
\printline app.setMainWidget
|
|
|
|
\printuntil }
|
|
|
|
|
|
|
|
Same procedure as with every Qt GUI program: the grid serves as the
|
|
|
|
main widget of our application and is shown. After that we enter
|
|
|
|
the GUI's event loop.
|
|
|
|
|
|
|
|
|
|
|
|
<h3><a name="structureparser.h">The handler API</a></h3>
|
|
|
|
|
|
|
|
Let's have a brief look at the API of our handler class
|
|
|
|
\e StructureParser:
|
|
|
|
|
|
|
|
\quotefile xml/tagreader-with-features/structureparser.h
|
|
|
|
\skipto include
|
|
|
|
\printuntil QString
|
|
|
|
|
|
|
|
\printline StructureParser
|
|
|
|
\printuntil {
|
|
|
|
|
|
|
|
We derive it from the \l QXmlDefaultHandler class that
|
|
|
|
implements a handler that simply does nothing.
|
|
|
|
|
|
|
|
\printuntil QListView
|
|
|
|
|
|
|
|
This makes it easy for us to implement only the functionality
|
|
|
|
we in fact need. In our case this is the constructor that
|
|
|
|
takes a \l QListView as an argument,
|
|
|
|
|
|
|
|
\printline startElement
|
|
|
|
\printuntil QXmlAttributes
|
|
|
|
|
|
|
|
the function to execute at the occurrence of element start tags
|
|
|
|
(inherited from \l QXmlContentHandler), and
|
|
|
|
|
|
|
|
\printline endElement
|
|
|
|
|
|
|
|
the code to run when an end tag occurs.
|
|
|
|
|
|
|
|
All we have to implement so far is content handling.
|
|
|
|
|
|
|
|
\printline setListView
|
|
|
|
|
|
|
|
In addition we have a function that selects a listview
|
|
|
|
for the output.
|
|
|
|
|
|
|
|
\printuntil QPtrStack
|
|
|
|
|
|
|
|
Keep in mind that we write a SAX2 parser that doesn't
|
|
|
|
have an object model to keep all elements and attributes
|
|
|
|
in memory. To display the elements and attributes in a tree like
|
|
|
|
structure we must however keep track of all elements
|
|
|
|
that haven't been closed yet.
|
|
|
|
|
|
|
|
To do this we use a LIFO stack
|
|
|
|
of QListItems. An element will be added to the stack when
|
|
|
|
its start tag appears and removed
|
|
|
|
as soon as its end tag is parsed.
|
|
|
|
|
|
|
|
\printline table
|
|
|
|
\printline };
|
|
|
|
|
|
|
|
Apart from this we define a member variable that contains
|
|
|
|
the currently used listview.
|
|
|
|
|
|
|
|
<h3><a name="structureparser.cpp">The handler itself</a></h3>
|
|
|
|
|
|
|
|
Now that we defined the API we have to implement the
|
|
|
|
relevant functions.
|
|
|
|
|
|
|
|
\quotefile xml/tagreader-with-features/structureparser.cpp
|
|
|
|
\skipto include
|
|
|
|
\printuntil ntqlistview.h
|
|
|
|
|
|
|
|
\printline StructureParser
|
|
|
|
\printuntil {
|
|
|
|
|
|
|
|
First we have the constructor that takes a listview pointer as
|
|
|
|
its argument.
|
|
|
|
|
|
|
|
\printline setListView
|
|
|
|
\printuntil }
|
|
|
|
|
|
|
|
All we have to do here is to prepare the argument \l QListView
|
|
|
|
before usage. This we do with the \link #setListView()
|
|
|
|
setListView() \endlink function.
|
|
|
|
|
|
|
|
<a name="setListView()"></a>
|
|
|
|
\printline setListView
|
|
|
|
\printuntil table
|
|
|
|
|
|
|
|
First we store the argument away.
|
|
|
|
|
|
|
|
\printline setSorting
|
|
|
|
|
|
|
|
We want the elements to be listed as they appear in the
|
|
|
|
document -- and not for example sorted alphabetically. That's
|
|
|
|
why we switch off sorting at all.
|
|
|
|
|
|
|
|
\printline addColumn
|
|
|
|
\printuntil }
|
|
|
|
|
|
|
|
The listview now consists of two columns: one for the
|
|
|
|
element's or attribute's qualified names and one for
|
|
|
|
their namespace URIs. Columns are added from left to right
|
|
|
|
and with the title as an argument.
|
|
|
|
|
|
|
|
Now let's deal with XML content handling.
|
|
|
|
|
|
|
|
\printline startElement
|
|
|
|
\printuntil {
|
|
|
|
|
|
|
|
When we come across the start tag of an element the handler does
|
|
|
|
the real work. Although \e startElement is called with four
|
|
|
|
arguments we keep track of only three: the namespace URI
|
|
|
|
of the element, its qualified name and its attributes.
|
|
|
|
If an element has no namespace assigned or if the feature
|
|
|
|
settings of the reader don't provide the handler with
|
|
|
|
namespace URIs at all \e namespaceURI contains an empty
|
|
|
|
string.
|
|
|
|
|
|
|
|
Note that we don't assign a variable to the second argument --
|
|
|
|
we're simply not interested in the local name of the element.
|
|
|
|
|
|
|
|
\printline element
|
|
|
|
|
|
|
|
Whenever an element occurs we want to show it in the listview.
|
|
|
|
Therefore we define a \l QListViewItem variable.
|
|
|
|
|
|
|
|
\printline stack.isEmpty()
|
|
|
|
\printline stack.top()
|
|
|
|
|
|
|
|
As long as the element \e stack isn't empty the current element
|
|
|
|
is a child of the topmost (last unclosed) element on the stack. Thus we
|
|
|
|
create a new \l QListViewItem as a child of QPtrStack::stack.top() with
|
|
|
|
the new element's qualified name in the first column and the according
|
|
|
|
namespace URI (or nothing) in the second one.
|
|
|
|
|
|
|
|
The QListViewItem is usally inserted as the first child. This means that we
|
|
|
|
would get the elements in reverse order. So we first search for the last
|
|
|
|
child of the QPtrStack::stack.top() element and insert it after this
|
|
|
|
element.
|
|
|
|
|
|
|
|
In a valid XML document this applies to all elements except
|
|
|
|
the document root.
|
|
|
|
|
|
|
|
\printuntil table
|
|
|
|
\printline }
|
|
|
|
|
|
|
|
The root element we have to handle separately because it is
|
|
|
|
the first element to go onto the \l QListViewItem stack.
|
|
|
|
Its listview item is therefore a direct child of the
|
|
|
|
\e table listview itself.
|
|
|
|
|
|
|
|
\printline stack.push
|
|
|
|
|
|
|
|
Now we put the element's listview item on top of the stack.
|
|
|
|
|
|
|
|
\printline setOpen
|
|
|
|
|
|
|
|
By default a QListView presents all of its nodes closed.
|
|
|
|
The user may then click on the \e + icon to see the child
|
|
|
|
entries.
|
|
|
|
|
|
|
|
We however want to see the entire element tree
|
|
|
|
at once when we run the program.
|
|
|
|
Therefore we open each listview item manually.
|
|
|
|
|
|
|
|
\printline attributes.length
|
|
|
|
|
|
|
|
What do we do if an element has attributes?
|
|
|
|
|
|
|
|
\printuntil }
|
|
|
|
\printline }
|
|
|
|
|
|
|
|
For each of them we create a new listview item to present the attribute's
|
|
|
|
qualified name and the relevant namespace URI (or nothing).
|
|
|
|
Obviously \e attribute is a child of
|
|
|
|
the current \e element.
|
|
|
|
|
|
|
|
|
|
|
|
\printline TRUE
|
|
|
|
\printline }
|
|
|
|
|
|
|
|
To prevent the reader from throwing an error we have to
|
|
|
|
return TRUE when we successfully dealt with an
|
|
|
|
element's start tag.
|
|
|
|
|
|
|
|
\printline endElement
|
|
|
|
\printuntil stack.pop
|
|
|
|
|
|
|
|
Whenever we come across an element's closing tag we
|
|
|
|
have to remove its listview item from the stack as
|
|
|
|
it can't have children any longer.
|
|
|
|
|
|
|
|
\printuntil }
|
|
|
|
|
|
|
|
And so we're done.
|
|
|
|
|
|
|
|
*/
|