Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/handlers/TemplateHandler.cpp
169678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 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 TemplateHandler.cpp
15
/// @author Pablo Alvarez Lopez
16
/// @date Dec 2022
17
///
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>
29
#include <utils/common/StringUtils.h>
30
#include <utils/common/StringTokenizer.h>
31
#include <utils/common/UtilExceptions.h>
32
#include <utils/common/FileHelpers.h>
33
#include <utils/common/MsgHandler.h>
34
#include <utils/common/ToString.h>
35
#include <utils/options/OptionsCont.h>
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
44
const std::string TemplateHandler::INVALID_INT_STR = toString(INVALID_INT);
45
const std::string TemplateHandler::INVALID_DOUBLE_STR = toString(INVALID_DOUBLE);
46
47
// ===========================================================================
48
// method definitions
49
// ===========================================================================
50
51
void
52
TemplateHandler::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
76
TemplateHandler::TemplateHandler(OptionsCont& options) :
77
myError(false),
78
myOptions(options) {
79
}
80
81
82
TemplateHandler::~TemplateHandler() {}
83
84
85
void
86
TemplateHandler::startElement(const XMLCh* const name, XERCES_CPP_NAMESPACE::AttributeList& attributes) {
87
// get current topic
88
myOptionName = StringUtils::transcode(name);
89
if (myLevel++ == 0) {
90
// skip root elemnt
91
return;
92
}
93
// check if this is a subtopic
94
if (attributes.getLength() == 0) {
95
mySubTopic = myOptionName;
96
myOptions.addOptionSubTopic(mySubTopic);
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
140
bool
141
TemplateHandler::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 {
143
if (myOptions.exists(myOptionName)) {
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
}
210
myOptions.doRegister(myOptionName, option);
211
// check if add synonyme
212
if (synonymes.size() > 0) {
213
myOptions.addSynonyme(myOptionName, synonymes);
214
}
215
// check if add help
216
if (help.size() > 0) {
217
myOptions.addDescription(myOptionName, mySubTopic, help);
218
}
219
myOptions.setFurtherAttributes(myOptionName, mySubTopic, required, positional, listSep);
220
return true;
221
} else {
222
return false;
223
}
224
}
225
}
226
227
228
void
229
TemplateHandler::endElement(const XMLCh* const /*name*/) {
230
myLevel--;
231
if (myOptionName.length() == 0) {
232
return;
233
}
234
myOptionName = "";
235
}
236
237
238
void
239
TemplateHandler::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
248
void
249
TemplateHandler::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
258
void
259
TemplateHandler::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
/****************************************************************************/
268
269