Files
simgear/simgear/xml/XMLStaticParser.hxx
2009-07-16 12:09:43 +02:00

127 lines
3.2 KiB
C++

// Template for defining an XML parser based on an element type and
// builder classes
#ifndef SIMGEAR_XMLSTATICPARSER_HXX
#define SIMGEAR_XMLSTATICPARSER_HXX 1
#include <string>
#include <map>
#include <stack>
#include <auto_ptr>
#include <osg/ref_ptr>
#include <osg/Referenced>
#include "easyxml.hxx"
namespace simgear
{
template <typename Element> class XMLStaticParser;
// Parser object. Instantiated for each new element encountered.
template<typename Element>
struct ElementBuilder : public osg::Referenced
{
ElementBuilder(XMLStaticParser<Element>* builder) {}
ElementBuilder(const ElementBuilder& rhs) const {}
virtual ~ElementBuilder() {}
virtual void initialize(const XMLAttributes& attributes) = 0;
virtual void processSubElement(Element* subElement) = 0;
virtual void processData(const char* data, int length) = 0;
virtual Element* finalize() = 0;
// Create element parser from prototype
virtual ElementBuilder* clone() const = 0;
};
template<typename Element>
struct BuilderFactory : public osg::Referenced
{
typedef ElementBuilder<Element> builder_type;
typedef std::map<std::string, osg::ref_ptr<const ElementBuilder> >
BuilderMap;
BuilderMap builderMap;
~virtual BuilderFactory() {}
static void registerBuilder(const std::string& name,
const builder_type* prototype)
{
if (!builderFactory.valid())
builderFactory = new BuilderFactory;
builderFactory->builderMap[name] = prototype;
}
};
template <typename Element>
class XMLStaticParser : public XMLVisitor
{
public:
static osg::ref_ptr<BuilderFactory> builderFactory;
static ElementBuilder* makeBuilder(const std::string& name)
{
BuilderMap::iterator iter = builderFactory->builderMap.find(name);
if (iter == builderFactory->builderMap.end())
return 0;
return iter->second->clone();
}
typedef std::stack<osg::ref_ptr<ElementBuilder> > BuilderStack;
BuilderStack builderStack;
Element* result;
XMLStaticParser() : result(0) {}
virtual ~XMLStaticParser() {}
virtual void startXML()
{
builderStack.push(makeBuilder(""));
}
virtual void endXML()
{
// Stack should have only the initial builder
result = builderStack.top()->finalize();
}
virtual void startElement(const char* name, const XMLAttributes& atts)
{
ElementBuilder* builder = makeBuilder(name);
if (builder) {
builderStack.push(builder);
builder->initialize(atts);
}
}
virtual void endElement(const char* name)
{
Element* result = builderStack.top()->finalize();
builderStack.pop();
if (!builderStack.empty())
builderStack.top()->processSubElement(result);
}
virtual void data(const char* s, int length)
{
builderStack.top()->processData(s, length);
}
struct RegisterBuilderProxy
{
RegisterBuilderProxy(const char* name, ElementBuilder* builder)
{
registerBuilder(name, builder);
}
};
};
template <typename E>
static osg::ref_ptr<BuilderFactory<E> > builderFactory;
}
#endif