/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2002-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file GenericSAXHandler.h14/// @author Daniel Krajzewicz15/// @author Jakob Erdmann16/// @author Michael Behrisch17/// @date Sept 200218///19// A handler which converts occurring elements and attributes into enums20/****************************************************************************/21#pragma once22#include <config.h>2324#include <string>25#include <map>26#include <stack>27#include <sstream>28#include <vector>29#include <xercesc/sax2/Attributes.hpp>30#include <xercesc/sax2/DefaultHandler.hpp>31#include <utils/common/UtilExceptions.h>32#include <utils/common/StringBijection.h>33#include "SUMOSAXAttributes.h"343536// ===========================================================================37// class definitions38// ===========================================================================39/**40* @class GenericSAXHandler41* @brief A handler which converts occurring elements and attributes into enums42*43* Normally, when using a standard SAX-handler, we would have to compare44* the incoming XMLCh*-element names with the ones we can parse. The same45* applies to parsing the attributes. This was assumed to be very time consuming,46* that's why we derive our handlers from this class.47*48* The idea behind this second handler layer was avoid repeated conversion49* from strings/whatever to XMLCh* and back again. The usage is quite straight50* forward, the only overhead is the need to define the enums - both elements51* and attributes within "SUMOXMLDefinitions". Still, it maybe helps to avoid typos.52*53* This class implements the SAX-callback and offers a new set of callbacks54* which must be implemented by derived classes. Instead of XMLCh*-values,55* element names are supplied to the derived classes as enums (int).56*57* Also, this class allows to retrieve attributes using enums (int) within58* the implemented "myStartElement" method.59*60* Basically, GenericSAXHandler is not derived within SUMO directly, but via SUMOSAXHandler61* which knows all tags/attributes used by SUMO. It is still kept separate for62* an easier maintainability and later extensions.63*/64class GenericSAXHandler : public XERCES_CPP_NAMESPACE::DefaultHandler {6566public:67/**68* @brief Constructor69*70* This constructor gets the lists of known tag and attribute names with71* their enums (sumotags and sumoattrs in most cases). The end of the list72* is signaled by terminatorTag/terminatorAttr respectively.73*74* The attribute names are converted into XMLCh* and stored within an75* internal container. This container is cleared within the destructor.76*77* @param[in] tags The list of known tags78* @param[in] terminatorTag The tag which indicates the end of tags (usually the last entry)79* @param[in] attrs The list of known attributes80* @param[in] terminatorAttr The attr which indicates the end of attrs (usually the last entry)81* @param[in] file The name of the processed file82* @param[in] expectedRoot The expected root element, empty string disables the check83*84* @todo Why are both lists non-const and given as pointers?85*/86GenericSAXHandler(87SequentialStringBijection::Entry* tags, int terminatorTag,88SequentialStringBijection::Entry* attrs, int terminatorAttr,89const std::string& file, const std::string& expectedRoot = "");909192/** @brief Destructor */93virtual ~GenericSAXHandler();949596/**97* @brief The inherited method called when a new tag opens98*99* The method parses the supplied XMLCh*-qname using the internal name/enum-map100* to obtain the enum representation of the attribute name.101*102* Then, "myStartElement" is called supplying the enumeration value, the103* string-representation of the name and the attributes.104*105* @todo recheck/describe encoding of the string-representation106* @todo do not generate and report the string-representation107*/108void startElement(const XMLCh* const uri, const XMLCh* const localname,109const XMLCh* const qname, const XERCES_CPP_NAMESPACE::Attributes& attrs);110111112/**113* @brief The inherited method called when characters occurred114*115* The retrieved characters are converted into a string and appended into a116* private buffer. They are reported as soon as the element ends.117*118* @todo recheck/describe what happens with characters when a new element is opened119* @todo describe characters processing in the class' head120*/121void characters(const XMLCh* const chars, const XERCES3_SIZE_t length);122123124/**125* @brief The inherited method called when a tag is being closed126*127* This method calls the user-implemented methods myCharacters with the previously128* collected and converted characters.129*130* Then, myEndElement is called, supplying it the qname converted to its enum-131* and string-representations.132*133* @todo recheck/describe encoding of the string-representation134* @todo do not generate and report the string-representation135*/136void endElement(const XMLCh* const uri, const XMLCh* const localname,137const XMLCh* const qname);138139140/**141* @brief Assigning a parent handler which is enabled when the specified tag is closed142*/143void registerParent(const int tag, GenericSAXHandler* handler);144145146/**147* @brief Sets the current file name148*149* @param[in] name The name of the currently processed file150*151* @todo Hmmm - this is as unsafe as having a direct access to the variable; recheck152*/153void setFileName(const std::string& name);154155156/**157* @brief returns the current file name158*159* @return The name of the currently processed file160*/161const std::string& getFileName() const;162163164/// @name SAX ErrorHandler callbacks165//@{166167/**168* @brief Handler for XML-warnings169*170* The message is built using buildErrorMessage and reported171* to the warning-instance of the MsgHandler.172*173* @param[in] exception The occurred exception to process174*/175void warning(const XERCES_CPP_NAMESPACE::SAXParseException& exception);176177178/**179* @brief Handler for XML-errors180*181* The message is built using buildErrorMessage and thrown within a ProcessError.182*183* @param[in] exception The occurred exception to process184* @exception ProcessError On any call185*/186void error(const XERCES_CPP_NAMESPACE::SAXParseException& exception);187188189/**190* @brief Handler for XML-errors191*192* The message is built using buildErrorMessage and thrown within a ProcessError.193*194* @exception ProcessError On any call195* @param[in] exception The occurred exception to process196*/197void fatalError(const XERCES_CPP_NAMESPACE::SAXParseException& exception);198//@}199200201void setSection(const int element, const bool seen) {202mySection = element;203mySectionSeen = seen;204mySectionOpen = seen;205mySectionEnded = false;206}207208bool sectionFinished() const {209return mySectionEnded;210}211212std::pair<int, SUMOSAXAttributes*> retrieveNextSectionStart() {213std::pair<int, SUMOSAXAttributes*> ret = myNextSectionStart;214myNextSectionStart.first = -1;215myNextSectionStart.second = nullptr;216return ret;217}218219void needsCharacterData(const bool value = true) {220myCollectCharacterData = value;221}222223// Reader needs access to myStartElement, myEndElement224friend class SUMOSAXReader;225226227protected:228/**229* @brief Builds an error message230*231* The error message includes the file name and the line/column information232* as supported by the given SAXParseException233*234* @param[in] exception The name of the currently processed file235* @return A string describing the given exception236*/237std::string buildErrorMessage(const XERCES_CPP_NAMESPACE::SAXParseException& exception);238239240/**241* @brief Callback method for an opening tag to implement by derived classes242*243* Called by "startElement" (see there).244* @param[in] element The element that contains the characters, given as a int245* @param[in] attrs The SAX-attributes, wrapped as SUMOSAXAttributes246* @exceptions ProcessError These method may throw a ProcessError if something fails247*/248virtual void myStartElement(int element,249const SUMOSAXAttributes& attrs);250251252/**253* @brief Callback method for characters to implement by derived classes254*255* Called by "endElement" (see there).256* @param[in] element The opened element, given as a int257* @param[in] chars The complete embedded character string258* @exceptions ProcessError These method may throw a ProcessError if something fails259*/260virtual void myCharacters(int element,261const std::string& chars);262263264/** @brief Callback method for a closing tag to implement by derived classes265*266* Called by "endElement" (see there).267* @param[in] element The closed element, given as a int268* @exceptions ProcessError These method may throw a ProcessError if something fails269*/270virtual void myEndElement(int element);271272/// @brief signal endElement to the parent handler (special case for MSCalibrator)273void callParentEnd(int element);274275private:276/**277* @brief converts from c++-string into unicode278*279* @todo recheck encoding280* @param[in] name The string to convert281* @return The string converted into a XMLCh-string282*/283XMLCh* convert(const std::string& name) const;284285286/**287* @brief Converts a tag from its string into its numerical representation288*289* Returns the enum-representation stored for the given tag. If the tag is not290* known, SUMO_TAG_NOTHING is returned.291* @param[in] tag The string to convert292* @return The int-value that represents the string, SUMO_TAG_NOTHING if the named attribute is not known293*/294int convertTag(const std::string& tag) const;295296297private:298/// @name attributes parsing299//@{300301// the type of the map from ids to their unicode-string representation302typedef std::vector<XMLCh*> AttrMap;303304// the map from ids to their unicode-string representation305AttrMap myPredefinedTags;306307/// the map from ids to their string representation308std::vector<std::string> myPredefinedTagsMML;309//@}310311312/// @name elements parsing313//@{314315// the type of the map that maps tag names to ints316typedef std::map<std::string, int> TagMap;317318// the map of tag names to their internal numerical representation319TagMap myTagMap;320//@}321322/// A list of character strings obtained so far to build the complete characters string at the end323std::vector<std::string> myCharactersVector;324325/// @brief The handler to give control back to326GenericSAXHandler* myParentHandler;327328/// @brief The tag indicating that control should be given back329int myParentIndicator;330331/// @brief The name of the currently parsed file332std::string myFileName;333334/// @brief The root element to expect, empty string disables the check335std::string myExpectedRoot;336337/// @brief whether the reader should collect character data338bool myCollectCharacterData = false;339340/// @brief whether the reader has already seen the root element341bool myRootSeen = false;342343/// @brief The tag indicating the current section to parse344int mySection = -1;345346/// @brief whether the reader has already seen the begin of the section347bool mySectionSeen = false;348349/// @brief whether the reader has already seen the end of the section350bool mySectionEnded = false;351352/// @brief whether an element of the current section is open353bool mySectionOpen = false;354355std::pair<int, SUMOSAXAttributes*> myNextSectionStart;356357private:358/// @brief invalidated copy constructor359GenericSAXHandler(const GenericSAXHandler& s);360361/// @brief invalidated assignment operator362const GenericSAXHandler& operator=(const GenericSAXHandler& s);363364};365366367