[ fromfile: memento.xml id: importing ]
Prerequisites | |
---|---|
The importing routine is more sophisticated than the exporting routine, and it has some interesting features.
It parses XML using the SAX parser.
Depending on the input, it creates objects.
The number and types of objects with their parent-child relationships must be reconstructed from the information in the file.
Example 16.12 shows the class definition for QObjectReader.
Example 16.12. src/libs/dataobjects/qobjectreader.h
[ . . . . ] #include "dobjs_export.h" #include <QString> #include <QStack> #include <QQueue> #include <QXmlDefaultHandler> class AbstractFactory; class DOBJS_EXPORT QObjectReader : public QXmlDefaultHandler { public: explicit QObjectReader (AbstractFactory* factory=0) : m_Factory(factory), m_Current(0) { } explicit QObjectReader (QString filename, AbstractFactory* factory=0); void parse(QString text); void parseFile(QString filename); QObject* getRoot(); ~QObjectReader(); // callback methods from QXmlDefaultHandler bool startElement( const QString& namespaceURI, const QString& name, const QString& qualifiedName, const QXmlAttributes& attributes ); bool endElement( const QString& namespaceURI, const QString& localName, const QString& qualifiedName); bool endDocument(); private: void addCurrentToQueue(); AbstractFactory* m_Factory; QObject* m_Current; QQueue<QObject*> m_ObjectList; QStack<QObject*> m_ParentStack; }; [ . . . . ]
<include src="src/libs/dataobjects/qobjectreader.h" href="src/libs/dataobjects/qobjectreader.h" id="qobjreaderh" mode="cpp"/>
Figure 16.3 shows the relationships between the various classes in the example.
QObjectReader is derived from QXmlDefaultHandler,
which is a plugin for the QXmlSimpleReader.
AbstractFactory is a plugin for QObjectReader.
When you create a QObjectReader, you must supply it with a concrete instance of ObjectFactory
or DataObjectFactory
.
QObjectReader is now completely separate from the specific types of objects that it can create. To use it with your own types, just derive a factory from AbstractFactory for them.
Keep in mind the XML output file in Example 16.10 as you read the code that constructs objects from it, starting with Example 16.13.
Example 16.13. src/libs/dataobjects/qobjectreader.cpp
[ . . . . ] bool QObjectReader::startElement( const QString&, const QString& elementName, const QString&, const QXmlAttributes& atts) { if (elementName == "object") { if (m_Current != 0) m_ParentStack.push(m_Current); QString classname = atts.value("class"); QString instancename = atts.value("name"); m_Current = m_Factory->newObject(classname); m_Current->setObjectName(instancename); if (!m_ParentStack.empty()) { m_Current->setParent(m_ParentStack.top()); } return true; } if (elementName == "property") { QString fieldType = atts.value("type"); QString fieldName = atts.value("name"); QString fieldValue = atts.value("value"); QVariant qv = QVariant(fieldValue); m_Current->setProperty(fieldName.toAscii(), qv); } return true; }
<include src="src/libs/dataobjects/qobjectreader.cpp" href="src/libs/dataobjects/qobjectreader.cpp" mode="cpp" segid="startelement" id="startelementcode"/>
startElement()
is called when the SAX parser encounters the initial tag of an XML element.
The parameters to this function contain all the information needed to create an object.
All other objects encountered between startElement()
and the matching endElement()
are children of m_Current
.
The object is "finished" when we reach endElement()
, as shown in Example 16.14.
Example 16.14. src/libs/dataobjects/qobjectreader.cpp
[ . . . . ] bool QObjectReader::endElement( const QString& , const QString& elementName, const QString& ) { if (elementName == "object") { if (!m_ParentStack.empty()) m_Current = m_ParentStack.pop(); else { addCurrentToQueue(); } } return true; }
<include src="src/libs/dataobjects/qobjectreader.cpp" href="src/libs/dataobjects/qobjectreader.cpp" mode="cpp" segid="endelement" id="endelementcode"/>
QObjectReader uses an Abstract Factory to do the actual object creation.
The callback function, newObject(QString className)
, creates an object that can hold all the properties described in className
.
ObjectFactory creates properly classed objects for the types for which it has a QMetaObject.
For other classes, it creates a regular QObject, but tries to "mimic" the type by setting its className
dynamic property.
To support your own types, you can write a concrete derived factory that maps the correct strings to QMetaObject.
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |