127 lines
3.2 KiB
C++
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
|