/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2007-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 SUMOSAXAttributes.h14/// @author Daniel Krajzewicz15/// @author Jakob Erdmann16/// @author Michael Behrisch17/// @date Fri, 30 Mar 200718///19// Encapsulated SAX-Attributes20/****************************************************************************/21#pragma once22#include <config.h>2324#include <string>25#include <vector>26#include <set>2728#include <utils/common/StringUtils.h>29#include <utils/common/SUMOTime.h>30#include <utils/common/ToString.h>31#include <utils/common/UtilExceptions.h>3233#include "SUMOXMLDefinitions.h"3435// ===========================================================================36// class declarations37// ===========================================================================3839class Position;40class PositionVector;41class Boundary;42class RGBColor;4344// ===========================================================================45// class definitions46// ===========================================================================47/**48* @class SUMOSAXAttributes49* @brief Encapsulated SAX-Attributes50*51* This class is an interface for using encapsulated SAX-attributes.52* Encapsulation is done to allow a common access without the need to53* import all the Xerces-definitions.54*/55class SUMOSAXAttributes {56public:57/* @brief Constructor58* @param[in] tagName The name of the parsed object type; used for error message generation59*/60SUMOSAXAttributes(const std::string& objectType);616263/// @brief Destructor64virtual ~SUMOSAXAttributes() { }656667/** @brief Tries to read given attribute assuming it is an int68*69* If an error occurs (the attribute is not there, it is not numeric), "ok" is70* set to false. If report is true an error message is written to MsgHandler::getErrorInstance.71*72* If the value could be read, "ok" is not changed, and the value is returned.73*74* @param[in] attr The id of the attribute to read75* @param[in] objectid The name of the parsed object; used for error message generation76* @param[out] ok Whether the value could be read77* @param[in] report Whether errors shall be written to msg handler's error instance78* @return The read value if given and correct; -1 if an error occurred79*/80template <typename T>81T get(int attr, const char* objectid, bool& ok, bool report = true) const;828384/** @brief Tries to read given attribute assuming it is an int85*86* If the attribute is not existing in the current element, the default value is returned.87* If an error occurs on parsing (the attribute is empty, it is not numeric), "ok" is88* set to false. If report is true an error message is written to MsgHandler::getErrorInstance.89*90* If the value could be read, "ok" is not changed, and the value is returned.91*92* @param[in] attr The id of the attribute to read93* @param[in] objectid The name of the parsed object; used for error message generation94* @param[out] ok Whether the value could be read95* @param[in] defaultValue The value to return if the attribute is not within the element96* @param[in] report Whether errors shall be written to msg handler's error instance97* @return The read value if given and correct; the default value if the attribute does not exist; -1 if an error occurred98*/99template <typename T>100T getOpt(int attr, const char* objectid, bool& ok, T defaultValue = T(), bool report = true) const;101102103/** @brief Tries to read given attribute assuming it is a SUMOTime104*105* If an error occurs (the attribute is not there, it is not numeric), "ok" is106* set to false and an error message is written to MsgHandler::getErrorInstance.107*108* Otherwise, "ok" is not changed.109*110* In dependence to the used time representation, either get<int> or get<double>111* is used.112*113* @param[in] attr The id of the attribute to read114* @param[in] objectid The name of the parsed object; used for error message generation115* @param[out] ok Whether the value could be read116* @param[in] report Whether errors shall be written to msg handler's error instance117* @return The read value if given and correct; -1 if an error occurred118*/119SUMOTime getSUMOTimeReporting(int attr, const char* objectid, bool& ok,120bool report = true) const;121122123/** @brief Tries to read the SUMOTime 'period' attribute124*125* If 'period' cannot be found, tries 'freq' as an alias.126*127* If an error occurs (the attribute is not there, it is not numeric), "ok" is128* set to false and an error message is written to MsgHandler::getErrorInstance.129*130* Otherwise, "ok" is not changed.131*132* In dependence to the used time representation, either get<int> or get<double>133* is used.134*135* @param[in] objectid The name of the parsed object; used for error message generation136* @param[out] ok Whether the value could be read137* @param[in] report Whether errors shall be written to msg handler's error instance138* @return The read value if given and correct; -1 if an error occurred139*/140SUMOTime getPeriod(const char* objectid, bool& ok, bool report = true) const;141142143/** @brief Tries to read given attribute assuming it is a SUMOTime144*145* If the attribute is not existing in the current element, the default value is returned.146* If an error occurs on parsing (the attribute is empty, it is not numeric), "ok" is147* set to false. If report is true an error message is written to MsgHandler::getErrorInstance.148*149* Otherwise, "ok" is not changed.150*151* In dependence to the used time representation, either get<int> or get<double>152* is used.153*154* @param[in] attr The id of the attribute to read155* @param[in] objectid The name of the parsed object; used for error message generation156* @param[out] ok Whether the value could be read157* @param[in] defaultValue The value to return if the attribute is not within the element158* @param[in] report Whether errors shall be written to msg handler's error instance159* @return The read value if given and correct; the default value if the attribute does not exist; -1 if an error occurred160*/161SUMOTime getOptSUMOTimeReporting(int attr, const char* objectid, bool& ok,162SUMOTime defaultValue, bool report = true) const;163164/** @brief Tries to read given attribute assuming it is a tls offset165* (SUMOTime or "begin")166*167* If the attribute is not existing in the current element, the default value is returned.168* If an error occurs on parsing (the attribute is empty, it is not numeric), "ok" is169* set to false. If report is true an error message is written to MsgHandler::getErrorInstance.170*171* Otherwise, "ok" is not changed.172*173* In dependence to the used time representation, either get<int> or get<double>174* is used.175*176* @param[in] attr The id of the attribute to read177* @param[in] objectid The name of the parsed object; used for error message generation178* @param[out] ok Whether the value could be read179* @param[in] defaultValue The value to return if the attribute is not within the element180* @param[in] report Whether errors shall be written to msg handler's error instance181* @return The read value if given and correct; the default value if the attribute does not exist; -1 if an error occurred182*/183SUMOTime getOptOffsetReporting(int attr, const char* objectid, bool& ok,184SUMOTime defaultValue, bool report = true) const;185186/** @brief Tries to read the SUMOTime 'period' attribute187*188* If 'period' cannot be found, tries 'freq' as an alias.189*190* If both attributes do not exist in the current element, the default value is returned.191* If an error occurs on parsing (the attribute is empty, it is not numeric), "ok" is192* set to false. If report is true an error message is written to MsgHandler::getErrorInstance.193*194* Otherwise, "ok" is not changed.195*196* In dependence to the used time representation, either get<int> or get<double>197* is used.198*199* @param[in] objectid The name of the parsed object; used for error message generation200* @param[out] ok Whether the value could be read201* @param[in] defaultValue The value to return if the attribute is not within the element202* @param[in] report Whether errors shall be written to msg handler's error instance203* @return The read value if given and correct; the default value if the attribute does not exist; -1 if an error occurred204*/205SUMOTime getOptPeriod(const char* objectid, bool& ok, SUMOTime defaultValue, bool report = true) const;206207208209/// @name virtual methods for retrieving attribute values210/// @{211212/** @brief Returns the information whether the named (by its enum-value) attribute is within the current list213*214* @param[in] id The id of the attribute to search for215* @return Whether the attribute is within the attributes216*/217virtual bool hasAttribute(int id) const = 0;218219220/** @brief Returns the information whether the named attribute is within the current list221*222* @param[in] id The name of the attribute to search for223* @return Whether the named attribute is within the attributes224*/225virtual bool hasAttribute(const std::string& id) const = 0;226227228/**229* @brief Returns the bool-value of the named (by its enum-value) attribute230*231* Tries to retrieve the attribute from the attribute list. The retrieved232* attribute (which may be 0) is then parsed using TplConvert<XMLCh>::_2bool.233* If the attribute is empty or ==0, TplConvert<XMLCh>::_2bool throws an234* EmptyData-exception which is passed.235* If the value can not be parsed to a bool, TplConvert<XMLCh>::_2bool throws a236* BoolFormatException-exception which is passed.237*238* @param[in] id The id of the attribute to return the value of239* @return The attribute's value as a bool, if it could be read and parsed240* @exception EmptyData If the attribute is not known or the attribute value is an empty string241* @exception BoolFormatException If the attribute value can not be parsed to a bool242*/243inline bool getBool(int id) const {244return StringUtils::toBool(getString(id));245}246247/**248* @brief Returns the int-value of the named (by its enum-value) attribute249*250* Tries to retrieve the attribute from the attribute list. The retrieved251* attribute (which may be 0) is then parsed using TplConvert<XMLCh>::_2int.252* If the attribute is empty or ==0, TplConvert<XMLCh>::_2int throws an253* EmptyData-exception which is passed.254* If the value can not be parsed to an int, TplConvert<XMLCh>::_2int throws a255* NumberFormatException-exception which is passed.256*257* @param[in] id The id of the attribute to return the value of258* @return The attribute's value as an int, if it could be read and parsed259* @exception EmptyData If the attribute is not known or the attribute value is an empty string260* @exception NumberFormatException If the attribute value can not be parsed to an int261*/262inline int getInt(int id) const {263return StringUtils::toInt(getString(id));264}265266267/**268* @brief Returns the long-value of the named (by its enum-value) attribute269*270* Tries to retrieve the attribute from the attribute list. The retrieved271* attribute (which may be 0) is then parsed using TplConvert<XMLCh>::_2long.272* If the attribute is empty or ==0, TplConvert<XMLCh>::_2long throws an273* EmptyData-exception which is passed.274* If the value can not be parsed to a long, TplConvert<XMLCh>::_2long throws a275* NumberFormatException-exception which is passed.276*277* @param[in] id The id of the attribute to return the value of278* @return The attribute's value as an int, if it could be read and parsed279* @exception EmptyData If the attribute is not known or the attribute value is an empty string280* @exception NumberFormatException If the attribute value can not be parsed to an int281*/282virtual long long int getLong(int id) const {283return StringUtils::toLong(getString(id));284}285286287/**288* @brief Returns the string-value of the named (by its enum-value) attribute289*290* Tries to retrieve the attribute from the attribute list. The retrieved291* attribute (which may be 0) is then parsed using TplConvert<XMLCh>::_2str.292* If the attribute is ==0, TplConvert<XMLCh>::_2str throws an293* EmptyData-exception which is passed.294*295* @param[in] id The id of the attribute to return the value of296* @return The attribute's value as a string, if it could be read and parsed297* @exception EmptyData If the attribute is not known or the attribute value is an empty string298*/299virtual std::string getString(int id, bool* isPresent = nullptr) const = 0;300301302/**303* @brief Returns the string-value of the named (by its enum-value) attribute304*305* Tries to retrieve the attribute from the attribute list. The retrieved306* attribute (which may be 0) is then parsed using TplConvert<XMLCh>::_2strSec.307* If the attribute is ==0, TplConvert<XMLCh>::_2strSec returns the default value.308*309* @param[in] id The id of the attribute to return the value of310* @param[in] def The default value to return if the attribute is not in attributes311* @return The attribute's value as a string, if it could be read and parsed312* @exception EmptyData If the attribute is not known or the attribute value is an empty string313*/314virtual std::string getStringSecure(int id, const std::string& def) const = 0;315316317/**318* @brief Returns the double-value of the named (by its enum-value) attribute319*320* Tries to retrieve the attribute from the attribute list. The retrieved321* attribute (which may be 0) is then parsed using TplConvert<XMLCh>::_2double.322* If the attribute is empty or ==0, TplConvert<XMLCh>::_2double throws an323* EmptyData-exception which is passed.324* If the value can not be parsed to a double, TplConvert<XMLCh>::_2double throws a325* NumberFormatException-exception which is passed.326*327* @param[in] id The id of the attribute to return the value of328* @return The attribute's value as a float, if it could be read and parsed329* @exception EmptyData If the attribute is not known or the attribute value is an empty string330* @exception NumberFormatException If the attribute value can not be parsed to an double331*/332inline double getFloat(int id) const {333return StringUtils::toDouble(getString(id));334}335336337/**338* @brief Returns the double-value of the named attribute339*340* Tries to retrieve the attribute from the attribute list. The retrieved341* attribute (which may be 0) is then parsed using TplConvert<XMLCh>::_2double.342* If the attribute is empty or ==0, TplConvert<XMLCh>::_2double throws an343* EmptyData-exception which is passed.344* If the value can not be parsed to a double, TplConvert<XMLCh>::_2double throws a345* NumberFormatException-exception which is passed.346*347* @param[in] id The name of the attribute to return the value of348* @return The attribute's value as a float, if it could be read and parsed349* @exception EmptyData If the attribute is not known or the attribute value is an empty string350* @exception NumberFormatException If the attribute value can not be parsed to an double351*/352virtual double getFloat(const std::string& id) const = 0;353354355/**356* @brief Returns the string-value of the named (by its enum-value) attribute357*358* Tries to retrieve the attribute from the attribute list.359* If the attribute is ==0, TplConvert<XMLCh>::_2strSec returns the default value.360* @param[in] id The name of the attribute to return the value of361* @param[in] def The default value to return if the attribute is not in attributes362* @return The attribute's value as a string, if it could be read and parsed363*/364virtual std::string getStringSecure(const std::string& id,365const std::string& def) const = 0;366//}367368369/** @brief Converts the given attribute id into a man readable string370*371* @param[in] attr The id of the attribute to return the name of372* @return The name of the described attribute373*/374virtual std::string getName(int attr) const = 0;375376/** @brief Prints all attribute names and values into the given stream377*378* @param[in] os The stream to use379*/380virtual void serialize(std::ostream& os) const = 0;381382/** @brief Retrieves all attribute names383*/384virtual std::vector<std::string> getAttributeNames() const = 0;385386/// @brief return the objecttype to which these attributes belong387const std::string& getObjectType() const {388return myObjectType;389}390391friend std::ostream& operator<<(std::ostream& os, const SUMOSAXAttributes& src);392393/// @brief return a new deep-copy attributes object394virtual SUMOSAXAttributes* clone() const = 0;395396/** @brief The encoding of parsed strings */397static const std::string ENCODING;398399400protected:401template <typename T> T fromString(const std::string& value) const;402void emitUngivenError(const std::string& attrname, const char* objectid) const;403void emitEmptyError(const std::string& attrname, const char* objectid) const;404void emitFormatError(const std::string& attrname, const std::string& type, const char* objectid) const;405406private:407/// @brief Invalidated copy constructor.408SUMOSAXAttributes(const SUMOSAXAttributes& src) = delete;409410/// @brief Invalidated assignment operator.411SUMOSAXAttributes& operator=(const SUMOSAXAttributes& src) = delete;412413/// @brief the object type to use in error reporting414std::string myObjectType;415416};417418419inline std::ostream& operator<<(std::ostream& os, const SUMOSAXAttributes& src) {420src.serialize(os);421return os;422}423424425template<typename X> struct invalid_return {426static const X value;427};428429#define INVALID_RETURN(TYPE) \430template<> struct invalid_return<TYPE> { \431static const TYPE value; \432}433INVALID_RETURN(std::string);434INVALID_RETURN(int);435INVALID_RETURN(long long int);436INVALID_RETURN(double);437INVALID_RETURN(bool);438INVALID_RETURN(RGBColor);439INVALID_RETURN(Position);440INVALID_RETURN(PositionVector);441INVALID_RETURN(Boundary);442INVALID_RETURN(SumoXMLEdgeFunc);443INVALID_RETURN(SumoXMLNodeType);444INVALID_RETURN(RightOfWay);445INVALID_RETURN(FringeType);446INVALID_RETURN(ParkingType);447INVALID_RETURN(std::vector<std::string>);448INVALID_RETURN(std::vector<int>);449INVALID_RETURN(std::vector<double>);450451452template <typename T>453T SUMOSAXAttributes::get(int attr, const char* objectid,454bool& ok, bool report) const {455try {456bool isPresent = true;457const std::string& strAttr = getString(attr, &isPresent);458if (isPresent) {459return fromString<T>(strAttr);460}461if (report) {462emitUngivenError(getName(attr), objectid);463}464} catch (const FormatException& e) {465if (report) {466emitFormatError(getName(attr), e.what(), objectid);467}468} catch (EmptyData&) {469if (report) {470emitEmptyError(getName(attr), objectid);471}472}473ok = false;474return invalid_return<T>::value;475}476477478template <typename T>479T SUMOSAXAttributes::getOpt(int attr, const char* objectid,480bool& ok, T defaultValue, bool report) const {481try {482bool isPresent = true;483const std::string& strAttr = getString(attr, &isPresent);484if (isPresent) {485return fromString<T>(strAttr);486}487return defaultValue;488} catch (const FormatException& e) {489if (report) {490emitFormatError(getName(attr), e.what(), objectid);491}492} catch (EmptyData&) {493if (report) {494emitEmptyError(getName(attr), objectid);495}496}497ok = false;498return invalid_return<T>::value;499}500501502