Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
TemplateHandler.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-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/****************************************************************************/
18// A SAX-Handler for loading templates
19/****************************************************************************/
20#include <config.h>
21
22#include <algorithm>
23#include <string>
24#include <vector>
25#include <xercesc/sax/HandlerBase.hpp>
26#include <xercesc/sax/AttributeList.hpp>
27#include <xercesc/sax/SAXParseException.hpp>
28#include <xercesc/sax/SAXException.hpp>
30#include <utils/xml/XMLSubSys.h>
37#include <xercesc/parsers/SAXParser.hpp>
38#include <xercesc/sax2/XMLReaderFactory.hpp>
39#include <xercesc/framework/LocalFileInputSource.hpp>
40#include <xercesc/framework/MemBufInputSource.hpp>
41
42#include "TemplateHandler.h"
43
44
47
48// ===========================================================================
49// method definitions
50// ===========================================================================
51
52void
53TemplateHandler::parseTemplate(OptionsCont& options, const std::string& templateString) {
54 // build parser
55 XERCES_CPP_NAMESPACE::SAXParser parser;
56 // disable validation
57 parser.setValidationScheme(XERCES_CPP_NAMESPACE::SAXParser::Val_Never);
58 parser.setDisableDefaultEntityResolution(true);
59 // build TemplateHandler
60 TemplateHandler handler(options);
61 // start parsing
62 try {
63 parser.setDocumentHandler(&handler);
64 parser.setErrorHandler(&handler);
65 XERCES_CPP_NAMESPACE::MemBufInputSource memBufIS((const XMLByte*)templateString.c_str(), templateString.size(), "template");
66 parser.parse(memBufIS);
67 if (handler.myError) {
68 throw ProcessError(TLF("Could not load template '%'.", templateString));
69 }
70 } catch (const XERCES_CPP_NAMESPACE::XMLException& e) {
71 throw ProcessError("Could not load template '" + templateString + "':\n " + XMLSubSys::transcode(e.getMessage()));
72 }
73 // mark al loaded options as default
74 options.resetDefault();
75}
76
78 myError(false),
79 myOptions(options) {
80}
81
82
84
85
86void
87TemplateHandler::startElement(const XMLCh* const name, XERCES_CPP_NAMESPACE::AttributeList& attributes) {
88 // get current topic
90 if (myLevel++ == 0) {
91 // skip root elemnt
92 return;
93 }
94 // check if this is a subtopic
95 if (attributes.getLength() == 0) {
98 } else {
99 // declare options parameters (by default all empty)
100 std::string value;
101 std::string synonymes;
102 std::string type;
103 std::string help;
104 bool required = false;
105 bool positional = false;
106 std::string listSep = "";
107 // iterate over attributes
108 for (int i = 0; i < (int)attributes.getLength(); i++) {
109 const std::string attributeName = XMLSubSys::transcode(attributes.getName(i));
110 const std::string attributeValue = XMLSubSys::transcode(attributes.getValue(i));
111 // check attribute name
112 if (attributeName == "value") {
113 value = attributeValue;
114 } else if (attributeName == "synonymes") {
115 synonymes = attributeValue;
116 } else if (attributeName == "type") {
117 type = attributeValue;
118 } else if (attributeName == "help") {
119 help = attributeValue;
120 } else if (attributeName == "category") {
121 // tool templates have subtopic as attribute category
122 mySubTopic = attributeValue;
123 const auto& topics = myOptions.getSubTopics();
124 if (std::find(topics.begin(), topics.end(), attributeValue) == topics.end()) {
125 myOptions.addOptionSubTopic(attributeValue);
126 }
127 } else if (attributeName == "required") {
128 required = StringUtils::toBool(attributeValue);
129 } else if (attributeName == "positional") {
130 positional = StringUtils::toBool(attributeValue);
131 } else if (attributeName == "listSeparator") {
132 listSep = attributeValue;
133 }
134 }
135 // add option
136 addOption(value, synonymes, type, help, required, positional, listSep);
137 }
138}
139
140
141bool
142TemplateHandler::addOption(std::string value, const std::string& synonymes, const std::string& type,
143 const std::string& help, bool required, bool positional, const std::string& listSep) const {
145 WRITE_WARNING(myOptionName + " already exists");
146 return false;
147 } else {
148 // declare option
149 Option* option = nullptr;
150 // handle "None" as empty
151 if (value == "None") {
152 value.clear();
153 }
154 // create register depending of type
155 if ((type == "STR") || (type == "string")) {
156 option = new Option_String(value);
157 } else if ((type == "TIME") || (type == "time")) {
158 option = new Option_String(value, "TIME");
159 } else if ((type == "INT") || (type == "int")) {
160 option = new Option_Integer(0);
161 if (value.empty()) {
162 option->set(INVALID_INT_STR, "", true);
163 } else {
164 option->set(value, value, true);
165 }
166 } else if ((type == "FLOAT") || (type == "float")) {
167 option = new Option_Float(0);
168 if (value.empty()) {
169 option->set(INVALID_DOUBLE_STR, "", true);
170 } else {
171 option->set(value, value, true);
172 }
173 } else if ((type == "BOOL") || (type == "bool")) {
174 option = new Option_Bool(false);
175 if (value.empty()) {
176 option->set("false", "", true);
177 } else {
178 option->set(value, value, true);
179 }
180 } else if (type == "INT[]") {
181 option = new Option_IntVector();
182 } else if (type == "STR[]") {
183 option = new Option_StringVector();
184 } else if ((type == "FILE") || (type == "file")) {
185 option = new Option_FileName();
186 } else if ((type == "NETWORK") || (type == "net_file")) {
187 option = new Option_Network(value);
188 } else if ((type == "ADDITIONAL") || (type == "additional_file")) {
189 option = new Option_Additional(value);
190 } else if ((type == "ROUTE") || (type == "route_file")) {
191 option = new Option_Route(value);
192 } else if ((type == "DATA") || (type == "data_file") || (type == "edgedata_file")) {
193 option = new Option_Data(value);
194 } else if ((type == "SUMOCONFIG") || (type == "sumoconfig_file")) {
195 option = new Option_SumoConfig(value);
196 } else if ((type == "EDGE") || (type == "edge")) {
197 if (listSep.empty()) {
198 option = new Option_Edge(value);
199 } else {
200 option = new Option_EdgeVector(value);
201 }
202 } else if (type.size() > 0) {
203 WRITE_WARNING(type + " is an invalid type");
204 }
205 // check if option was created
206 if (option) {
207 // set value
208 if (!option->isSet()) {
209 option->set(value, "", false);
210 }
212 // check if add synonyme
213 if (synonymes.size() > 0) {
215 }
216 // check if add help
217 if (help.size() > 0) {
219 }
220 myOptions.setFurtherAttributes(myOptionName, mySubTopic, required, positional, listSep);
221 return true;
222 } else {
223 return false;
224 }
225 }
226}
227
228
229void
230TemplateHandler::endElement(const XMLCh* const /*name*/) {
231 myLevel--;
232 if (myOptionName.length() == 0) {
233 return;
234 }
235 myOptionName = "";
236}
237
238
239void
240TemplateHandler::warning(const XERCES_CPP_NAMESPACE::SAXParseException& exception) {
241 WRITE_WARNING(XMLSubSys::transcode(exception.getMessage()));
242 WRITE_WARNING(" (At line/column " \
243 + toString(exception.getLineNumber() + 1) + '/' \
244 + toString(exception.getColumnNumber()) + ").");
245 myError = true;
246}
247
248
249void
250TemplateHandler::error(const XERCES_CPP_NAMESPACE::SAXParseException& exception) {
251 WRITE_ERROR(XMLSubSys::transcode(exception.getMessage()));
252 WRITE_ERROR(" (At line/column "
253 + toString(exception.getLineNumber() + 1) + '/'
254 + toString(exception.getColumnNumber()) + ").");
255 myError = true;
256}
257
258
259void
260TemplateHandler::fatalError(const XERCES_CPP_NAMESPACE::SAXParseException& exception) {
261 WRITE_ERROR(XMLSubSys::transcode(exception.getMessage()));
262 WRITE_ERROR(" (At line/column "
263 + toString(exception.getLineNumber() + 1) + '/'
264 + toString(exception.getColumnNumber()) + ").");
265 myError = true;
266}
267
268/****************************************************************************/
#define WRITE_ERROR(msg)
Definition MsgHandler.h:295
#define WRITE_WARNING(msg)
Definition MsgHandler.h:286
#define TLF(string,...)
Definition MsgHandler.h:306
const double INVALID_DOUBLE
invalid double
Definition StdDefs.h:68
const int INVALID_INT
invalid int
Definition StdDefs.h:65
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:49
A class representing a single program option.
Definition Option.h:74
bool isSet() const
returns the information whether this options holds a valid value
Definition Option.cpp:53
virtual bool set(const std::string &v, const std::string &orig, const bool append)=0
Stores the given value.
A storage for options typed value containers)
Definition OptionsCont.h:89
void addDescription(const std::string &name, const std::string &subtopic, const std::string &description)
Adds a description for an option.
void resetDefault()
Resets all options to default.
void setFurtherAttributes(const std::string &name, const std::string &subtopic, bool required, bool positional, const std::string &listSep)
mark option as required
const std::vector< std::string > & getSubTopics() const
return the list of subtopics
void addSynonyme(const std::string &name1, const std::string &name2, bool isDeprecated=false)
Adds a synonyme for an options name (any order)
void doRegister(const std::string &name, Option *o)
Adds an option under the given name.
bool exists(const std::string &name) const
Returns the information whether the named option is known.
void addOptionSubTopic(const std::string &topic)
Adds an option subtopic.
static bool toBool(const std::string &sData)
converts a string into the bool value described by it by calling the char-type converter
A SAX-Handler for loading options.
void fatalError(const XERCES_CPP_NAMESPACE::SAXParseException &exception)
Called on an XML-fatal error.
static const std::string INVALID_DOUBLE_STR
invalid double in string format
TemplateHandler()=delete
invalidate default onstructor
void endElement(const XMLCh *const name)
Called on the end of an element.
bool myError
The information whether an error occurred.
int myLevel
The nesting level of parsed elements.
std::string mySubTopic
current subtopic
std::string myOptionName
The name of the current option.
void startElement(const XMLCh *const name, XERCES_CPP_NAMESPACE::AttributeList &attributes)
Called on the occurrence of the beginning of a tag.
OptionsCont & myOptions
The options to fill.
~TemplateHandler()
destructor
void error(const XERCES_CPP_NAMESPACE::SAXParseException &exception)
Called on an XML-error.
static void parseTemplate(OptionsCont &options, const std::string &templateString)
run parser
static const std::string INVALID_INT_STR
invalid int in string format
bool addOption(std::string value, const std::string &synonymes, const std::string &type, const std::string &help, bool required, bool positional, const std::string &listSep) const
add option
void warning(const XERCES_CPP_NAMESPACE::SAXParseException &exception)
Called on an XML-warning.
static std::string transcode(const XMLCh *const data, int length=-1)
converts a 0-terminated XMLCh* array (usually UTF-16, stemming from Xerces) into std::string in UTF-8