📄 saxreaderbase.h
字号:
/*gpsmgr: A program for managing GPS informationCopyright (C) 2003 Austin BinghamThis program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation; either version 2of the License, or (at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.You can reach the author at: abingham@spamcop.net*/#ifndef SAXREADERBASE_H#define SAXREADERBASE_H#include <iosfwd>#include <map>#include <qstring.h>#include <qxml.h>#include <stack>namespace gpsmgr { namespace io { namespace util {//------------------------------------------------------------------------------/** This is intended to act as a base class for any class that wants to parse XML files. Specifically, this class stubs the interfaces for ContentHandler and ErrorHandler from the SAX specification and provides a method for associating parsed string tags with runtime objects. Using this string->object mapping, the parser informs parsing clients of document entities by referencing objects rather than strings. One benefit of this approach is that it's simpler from the point of view of the subclass. Instead of thinking about all the details of parsing an XML file with SAX, the subclass just defines some string-object associations and waits for them to 'trigger'. Another benefit is that it creates a disconnect between the strings in the XML file and the symbolic representation during parsing. That is, normal SAX parsing requires that the parsing client match on strings everywhere that they feel like knowing what's going on. If that string changes (i.e. an entity name changes), the string must be updated everywhere. With this implementation, the string-object association needs to be updated, and that's it. Other good things include: -simplified interface with optional full SAX power -easy modification of overall document structure from client perspective So, how do you use it? First, create a subclass of SAXReaderBase. Semantically, this subclass is responsible for parsing an XML stream and saving/providing access to the information therein. Next, the class needs create the mappings between entity names in the XML file and "phases". A Phase is simply an empty class which represents a unique identifier for the parser. To create the mappings, construct the Phase object, probably as member objects of the subclass. Next, call addTagMap with the entity name and its associated Phase object for every entity you want to watch. There are factilities for associating different Phase objects with the same string depending on the context...this is important in cases where, for instance, a common entity name appears in many places as part of different larger entities. A common example of this is the entity name "NAME" which is used all the time with different meanings. Now, the subclass also needs to make sure it overrides at least one of the following functions: startElementPrePhaseChange startElementPostPhaseChange endElementPrePhaseChange endElementPostPhaseChange More then likely, you will want to subclass startElementPostPhaseChange and startElementPrePhaseChange. The other two are included for completeness, although I've never run into a case where I needed them. In these functions, you have access to the parsed data associated with its Phase objects. Just set up a switch construct which waits for the correct phases to show up and go to town on the data. So, this may not be entirely clear. It might be helpful to look for an example of a class based on SAXReaderBase...that ought to help clue you in a lot better.*/ class SAXReaderBase : public QXmlDefaultHandler { public: /** The empty class used to symbolize the entities in the XML document */ class Phase {}; SAXReaderBase(); virtual ~SAXReaderBase(); /** These do the actual parsing. Call these only after all the mappings have been set up. Returns true if the document parses properly. If it returns false, call errorString to (hopefully) find out why. THROWS: Exception<ParseError> */ bool parse(QXmlInputSource& is); bool parse(QXmlInputSource& is, QXmlErrorHandler& eh); /** * Get the error message associated with a failed parsing run */ QString errorString(); /** IgnoreUnmappedTags just means that the parser will not get upset if it encounters entities in the document with no associated Phase object. This is desirable most of the time, but maybe not all the time. */ void ignoreUnmappedTags(bool ignore = true) { mIgnoreUnmappedTags = ignore; } bool getIgnoreUnmappedTags() { return mIgnoreUnmappedTags; } bool warning(const QXmlParseException& exception); bool error(const QXmlParseException& exception); bool fatalError(const QXmlParseException& exception); protected: /** create an association between the string 'tag' and the phase object 'phase'. This association is applicable when: 1. No applicable context-dependent mapping exists which matches [tag, phase], or 2. There is no current phase (in the default/base phase) */ void addTagMapping(const QString& tag, Phase* phase); /** Create an association between the string 'tag' and the phase object 'phase' which is only applicable if 'tag' is encountered when 'context' is the current phase. */ void addTagMapping(const QString& tag, Phase* phase, Phase* context); /** Convenience function for getting the value of an attribute from and XML tag. It returns true if the value is found and returned, false otherwise. The parameters are as follows: -name: The name of the attribute we are interested in -value: The string into which the value will go -atts: the attributes structure to search -required: indicates whether the attribute is required for this tag. -errmsg: the string to set as the last-error if the attribute is required and not found (false is returned and required==true). */ bool getAttributeValue(const QString& name, QString& value, const QXmlAttributes& atts, bool required, const QString& errmsg); /** Get the current phase */ Phase* getCurrentPhase() const; /** set the last-error message */ void setErrorMessage(const QString& msg); private: Phase* getPhaseForTag(const QString& tag, Phase* context) const; /** called at the end of processing for a single element before the phase is changed. */ virtual bool endElementPrePhaseChange(const QString& namespaceURI, const QString& localName, const QString& rawName, Phase* phase); /** called at the end of processing for a single elements (endElement()) after the phase is changed */ virtual bool endElementPostPhaseChange(const QString& namespaceURI, const QString& localName, const QString& rawName, Phase* phase); bool endElement(const QString & namespaceURI, const QString & localName, const QString & qName); /** called at the beginning of processing for a single element (startElement()) before the phase is changed. */ virtual bool startElementPrePhaseChange(const QString& namespaceURI, const QString& localName, const QString& rawName, const QXmlAttributes& atts, Phase* phase); /** called at the beginning of processing for a single element (startElement()) after the phase is changed. */ virtual bool startElementPostPhaseChange(const QString& namespaceURI, const QString& localName, const QString& rawName, const QXmlAttributes& atts, Phase* phase); bool startElement(const QString & namespaceURI, const QString & localName, const QString & qName, const QXmlAttributes & atts); private: typedef std::map<QString, Phase*> DataToPhaseMap; typedef std::map<Phase*, DataToPhaseMap> PhaseMap; PhaseMap mMainMap; std::stack<Phase*> mCurrPhase; QString mLastError; bool mIgnoreUnmappedTags; };} } } #endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -