]> git.mxchange.org Git - simgear.git/blob - simgear/xml/XMLStaticParser.hxx
Initial work on CMake support for SimGear.
[simgear.git] / simgear / xml / XMLStaticParser.hxx
1 // Template for defining an XML parser based on an element type and
2 // builder classes
3
4 #ifndef SIMGEAR_XMLSTATICPARSER_HXX
5 #define SIMGEAR_XMLSTATICPARSER_HXX 1
6
7 #include <string>
8 #include <map>
9 #include <stack>
10 #include <auto_ptr>
11
12 #include <osg/ref_ptr>
13 #include <osg/Referenced>
14
15 #include "easyxml.hxx"
16
17 namespace simgear
18 {
19
20 template <typename Element> class XMLStaticParser;
21
22 // Parser object. Instantiated for each new element encountered.
23
24 template<typename Element>
25 struct ElementBuilder : public osg::Referenced
26 {
27     ElementBuilder(XMLStaticParser<Element>* builder) {}
28     ElementBuilder(const ElementBuilder& rhs) const {}
29     virtual ~ElementBuilder() {}
30     virtual void initialize(const XMLAttributes& attributes) = 0;
31     virtual void processSubElement(Element* subElement) = 0;
32     virtual void processData(const char* data, int length) = 0;
33     virtual Element* finalize() = 0;
34     // Create element parser from prototype
35     virtual ElementBuilder* clone() const = 0;
36 };
37
38 template<typename Element>
39 struct BuilderFactory : public osg::Referenced
40 {
41     typedef ElementBuilder<Element> builder_type;
42     typedef std::map<std::string, osg::ref_ptr<const ElementBuilder> >
43     BuilderMap;
44     BuilderMap builderMap;
45     ~virtual BuilderFactory() {}
46     static void registerBuilder(const std::string& name,
47                                 const builder_type* prototype)
48     {
49         if (!builderFactory.valid())
50             builderFactory = new BuilderFactory;
51         builderFactory->builderMap[name] = prototype;
52     }
53 };
54
55 template <typename Element>
56 class XMLStaticParser : public XMLVisitor
57 {
58 public:
59
60
61     static osg::ref_ptr<BuilderFactory> builderFactory;
62
63
64
65     static ElementBuilder* makeBuilder(const std::string& name)
66     {
67         BuilderMap::iterator iter = builderFactory->builderMap.find(name);
68         if (iter == builderFactory->builderMap.end())
69             return 0;
70         return iter->second->clone();
71     }
72
73     typedef std::stack<osg::ref_ptr<ElementBuilder> > BuilderStack;
74     BuilderStack builderStack;
75
76     Element* result;
77
78     XMLStaticParser() : result(0) {}
79     virtual ~XMLStaticParser() {}
80
81     virtual void startXML()
82     {
83         builderStack.push(makeBuilder(""));
84     }
85
86     virtual void endXML()
87     {
88         // Stack should have only the initial builder
89         result = builderStack.top()->finalize();
90     }
91
92     virtual void startElement(const char* name, const XMLAttributes& atts)
93     {
94         ElementBuilder* builder = makeBuilder(name);
95         if (builder) {
96             builderStack.push(builder);
97             builder->initialize(atts);
98         }
99     }
100
101     virtual void endElement(const char* name)
102     {
103         Element* result = builderStack.top()->finalize();
104         builderStack.pop();
105         if (!builderStack.empty())
106             builderStack.top()->processSubElement(result);
107     }
108
109     virtual void data(const char* s, int length)
110     {
111         builderStack.top()->processData(s, length);
112     }
113
114     struct RegisterBuilderProxy
115     {
116         RegisterBuilderProxy(const char* name, ElementBuilder* builder)
117         {
118             registerBuilder(name, builder);
119         }
120     };
121 };
122
123 template <typename E>
124 static osg::ref_ptr<BuilderFactory<E> > builderFactory;
125 }
126 #endif