[ 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; }; [ . . . . ]
QObjectReader is derived from QXmlDefaultHandler,
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.
Example 16.14. 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; }
startElement()
is called when the SAX parser encounters the initial tag of an XML element.
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.15.
Example 16.15. 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; }
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.
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |