Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2002-2026 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file GenericSAXHandler.h
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date Sept 2002
19 : ///
20 : // A handler which converts occurring elements and attributes into enums
21 : /****************************************************************************/
22 : #pragma once
23 : #include <config.h>
24 :
25 : #include <string>
26 : #include <map>
27 : #include <stack>
28 : #include <sstream>
29 : #include <vector>
30 : #include <xercesc/sax2/Attributes.hpp>
31 : #include <xercesc/sax2/DefaultHandler.hpp>
32 : #include <utils/common/UtilExceptions.h>
33 : #include <utils/common/StringBijection.h>
34 : #include "SUMOSAXAttributes.h"
35 :
36 :
37 : // ===========================================================================
38 : // class definitions
39 : // ===========================================================================
40 : /**
41 : * @class GenericSAXHandler
42 : * @brief A handler which converts occurring elements and attributes into enums
43 : *
44 : * Normally, when using a standard SAX-handler, we would have to compare
45 : * the incoming XMLCh*-element names with the ones we can parse. The same
46 : * applies to parsing the attributes. This was assumed to be very time consuming,
47 : * that's why we derive our handlers from this class.
48 : *
49 : * The idea behind this second handler layer was avoid repeated conversion
50 : * from strings/whatever to XMLCh* and back again. The usage is quite straight
51 : * forward, the only overhead is the need to define the enums - both elements
52 : * and attributes within "SUMOXMLDefinitions". Still, it maybe helps to avoid typos.
53 : *
54 : * This class implements the SAX-callback and offers a new set of callbacks
55 : * which must be implemented by derived classes. Instead of XMLCh*-values,
56 : * element names are supplied to the derived classes as enums (int).
57 : *
58 : * Also, this class allows to retrieve attributes using enums (int) within
59 : * the implemented "myStartElement" method.
60 : *
61 : * Basically, GenericSAXHandler is not derived within SUMO directly, but via SUMOSAXHandler
62 : * which knows all tags/attributes used by SUMO. It is still kept separate for
63 : * an easier maintainability and later extensions.
64 : */
65 : class GenericSAXHandler : public XERCES_CPP_NAMESPACE::DefaultHandler {
66 :
67 : public:
68 : /**
69 : * @brief Constructor
70 : *
71 : * This constructor gets the lists of known tag and attribute names with
72 : * their enums (sumotags and sumoattrs in most cases). The end of the list
73 : * is signaled by terminatorTag/terminatorAttr respectively.
74 : *
75 : * The attribute names are converted into XMLCh* and stored within an
76 : * internal container. This container is cleared within the destructor.
77 : *
78 : * @param[in] tags The list of known tags
79 : * @param[in] terminatorTag The tag which indicates the end of tags (usually the last entry)
80 : * @param[in] attrs The list of known attributes
81 : * @param[in] terminatorAttr The attr which indicates the end of attrs (usually the last entry)
82 : * @param[in] file The name of the processed file
83 : * @param[in] expectedRoot The expected root element, empty string disables the check
84 : *
85 : * @todo Why are both lists non-const and given as pointers?
86 : */
87 : GenericSAXHandler(
88 : SequentialStringBijection::Entry* tags, int terminatorTag,
89 : SequentialStringBijection::Entry* attrs, int terminatorAttr,
90 : const std::string& file, const std::string& expectedRoot = "");
91 :
92 :
93 : /** @brief Destructor */
94 : virtual ~GenericSAXHandler();
95 :
96 :
97 : /**
98 : * @brief The inherited method called when a new tag opens
99 : *
100 : * The method parses the supplied XMLCh*-qname using the internal name/enum-map
101 : * to obtain the enum representation of the attribute name.
102 : *
103 : * Then, "myStartElement" is called supplying the enumeration value, the
104 : * string-representation of the name and the attributes.
105 : *
106 : * @todo recheck/describe encoding of the string-representation
107 : * @todo do not generate and report the string-representation
108 : */
109 : void startElement(const XMLCh* const uri, const XMLCh* const localname,
110 : const XMLCh* const qname, const XERCES_CPP_NAMESPACE::Attributes& attrs);
111 :
112 :
113 : /**
114 : * @brief The inherited method called when characters occurred
115 : *
116 : * The retrieved characters are converted into a string and appended into a
117 : * private buffer. They are reported as soon as the element ends.
118 : *
119 : * @todo recheck/describe what happens with characters when a new element is opened
120 : * @todo describe characters processing in the class' head
121 : */
122 : void characters(const XMLCh* const chars, const XERCES3_SIZE_t length);
123 :
124 :
125 : /**
126 : * @brief The inherited method called when a tag is being closed
127 : *
128 : * This method calls the user-implemented methods myCharacters with the previously
129 : * collected and converted characters.
130 : *
131 : * Then, myEndElement is called, supplying it the qname converted to its enum-
132 : * and string-representations.
133 : *
134 : * @todo recheck/describe encoding of the string-representation
135 : * @todo do not generate and report the string-representation
136 : */
137 : void endElement(const XMLCh* const uri, const XMLCh* const localname,
138 : const XMLCh* const qname);
139 :
140 :
141 : /**
142 : * @brief Assigning a parent handler which is enabled when the specified tag is closed
143 : */
144 : void registerParent(const int tag, GenericSAXHandler* handler);
145 :
146 :
147 : /**
148 : * @brief Sets the current file name
149 : *
150 : * @param[in] name The name of the currently processed file
151 : *
152 : * @todo Hmmm - this is as unsafe as having a direct access to the variable; recheck
153 : */
154 : void setFileName(const std::string& name);
155 :
156 :
157 : /**
158 : * @brief returns the current file name
159 : *
160 : * @return The name of the currently processed file
161 : */
162 : const std::string& getFileName() const;
163 :
164 :
165 : /// @name SAX ErrorHandler callbacks
166 : //@{
167 :
168 : /**
169 : * @brief Handler for XML-warnings
170 : *
171 : * The message is built using buildErrorMessage and reported
172 : * to the warning-instance of the MsgHandler.
173 : *
174 : * @param[in] exception The occurred exception to process
175 : */
176 : void warning(const XERCES_CPP_NAMESPACE::SAXParseException& exception);
177 :
178 :
179 : /**
180 : * @brief Handler for XML-errors
181 : *
182 : * The message is built using buildErrorMessage and thrown within a ProcessError.
183 : *
184 : * @param[in] exception The occurred exception to process
185 : * @exception ProcessError On any call
186 : */
187 : void error(const XERCES_CPP_NAMESPACE::SAXParseException& exception);
188 :
189 :
190 : /**
191 : * @brief Handler for XML-errors
192 : *
193 : * The message is built using buildErrorMessage and thrown within a ProcessError.
194 : *
195 : * @exception ProcessError On any call
196 : * @param[in] exception The occurred exception to process
197 : */
198 : void fatalError(const XERCES_CPP_NAMESPACE::SAXParseException& exception);
199 : //@}
200 :
201 : void setSection(const int element, const bool seen) {
202 1158 : mySection = element;
203 1158 : mySectionSeen = seen;
204 1158 : mySectionOpen = seen;
205 1158 : mySectionEnded = false;
206 1158 : }
207 :
208 : bool sectionFinished() const {
209 3645302 : return mySectionEnded;
210 : }
211 :
212 : std::pair<int, SUMOSAXAttributes*> retrieveNextSectionStart() {
213 641 : std::pair<int, SUMOSAXAttributes*> ret = myNextSectionStart;
214 641 : myNextSectionStart.first = -1;
215 641 : myNextSectionStart.second = nullptr;
216 : return ret;
217 : }
218 :
219 : void needsCharacterData(const bool value = true) {
220 26 : myCollectCharacterData = value;
221 4 : }
222 :
223 : // Reader needs access to myStartElement, myEndElement
224 : friend class SUMOSAXReader;
225 :
226 : protected:
227 : /**
228 : * @brief Builds an error message
229 : *
230 : * The error message includes the file name and the line/column information
231 : * as supported by the given SAXParseException
232 : *
233 : * @param[in] exception The name of the currently processed file
234 : * @return A string describing the given exception
235 : */
236 : std::string buildErrorMessage(const XERCES_CPP_NAMESPACE::SAXParseException& exception);
237 :
238 : /**
239 : * @brief Callback method for an opening tag to implement by derived classes
240 : *
241 : * Called by "startElement" (see there).
242 : * @param[in] element The element that contains the characters, given as a int
243 : * @param[in] attrs The SAX-attributes, wrapped as SUMOSAXAttributes
244 : * @exceptions ProcessError These method may throw a ProcessError if something fails
245 : */
246 : virtual void myStartElement(int element,
247 : const SUMOSAXAttributes& attrs);
248 :
249 : /**
250 : * @brief Callback method for characters to implement by derived classes
251 : *
252 : * Called by "endElement" (see there).
253 : * @param[in] element The opened element, given as a int
254 : * @param[in] chars The complete embedded character string
255 : * @exceptions ProcessError These method may throw a ProcessError if something fails
256 : */
257 : virtual void myCharacters(int element,
258 : const std::string& chars);
259 :
260 : /** @brief Callback method for a closing tag to implement by derived classes
261 : *
262 : * Called by "endElement" (see there).
263 : * @param[in] element The closed element, given as a int
264 : * @exceptions ProcessError These method may throw a ProcessError if something fails
265 : */
266 : virtual void myEndElement(int element);
267 :
268 : /// @brief signal endElement to the parent handler (special case for MSCalibrator)
269 : void callParentEnd(int element);
270 :
271 : private:
272 : /**
273 : * @brief converts from c++-string into unicode
274 : *
275 : * @todo recheck encoding
276 : * @param[in] name The string to convert
277 : * @return The string converted into a XMLCh-string
278 : */
279 : XMLCh* convert(const std::string& name) const;
280 :
281 : /**
282 : * @brief Converts a tag from its string into its numerical representation
283 : *
284 : * Returns the enum-representation stored for the given tag. If the tag is not
285 : * known, SUMO_TAG_NOTHING is returned.
286 : * @param[in] tag The string to convert
287 : * @return The int-value that represents the string, SUMO_TAG_NOTHING if the named attribute is not known
288 : */
289 : int convertTag(const std::string& tag) const;
290 :
291 : private:
292 : /// @name attributes parsing
293 : //@{
294 :
295 : // the type of the map from ids to their unicode-string representation
296 : typedef std::vector<XMLCh*> AttrMap;
297 :
298 : // the map from ids to their unicode-string representation
299 : AttrMap myPredefinedTags;
300 :
301 : /// the map from ids to their string representation
302 : std::vector<std::string> myPredefinedTagsMML;
303 : //@}
304 :
305 :
306 : /// @name elements parsing
307 : //@{
308 :
309 : // the type of the map that maps tag names to ints
310 : typedef std::map<std::string, int> TagMap;
311 :
312 : // the map of tag names to their internal numerical representation
313 : TagMap myTagMap;
314 : //@}
315 :
316 : /// A list of character strings obtained so far to build the complete characters string at the end
317 : std::vector<std::string> myCharactersVector;
318 :
319 : /// @brief The handler to give control back to
320 : GenericSAXHandler* myParentHandler;
321 :
322 : /// @brief The tag indicating that control should be given back
323 : int myParentIndicator;
324 :
325 : /// @brief The name of the currently parsed file
326 : std::string myFileName;
327 :
328 : /// @brief The root element to expect, empty string disables the check
329 : std::string myExpectedRoot;
330 :
331 : /// @brief whether the reader should collect character data
332 : bool myCollectCharacterData = false;
333 :
334 : /// @brief whether the reader has already seen the root element
335 : bool myRootSeen = false;
336 :
337 : /// @brief The tag indicating the current section to parse
338 : int mySection = -1;
339 :
340 : /// @brief whether the reader has already seen the begin of the section
341 : bool mySectionSeen = false;
342 :
343 : /// @brief whether the reader has already seen the end of the section
344 : bool mySectionEnded = false;
345 :
346 : /// @brief whether an element of the current section is open
347 : bool mySectionOpen = false;
348 :
349 : std::pair<int, SUMOSAXAttributes*> myNextSectionStart;
350 :
351 :
352 : private:
353 : /// @brief invalidated copy constructor
354 : GenericSAXHandler(const GenericSAXHandler& s);
355 :
356 : /// @brief invalidated assignment operator
357 : const GenericSAXHandler& operator=(const GenericSAXHandler& s);
358 :
359 : };
|