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-2024 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>
36#include <xercesc/parsers/SAXParser.hpp>
37#include <xercesc/sax2/XMLReaderFactory.hpp>
38#include <xercesc/framework/LocalFileInputSource.hpp>
39#include <xercesc/framework/MemBufInputSource.hpp>
40
41#include "TemplateHandler.h"
42
43
46
47// ===========================================================================
48// method definitions
49// ===========================================================================
50
51void
52TemplateHandler::parseTemplate(OptionsCont& options, const std::string& templateString) {
53 // build parser
54 XERCES_CPP_NAMESPACE::SAXParser parser;
55 // disable validation
56 parser.setValidationScheme(XERCES_CPP_NAMESPACE::SAXParser::Val_Never);
57 parser.setDisableDefaultEntityResolution(true);
58 // build TemplateHandler
59 TemplateHandler handler(options);
60 // start parsing
61 try {
62 parser.setDocumentHandler(&handler);
63 parser.setErrorHandler(&handler);
64 XERCES_CPP_NAMESPACE::MemBufInputSource memBufIS((const XMLByte*)templateString.c_str(), templateString.size(), "template");
65 parser.parse(memBufIS);
66 if (handler.myError) {
67 throw ProcessError(TLF("Could not load template '%'.", templateString));
68 }
69 } catch (const XERCES_CPP_NAMESPACE::XMLException& e) {
70 throw ProcessError("Could not load template '" + templateString + "':\n " + StringUtils::transcode(e.getMessage()));
71 }
72 // mark al loaded options as default
73 options.resetDefault();
74}
75
77 myError(false),
78 myOptions(options) {
79}
80
81
83
84
85void
86TemplateHandler::startElement(const XMLCh* const name, XERCES_CPP_NAMESPACE::AttributeList& attributes) {
87 // get current topic
89 if (myLevel++ == 0) {
90 // skip root elemnt
91 return;
92 }
93 // check if this is a subtopic
94 if (attributes.getLength() == 0) {
97 } else {
98 // declare options parameters (by default all empty)
99 std::string value;
100 std::string synonymes;
101 std::string type;
102 std::string help;
103 bool required = false;
104 bool positional = false;
105 std::string listSep = "";
106 // iterate over attributes
107 for (int i = 0; i < (int)attributes.getLength(); i++) {
108 const std::string attributeName = StringUtils::transcode(attributes.getName(i));
109 const std::string attributeValue = StringUtils::transcode(attributes.getValue(i));
110 // check attribute name
111 if (attributeName == "value") {
112 value = attributeValue;
113 } else if (attributeName == "synonymes") {
114 synonymes = attributeValue;
115 } else if (attributeName == "type") {
116 type = attributeValue;
117 } else if (attributeName == "help") {
118 help = attributeValue;
119 } else if (attributeName == "category") {
120 // tool templates have subtopic as attribute category
121 mySubTopic = attributeValue;
122 const auto& topics = myOptions.getSubTopics();
123 if (std::find(topics.begin(), topics.end(), attributeValue) == topics.end()) {
124 myOptions.addOptionSubTopic(attributeValue);
125 }
126 } else if (attributeName == "required") {
127 required = StringUtils::toBool(attributeValue);
128 } else if (attributeName == "positional") {
129 positional = StringUtils::toBool(attributeValue);
130 } else if (attributeName == "listSeparator") {
131 listSep = attributeValue;
132 }
133 }
134 // add option
135 addOption(value, synonymes, type, help, required, positional, listSep);
136 }
137}
138
139
140bool
141TemplateHandler::addOption(std::string value, const std::string& synonymes, const std::string& type,
142 const std::string& help, bool required, bool positional, const std::string& listSep) const {
144 WRITE_WARNING(myOptionName + " already exists");
145 return false;
146 } else {
147 // declare option
148 Option* option = nullptr;
149 // handle "None" as empty
150 if (value == "None") {
151 value.clear();
152 }
153 // create register depending of type
154 if ((type == "STR") || (type == "string")) {
155 option = new Option_String(value);
156 } else if ((type == "TIME") || (type == "time")) {
157 option = new Option_String(value, "TIME");
158 } else if ((type == "INT") || (type == "int")) {
159 option = new Option_Integer(0);
160 if (value.empty()) {
161 option->set(INVALID_INT_STR, "", true);
162 } else {
163 option->set(value, value, true);
164 }
165 } else if ((type == "FLOAT") || (type == "float")) {
166 option = new Option_Float(0);
167 if (value.empty()) {
168 option->set(INVALID_DOUBLE_STR, "", true);
169 } else {
170 option->set(value, value, true);
171 }
172 } else if ((type == "BOOL") || (type == "bool")) {
173 option = new Option_Bool(false);
174 if (value.empty()) {
175 option->set("false", "", true);
176 } else {
177 option->set(value, value, true);
178 }
179 } else if (type == "INT[]") {
180 option = new Option_IntVector();
181 } else if (type == "STR[]") {
182 option = new Option_StringVector();
183 } else if ((type == "FILE") || (type == "file")) {
184 option = new Option_FileName();
185 } else if ((type == "NETWORK") || (type == "net_file")) {
186 option = new Option_Network(value);
187 } else if ((type == "ADDITIONAL") || (type == "additional_file")) {
188 option = new Option_Additional(value);
189 } else if ((type == "ROUTE") || (type == "route_file")) {
190 option = new Option_Route(value);
191 } else if ((type == "DATA") || (type == "data_file") || (type == "edgedata_file")) {
192 option = new Option_Data(value);
193 } else if ((type == "SUMOCONFIG") || (type == "sumoconfig_file")) {
194 option = new Option_SumoConfig(value);
195 } else if ((type == "EDGE") || (type == "edge")) {
196 if (listSep.empty()) {
197 option = new Option_Edge(value);
198 } else {
199 option = new Option_EdgeVector(value);
200 }
201 } else if (type.size() > 0) {
202 WRITE_WARNING(type + " is an invalid type");
203 }
204 // check if option was created
205 if (option) {
206 // set value
207 if (!option->isSet()) {
208 option->set(value, "", false);
209 }
211 // check if add synonyme
212 if (synonymes.size() > 0) {
214 }
215 // check if add help
216 if (help.size() > 0) {
218 }
219 myOptions.setFurtherAttributes(myOptionName, mySubTopic, required, positional, listSep);
220 return true;
221 } else {
222 return false;
223 }
224 }
225}
226
227
228void
229TemplateHandler::endElement(const XMLCh* const /*name*/) {
230 myLevel--;
231 if (myOptionName.length() == 0) {
232 return;
233 }
234 myOptionName = "";
235}
236
237
238void
239TemplateHandler::warning(const XERCES_CPP_NAMESPACE::SAXParseException& exception) {
240 WRITE_WARNING(StringUtils::transcode(exception.getMessage()));
241 WRITE_WARNING(" (At line/column " \
242 + toString(exception.getLineNumber() + 1) + '/' \
243 + toString(exception.getColumnNumber()) + ").");
244 myError = true;
245}
246
247
248void
249TemplateHandler::error(const XERCES_CPP_NAMESPACE::SAXParseException& exception) {
250 WRITE_ERROR(StringUtils::transcode(exception.getMessage()));
251 WRITE_ERROR(" (At line/column "
252 + toString(exception.getLineNumber() + 1) + '/'
253 + toString(exception.getColumnNumber()) + ").");
254 myError = true;
255}
256
257
258void
259TemplateHandler::fatalError(const XERCES_CPP_NAMESPACE::SAXParseException& exception) {
260 WRITE_ERROR(StringUtils::transcode(exception.getMessage()));
261 WRITE_ERROR(" (At line/column "
262 + toString(exception.getLineNumber() + 1) + '/'
263 + toString(exception.getColumnNumber()) + ").");
264 myError = true;
265}
266
267/****************************************************************************/
#define WRITE_ERROR(msg)
Definition MsgHandler.h:304
#define WRITE_WARNING(msg)
Definition MsgHandler.h:295
#define TLF(string,...)
Definition MsgHandler.h:317
const double INVALID_DOUBLE
invalid double
Definition StdDefs.h:64
const int INVALID_INT
invalid int
Definition StdDefs.h:61
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
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 std::string transcode(const XMLCh *const data)
converts a 0-terminated XMLCh* array (usually UTF-16, stemming from Xerces) into std::string in UTF-8
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(OptionsCont &options)
Constructor.
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.