From d796c9dd933ab96ec83b9a634feedd5d32e1ba3f Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Tue, 8 Nov 2011 12:31:36 -0600 Subject: Test conversion to TQt3 from Qt3 8c6fc1f8e35fd264dd01c582ca5e7549b32ab731 --- doc/html/xml-sax-features-walkthrough.html | 379 +++++++++++++++++++++++++++++ 1 file changed, 379 insertions(+) create mode 100644 doc/html/xml-sax-features-walkthrough.html (limited to 'doc/html/xml-sax-features-walkthrough.html') diff --git a/doc/html/xml-sax-features-walkthrough.html b/doc/html/xml-sax-features-walkthrough.html new file mode 100644 index 000000000..a8dd0995d --- /dev/null +++ b/doc/html/xml-sax-features-walkthrough.html @@ -0,0 +1,379 @@ + + + + + +Walkthrough: Using SAX2 features with the TQt XML classes + + + + + + + +
+ +Home + | +All Classes + | +Main Classes + | +Annotated + | +Grouped Classes + | +Functions +

Walkthrough: Using SAX2 features with the TQt XML classes

+ + +

+

This document assumes that you are familiar with namespaces in XML and the concept of a SAX2 +parser. +If features of SAX2 readers are new to you please read +the feature section of the SAX2 document. +

As a novice to the TQt XML classes it is advisable to have a look at the +tiny SAX2 parser walkthrough before +reading on. +

This walkthrough covers two topics: First of all it shows how to +set SAX2 features and secondly how to integrate the TQt XML functionality +into a TQt GUI application. +

The resulting application allows you to compare the output of the reader +depending on how the two features +http://xml.org/sax/features/namespace-prefixes +and 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. +

Setting features

+

+ +

Let's begin with the main program of the application. First the boring +part: we include all the classes we need: +

    #include "structureparser.h"
+    #include <qapplication.h>
+    #include <qfile.h>
+    #include <qxml.h>
+    #include <qlistview.h>
+    #include <qgrid.h>
+    #include <qmainwindow.h>
+    #include <qlabel.h>
+
+

structureparser.h contains the API of +the XML parser that we implement in structureparser.cpp. +

    int main( int argc, char **argv )
