Eclipse SUMO - Simulation of Urban MObility
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>
34 #include <utils/common/ToString.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 
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 
77  myError(false),
78  myOptions(options) {
79 }
80 
81 
83 
84 
85 void
86 TemplateHandler::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 
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 {
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 == "INT") || (type == "int")) {
157  option = new Option_Integer(0);
158  if (value.empty()) {
159  option->set(INVALID_INT_STR, "", true);
160  } else {
161  option->set(value, value, true);
162  }
163  } else if ((type == "FLOAT") || (type == "float") || (type == "TIME") || (type == "time")) {
164  option = new Option_Float(0);
165  if (value.empty()) {
166  option->set(INVALID_DOUBLE_STR, "", true);
167  } else {
168  option->set(value, value, true);
169  }
170  } else if ((type == "BOOL") || (type == "bool")) {
171  option = new Option_Bool(false);
172  if (value.empty()) {
173  option->set("false", "", true);
174  } else {
175  option->set(value, value, true);
176  }
177  } else if (type == "INT[]") {
178  option = new Option_IntVector();
179  } else if (type == "STR[]") {
180  option = new Option_StringVector();
181  } else if ((type == "FILE") || (type == "file")) {
182  option = new Option_FileName();
183  } else if ((type == "NETWORK") || (type == "net_file")) {
184  option = new Option_Network(value);
185  } else if ((type == "ADDITIONAL") || (type == "additional_file")) {
186  option = new Option_Additional(value);
187  } else if ((type == "ROUTE") || (type == "route_file")) {
188  option = new Option_Route(value);
189  } else if ((type == "DATA") || (type == "data_file") || (type == "edgedata_file")) {
190  option = new Option_Data(value);
191  } else if ((type == "SUMOCONFIG") || (type == "sumoconfig_file")) {
192  option = new Option_SumoConfig(value);
193  } else if ((type == "EDGE") || (type == "edge")) {
194  if (listSep.empty()) {
195  option = new Option_Edge(value);
196  } else {
197  option = new Option_EdgeVector(value);
198  }
199  } else if (type.size() > 0) {
200  WRITE_WARNING(type + " is an invalid type");
201  }
202  // check if option was created
203  if (option) {
204  // set value
205  if (!option->isSet()) {
206  option->set(value, "", false);
207  }
209  // check if add synonyme
210  if (synonymes.size() > 0) {
211  myOptions.addSynonyme(myOptionName, synonymes);
212  }
213  // check if add help
214  if (help.size() > 0) {
216  }
217  myOptions.setFurtherAttributes(myOptionName, mySubTopic, required, positional, listSep);
218  return true;
219  } else {
220  return false;
221  }
222  }
223 }
224 
225 
226 void
227 TemplateHandler::endElement(const XMLCh* const /*name*/) {
228  myLevel--;
229  if (myOptionName.length() == 0) {
230  return;
231  }
232  myOptionName = "";
233 }
234 
235 
236 void
237 TemplateHandler::warning(const XERCES_CPP_NAMESPACE::SAXParseException& exception) {
238  WRITE_WARNING(StringUtils::transcode(exception.getMessage()));
239  WRITE_WARNING(" (At line/column " \
240  + toString(exception.getLineNumber() + 1) + '/' \
241  + toString(exception.getColumnNumber()) + ").");
242  myError = true;
243 }
244 
245 
246 void
247 TemplateHandler::error(const XERCES_CPP_NAMESPACE::SAXParseException& exception) {
248  WRITE_ERROR(StringUtils::transcode(exception.getMessage()));
249  WRITE_ERROR(" (At line/column "
250  + toString(exception.getLineNumber() + 1) + '/'
251  + toString(exception.getColumnNumber()) + ").");
252  myError = true;
253 }
254 
255 
256 void
257 TemplateHandler::fatalError(const XERCES_CPP_NAMESPACE::SAXParseException& exception) {
258  WRITE_ERROR(StringUtils::transcode(exception.getMessage()));
259  WRITE_ERROR(" (At line/column "
260  + toString(exception.getLineNumber() + 1) + '/'
261  + toString(exception.getColumnNumber()) + ").");
262  myError = true;
263 }
264 
265 /****************************************************************************/
#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:72
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.
Definition: OptionsCont.cpp:76
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
Definition: StringUtils.h:146
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.