Home · Examples 


QObject XML Model Example

This example shows how to use QtXmlPatterns to query QObject trees using XQuery by modeling the non-XML data structure of a QObject tree to look like XML.

Note: This page is not complete. Watch this space.

Introduction

This example illustrates two important aspects of modeling non-XML data to look like XML. The first is to illustrate that a custom node model class doesn't always have to actually build a node model. Sometimes the node model can be an already existing data structure in memory, like the
QObject tree used in this example. The second important aspect is to explain what is really required to make non-XML data look like XML.

In this example, we want to model a QObject tree to look like XML. That is easy to do because QObject tree structures map simply to XML tree structures. Each QObject node is modeled as an XML element node. But when we try to include the QMetaObject tree in the model, we are adding a second tree to the mode, the QMetaObject tree, which exists behind the QObject tree, thus changing the two dimensional data structure into a three dimensional one.

By adding the QMetaObject tree to the node model and thereby making the model three dimensional, the query engine can no longer traverse it as if it were an XML document, because an XML document is always a two dimensional tree. This means if we want to include the QMetaObject tree in the node model, we have to somehow flatten it into the the same plane as the two dimensional QObject tree. This requires that our node model class must actually build an auxiliary component of the node model. How we do this and how this auxiliary structure is traversed is explained in Including The QMetaObject Tree.

The User Interface

The UI for this example was created using Qt Designer:

Code Walk-Through

The strategy for this example is different from the strategy for the
file system example. In the file system example, the node model class had to actually build a node model, because the non-XML data to be traversed was the computer's file system, a structure stored on disk in a form that the query engine couldn't use. The node model class had to build an analog of the computer's file system in memory, and that in-memory structure was the node model.

For this example, the data structure to be traversed already exists in memory in a usable form. It is the QObject tree of the example application itself. All we need is the pointer to the root of the QObject tree.

Note: When we add the QMetaObject tree to the node model, the node model class will have to build an auxiliary data structure to move the QMetaObject tree into the same plane as the QObject tree. This is explained later in Including The QMetaObject Tree.

The Custom Node Model Class: QObjextXmlModel

The node model class for this example is QObjextXmlModel, which is derived from QSimpleXmlNodeModel. QObjextXmlModel implements the callback interface functions that don't have implementations in QSimpleXmlNodeModel:
    virtual QXmlNodeModelIndex::DocumentOrder compareOrder(const QXmlNodeModelIndex &n1, const QXmlNodeModelIndex &n2) const;
    virtual QXmlName name(const QXmlNodeModelIndex &n) const;
    virtual QUrl documentUri(const QXmlNodeModelIndex &n) const;
    virtual QXmlNodeModelIndex::NodeKind kind(const QXmlNodeModelIndex &n) const;
    virtual QXmlNodeModelIndex root(const QXmlNodeModelIndex &n) const;
    virtual QVariant typedValue(const QXmlNodeModelIndex &n) const;
    virtual QVector<QXmlNodeModelIndex> attributes(const QXmlNodeModelIndex&) const;
    virtual QXmlNodeModelIndex nextFromSimpleAxis(SimpleAxis, const QXmlNodeModelIndex&) const;
The node model class declares three data members:
    const QUrl              m_baseURI;
    QObject *const          m_root;

    const AllMetaObjects    m_allMetaObjects;

m_baseURI is returned by documentUri(). m_root is the pointer to our node model, the already existing QObject tree for the example application itself. m_allMetaObjects will contain the auxiliary component of the node model required for including the QMetaObject tree in the node model. This is discussed in Including The QMetaObject Tree.

Accessing The Node Model

Since the node model is stored outside the query engine in the QObjectXmlModel class, the query engine knows nothing about it and can only access it by calling functions in the callback interface. When the query engine calls any callback function to access data in the node model, it passes a
QXmlNodeModelIndex to identify the node in the node model that it wants to access. Hence all the virtual functions in the callback interface use a QXmlNodeModelIndex to uniquely identify a node in the model.

Since the node model is a QObject tree, we use a pointer to a QObject to uniquely identify a node in the node model. To get the QXmlNodeModelIndex for a QObject, we pass a pointer to the QObject to createIndex(), as in the root() function:

The following code example is written in c++.

QXmlNodeModelIndex QObjectXmlModel::root() const
{
    return createIndex(m_root);
}
An overloading of root() allows finding the root node given the QXmlNodeModelIndex of any QObject in the node model:

The following code example is written in c++.
QObjectXmlModel::QObjectNodeType QObjectXmlModel::toNodeType(const QXmlNodeModelIndex &n)
{
    return QObjectNodeType(n.additionalData() & (15 << 26));
}

Traversing The Node Model

The query engine traverses the
QObject tree by calling back to the node model class's implementation of nextFromSimpleAxis().

The following code example is written in c++.
QXmlNodeModelIndex QObjectXmlModel::nextFromSimpleAxis(SimpleAxis axis, const QXmlNodeModelIndex &n) const
{
    switch (toNodeType(n))
    {
        case IsQObject:
        {
            switch (axis)
            {
                case Parent:
                    return createIndex(asQObject(n)->parent());

                case FirstChild:
                {
                    if (!asQObject(n) || asQObject(n)->children().isEmpty())
                        return QXmlNodeModelIndex();
                    else
                        return createIndex(asQObject(n)->children().first());
                }
                
                case NextSibling:
                    return qObjectSibling(1, n);

                    
                case PreviousSibling:
                {
                    if (asQObject(n) == m_root)
                        return createIndex(qint64(0), MetaObjects);
                    else
                        return qObjectSibling(-1, n);
                }
                    
            }
            Q_ASSERT(false);
        }


        case QObjectClassName:
        case QObjectProperty:
        {
            Q_ASSERT(axis == Parent);
            return createIndex(asQObject(n));
        }


    }

    Q_ASSERT(false);
    return QXmlNodeModelIndex();
}

The UI Class: MainWindow

The example's UI is a conventional Qt GUI application inheriting
QMainWindow and the class generated by Qt Designer:
class MainWindow : public QMainWindow,
                   private Ui_MainWindow
{
    Q_OBJECT

  public:
    MainWindow();

  private slots:
    void on_actionAbout_triggered();
};

Including The QMetaObject Tree


Copyright © 2009 Nokia Corporation and/or its subsidiary(-ies) Trademarks
Qt Jambi 4.5.2_01