+    {
+        TQApplication app( argc, argv );
+
+

As usual we then create a TQt application object and hand command line arguments +over to it. +

        TQFile xmlFile( argc == 2 ? argv[1] : "fnord.xml" );
+
+

If the user runs the program with one filename as +an argument we process this file, otherwise we use the fnord.xml file from +the example directory for demonstration purposes. +

        TQXmlInputSource source( &xmlFile );
+
+

We use xmlFile as the XML Input Source... +

        TQXmlSimpleReader reader;
+
+

... and instantiate a reader object. Later we will manipulate its features +and thus influence how the XML data are read. +

        TQGrid * container = new TQGrid( 3 );
+
+

Now let's think about presenting the output: As described in the +TQt SAX2 documentation +there are three valid combinations of http://xml.org/sax/features/namespace-prefixes +and 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). +

        TQListView * nameSpace = new TQListView( container, "table_namespace" );
+
+

The most natural way of presenting XML elements is in a tree. +Thus we use a listview. Its name nameSpace indicates that this +one will be used to present the combination of http://xml.org/sax/features/namespaces being TRUE and +http://xml.org/sax/features/namespace-prefixes +being FALSE -- the default configuration of a TQXmlSimpleReader. +

Being the first grid entry the nameSpace listview will +appear in the upper left corner of the virtual grid. +

        StructureParser * handler = new StructureParser( nameSpace );
+
+

Then we create a handler that deals with the XML data read by the reader. +As the provided handler class TQXmlDefaultHandler simply does nothing +with the data from the reader, +we can't use it right away. Instead we have to subclass our +own StructureParser from it. +

        reader.setContentHandler( handler );
+
+

The 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. +

        reader.parse( source );
+
+

Finally we parse the document with the reader's default feature settings. +

        TQListView * namespacePrefix = new TQListView( container,
+                                                     "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 TQListView, namespacePrefix. As it is the second +member of the container grid it will appear in the middle of +the upper grid row. +

        handler->setListView( namespacePrefix );
+
+

Then we ask the handler to present the data in the namespacePrefix +listview. +

        reader.setFeature( "http://xml.org/sax/features/namespace-prefixes",
+                           TRUE );
+
+

Now we modify the behaviour of the reader and change +http://xml.org/sax/features/namespace-prefixes from the default FALSE +to TRUE. The http://xml.org/sax/features/namespaces feature has +still its default setting TRUE. +

        source.reset();
+
+

We have to reset the input source to make the new parsing start from the +beginning of the document again. +

        reader.parse( source );
+
+

Finally we parse the XML file a second time with the changed reader +settings (TRUE/TRUE). +

        TQListView * prefix = new TQListView( container, "table_prefix");
+        handler->setListView( prefix );
+        reader.setFeature( "http://xml.org/sax/features/namespaces", FALSE );
+        source.reset();
+        reader.parse( source );
+
+

Next we prepare and use the upper right listview to show the reader results +with the feature setting http://xml.org/sax/features/namespaces +FALSE and http://xml.org/sax/features/namespace-prefixes TRUE. +

        // namespace label
+        (void) new TQLabel(
+                 "Default:\n"
+                 "http://xml.org/sax/features/namespaces: TRUE\n"
+                 "http://xml.org/sax/features/namespace-prefixes: FALSE\n",
+                 container );
+
+        // namespace prefix label
+        (void) new TQLabel(
+                 "\n"
+                 "http://xml.org/sax/features/namespaces: TRUE\n"
+                 "http://xml.org/sax/features/namespace-prefixes: TRUE\n",
+                 container );
+
+        // prefix label
+        (void) new TQLabel(
+                 "\n"
+                 "http://xml.org/sax/features/namespaces: FALSE\n"
+                 "http://xml.org/sax/features/namespace-prefixes: TRUE\n",
+                 container );
+
+

The second row of the container grid is filled with three labels +denoting the reader settings that belong to the above listview. +

        app.setMainWidget( container );
+        container->show();
+        return app.exec();
+    }
+
+

Same procedure as with every TQt GUI program: the grid serves as the +main widget of our application and is shown. After that we enter +the GUI's event loop. +

The handler API

+

Let's have a brief look at the API of our handler class +StructureParser: +

+ +

    #include <qxml.h>
+    #include <qptrstack.h>
+
+    class TQListView;
+    class TQListViewItem;
+    class TQString;
+
+

    class StructureParser: public TQXmlDefaultHandler
+    {
+
+

We derive it from the TQXmlDefaultHandler class that +implements a handler that simply does nothing. +

    public:
+        StructureParser( TQListView * );
+
+

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 TQListView as an argument, +

        bool startElement( const TQString&, const TQString&, const TQString& ,
+                           const TQXmlAttributes& );
+
+

the function to execute at the occurrence of element start tags +(inherited from TQXmlContentHandler), and +

        bool endElement( const TQString&, const TQString&, const TQString& );
+
+

the code to run when an end tag occurs. +

All we have to implement so far is content handling. +

        void setListView( TQListView * );
+
+

In addition we have a function that selects a listview +for the output. +

    private:
+        TQPtrStack<TQListViewItem> stack;
+
+

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 TQListItems. An element will be added to the stack when +its start tag appears and removed +as soon as its end tag is parsed. +

        TQListView * table;
+    };
+
+

Apart from this we define a member variable that contains +the currently used listview. +

The handler itself

+

Now that we defined the API we have to implement the +relevant functions. +

+ +

    #include "structureparser.h"
+
+    #include <qstring.h>
+    #include <qlistview.h>
+
+

    StructureParser::StructureParser( TQListView * t )
+                    : TQXmlDefaultHandler()
+    {
+
+

First we have the constructor that takes a listview pointer as +its argument. +

        setListView( t );
+    }
+
+

All we have to do here is to prepare the argument TQListView +before usage. This we do with the setListView() function. +

+

    void StructureParser::setListView( TQListView * t )
+    {
+        table = t;
+
+

First we store the argument away. +

        table->setSorting( -1 );
+
+

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. +

        table->addColumn( "Qualified name" );
+        table->addColumn( "Namespace" );
+    }
+
+

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. +

    bool StructureParser::startElement( const TQString& namespaceURI,
+                                        const TQString& ,
+                                        const TQString& qName,
+                                        const TQXmlAttributes& attributes)
+    {
+
+

When we come across the start tag of an element the handler does +the real work. Although 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 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. +

        TQListViewItem * element;
+
+

Whenever an element occurs we want to show it in the listview. +Therefore we define a TQListViewItem variable. +

        if ( ! stack.isEmpty() ){
+            TQListViewItem *lastChild = stack.top()->firstChild();
+
+

As long as the element stack isn't empty the current element +is a child of the topmost (last unclosed) element on the stack. Thus we +create a new TQListViewItem as a child of TQPtrStack::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 TQListViewItem 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 TQPtrStack::stack.top() element and insert it after this +element. +

In a valid XML document this applies to all elements except +the document root. +

            if ( lastChild ) {
+                while ( lastChild->nextSibling() )
+                    lastChild = lastChild->nextSibling();
+            }
+            element = new TQListViewItem( stack.top(), lastChild, qName, namespaceURI );
+        } else {
+            element = new TQListViewItem( table, qName, namespaceURI );
+        }
+
+

The root element we have to handle separately because it is +the first element to go onto the TQListViewItem stack. +Its listview item is therefore a direct child of the +table listview itself. +

        stack.push( element );
+
+

Now we put the element's listview item on top of the stack. +

        element->setOpen( TRUE );
+
+

By default a TQListView presents all of its nodes closed. +The user may then click on the + 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. +

        if ( attributes.length() > 0 ) {
+
+

What do we do if an element has attributes? +

            for ( int i = 0 ; i < attributes.length(); i++ ) {
+                new TQListViewItem( element, attributes.qName(i), attributes.uri(i) );
+            }
+        }
+
+

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 attribute is a child of +the current element. +

        return TRUE;
+    }
+
+

To prevent the reader from throwing an error we have to +return TRUE when we successfully dealt with an +element's start tag. +

    bool StructureParser::endElement( const TQString&, const TQString&,
+                                      const TQString& )
+    {
+        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. +

        return TRUE;
+    }
+
+

And so we're done. +

See also Step-by-step Examples. + + +


+ +
Copyright © 2007 +TrolltechTrademarks +
TQt 3.3.8
+
+ -- cgit v1.2.1