Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
PnmlParser.cpp
Go to the documentation of this file.
1
3#ifdef STORM_HAVE_XERCES
4#include <iostream>
5
7
11
12namespace {
13bool isOnlyWhitespace(std::string const& in) {
14 return std::all_of(in.begin(), in.end(), [](char c) { return std::isspace(static_cast<unsigned char>(c)); });
15}
16} // namespace
17namespace storm {
18namespace parser {
19
20storm::gspn::GSPN* PnmlParser::parse(xercesc::DOMElement const* elementRoot) {
21 if (storm::adapters::getName(elementRoot) == "pnml") {
22 traversePnmlElement(elementRoot);
23 } else {
24 // If the top-level node is not a "pnml" or "" node, then throw an exception.
25 STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Failed to identify the root element.\n");
26 }
27 return builder.buildGspn();
28}
29
30void PnmlParser::traversePnmlElement(xercesc::DOMElement const* const element) {
31 // traverse attributes
32 for (uint_fast64_t i = 0; i < element->getAttributes()->getLength(); ++i) {
33 auto attr = element->getAttributes()->item(i);
34 auto name = storm::adapters::getName(attr);
35
36 // Found node or attribute which is at the moment nod handled by this parser.
37 // Notify the user and continue the parsing.
38 STORM_PRINT_AND_LOG("unknown attribute (node=pnml): " + name + "\n");
39 }
40
41 // traverse children
42 for (uint_fast64_t i = 0; i < element->getChildNodes()->getLength(); ++i) {
43 auto child = element->getChildNodes()->item(i);
44 auto name = storm::adapters::getName(child);
45
46 if (name == "net") {
47 traverseNetOrPage(child);
48 } else if (isOnlyWhitespace(name)) {
49 // ignore node (contains only whitespace)
50 } else {
51 // Found node or attribute which is at the moment nod handled by this parser.
52 // Notify the user and continue the parsing.
53 STORM_PRINT_AND_LOG("unknown child (node=pnml): " + name + "\n");
54 }
55 }
56}
57
58void PnmlParser::traverseNetOrPage(xercesc::DOMNode const* const node) {
59 // traverse attributes
60 for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
61 auto attr = node->getAttributes()->item(i);
62 auto name = storm::adapters::getName(attr);
63
64 if (name == "id") {
65 builder.setGspnName(storm::adapters::XMLtoString(attr->getNodeValue()));
66 } else {
67 // Found node or attribute which is at the moment nod handled by this parser.
68 // Notify the user and continue the parsing.
69 STORM_PRINT_AND_LOG("unknown attribute (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
70 }
71 }
72
73 // traverse children
74 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
75 auto child = node->getChildNodes()->item(i);
76 auto name = storm::adapters::getName(child);
77
78 if (name == "place") {
79 traversePlace(child);
80 } else if (name == "transition") {
81 traverseTransition(child);
82 } else if (name == "arc") {
83 traverseArc(child);
84 } else if (name == "page") {
85 // Some pnml files have a child named page.
86 // The page node has the same children like the net node (e.g., place, transition, arc)
87 traverseNetOrPage(child);
88 } else if (isOnlyWhitespace(name)) {
89 // ignore node (contains only whitespace)
90 } else {
91 // Found node or attribute which is at the moment nod handled by this parser.
92 // Notify the user and continue the parsing.
93 STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
94 }
95 }
96}
97
98void PnmlParser::traversePlace(xercesc::DOMNode const* const node) {
99 std::string placeName;
100 // the first entry is false if the corresponding information was not found in the pnml file
101 std::pair<bool, uint_fast64_t> numberOfInitialTokens(false, defaultNumberOfInitialTokens);
102 std::pair<bool, boost::optional<uint64_t>> capacity(false, boost::none);
103
104 // traverse attributes
105 for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
106 auto attr = node->getAttributes()->item(i);
107 auto name = storm::adapters::getName(attr);
108
109 if (name == "id") {
110 placeName = storm::adapters::XMLtoString(attr->getNodeValue());
111 } else {
112 // Found node or attribute which is at the moment nod handled by this parser.
113 // Notify the user and continue the parsing.
114 STORM_PRINT_AND_LOG("unknown attribute (node=place): " + name + "\n");
115 }
116 }
117
118 // traverse children
119 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
120 auto child = node->getChildNodes()->item(i);
121 auto name = storm::adapters::getName(child);
122
123 if (name == "initialMarking") {
124 numberOfInitialTokens.first = true;
125 numberOfInitialTokens.second = traverseInitialMarking(child);
126 } else if (name == "capacity") {
127 capacity.first = true;
128 capacity.second = traverseCapacity(child);
129 } else if (isOnlyWhitespace(name)) {
130 // ignore node (contains only whitespace)
131 } else if (name == "name" || name == "graphics") {
132 // ignore these tags
133 } else {
134 // Found node or attribute which is at the moment nod handled by this parser.
135 // Notify the user and continue the parsing.
136 STORM_PRINT_AND_LOG("unknown child (node=place): " + name + "\n");
137 }
138 }
139
140 if (!numberOfInitialTokens.first) {
141 // no information about the number of initial tokens is found
142 // use the default number of initial tokens
143 STORM_PRINT_AND_LOG("unknown numberOfInitialTokens (place=" + placeName + ")\n");
144 }
145 if (!capacity.first) {
146 // no information about the capacity is found
147 STORM_PRINT_AND_LOG("unknown capacity (place=" + placeName + ")\n");
148 }
149 builder.addPlace(capacity.second, numberOfInitialTokens.first ? numberOfInitialTokens.second : 0, placeName);
150}
151
152void PnmlParser::traverseTransition(xercesc::DOMNode const* const node) {
153 // the first entry is false if the corresponding information was not found in the pnml file
154 std::pair<bool, bool> timed(false, defaultTransitionType);
155 std::pair<bool, std::string> value(false, "");
156 std::string id;
157 uint_fast64_t priority = defaultPriority;
158
159 // parse attributes
160 for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
161 auto attr = node->getAttributes()->item(i);
162 auto name = storm::adapters::getName(attr);
163
164 if (name == "id") {
165 id = storm::adapters::XMLtoString(attr->getNodeValue());
166 } else {
167 // Found node or attribute which is at the moment nod handled by this parser.
168 // Notify the user and continue the parsing.
169 STORM_PRINT_AND_LOG("unknown attribute (node=transition): " + name + "\n");
170 }
171 }
172
173 // traverse children
174 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
175 auto child = node->getChildNodes()->item(i);
176 auto name = storm::adapters::getName(child);
177
178 if (name == "rate") {
179 value.first = true;
180 value.second = traverseTransitionValue(child);
181 } else if (name == "timed") {
182 timed.first = true;
183 timed.second = traverseTransitionType(child);
184 } else if (name == "priority") {
185 priority = traversePriority(child);
186 } else if (isOnlyWhitespace(name)) {
187 // ignore node (contains only whitespace)
188 } else if (name == "graphics" || name == "name" || name == "orientation") {
189 // ignore these tags
190 } else {
191 // Found node or attribute which is at the moment nod handled by this parser.
192 // Notify the user and continue the parsing.
193 STORM_PRINT_AND_LOG("unknown child (node=transition): " + name + "\n");
194 }
195 }
196
197 // build transition and add it to the gspn
198 if (!timed.first) {
199 // found unknown transition type
200 // abort parsing
201 STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "unknown transition type (transition=" + id + ")\n");
202 return;
203 }
204
205 if (timed.second) {
206 if (!value.first) {
207 // no information about the rate is found
208 // abort the parsing
209 STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "unknown transition rate (transition=" + id + ")\n");
210 }
211 builder.addTimedTransition(priority, std::stod(value.second), id);
212 } else {
213 if (!value.first) {
214 // no information about the weight is found
215 // continue with the default weight
216 STORM_PRINT_AND_LOG("unknown transition weight (transition=" + id + ")\n");
217 }
218 builder.addImmediateTransition(priority, std::stod(value.second), id);
219 }
220}
221
222void PnmlParser::traverseArc(xercesc::DOMNode const* const node) {
223 // the first entry is false if the corresponding information was not found in the pnml file
224 std::pair<bool, std::string> source(false, "");
225 std::pair<bool, std::string> target(false, "");
226 std::pair<bool, std::string> type(false, defaultArcType);
227 std::pair<bool, uint_fast64_t> multiplicity(false, defaultMultiplicity);
228 std::string id;
229
230 // parse attributes
231 for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
232 auto attr = node->getAttributes()->item(i);
233 auto name = storm::adapters::getName(attr);
234
235 if (name == "source") {
236 source.first = true;
237 source.second = storm::adapters::XMLtoString(attr->getNodeValue());
238 } else if (name == "target") {
239 target.first = true;
240 target.second = storm::adapters::XMLtoString(attr->getNodeValue());
241 } else if (name == "id") {
242 id = storm::adapters::XMLtoString(attr->getNodeValue());
243 } else {
244 // Found node or attribute which is at the moment nod handled by this parser.
245 // Notify the user and continue the parsing.
246 STORM_PRINT_AND_LOG("unknown attribute (node=arc): " + name + "\n");
247 }
248 }
249
250 // parse children
251 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
252 auto child = node->getChildNodes()->item(i);
253 auto name = storm::adapters::getName(child);
254 if (name == "type") {
255 type.first = true;
256 type.second = traverseArcType(child);
257 } else if (name == "inscription") {
258 multiplicity.first = true;
259 multiplicity.second = traverseMultiplicity(child);
260 } else if (isOnlyWhitespace(name)) {
261 // ignore node (contains only whitespace)
262 } else if (name == "graphics" || name == "arcpath" || name == "tagged") {
263 // ignore these tags
264 } else {
265 // Found node or attribute which is at the moment nod handled by this parser.
266 // Notify the user and continue the parsing.
267 STORM_PRINT_AND_LOG("unknown child (node=arc): " + name + "\n");
268 }
269 }
270
271 // check if all necessary information where stored in the pnml file
272 if (!source.first) {
273 // could not find start of the arc
274 // abort parsing
275 STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "unknown arc source (arc=" + id + ")\n");
276 }
277 if (!target.first) {
278 // could not find the target of the arc
279 // abort parsing
280 STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "unknown arc target (arc=" + id + ")\n");
281 }
282 if (!multiplicity.first) {
283 // no information about the multiplicity of the arc
284 // continue and use the default multiplicity
285 STORM_PRINT_AND_LOG("unknown multiplicity (node=arc): " + id + "\n");
286 }
287
288 if (type.second == "normal") {
289 builder.addNormalArc(source.second, target.second, multiplicity.second);
290 } else if (type.second == "inhibition") {
291 builder.addInhibitionArc(source.second, target.second, multiplicity.second);
292 } else {
293 STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Arc type '" << type.second << "' in arc '" << id << "' is unknown.");
294 }
295}
296
297uint_fast64_t PnmlParser::traverseInitialMarking(xercesc::DOMNode const* const node) {
298 uint_fast64_t result = defaultNumberOfInitialTokens;
299 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
300 auto child = node->getChildNodes()->item(i);
301 auto name = storm::adapters::getName(child);
302 if (name == "text") {
303 result = std::stoull(storm::adapters::getName(child->getFirstChild()));
304 } else if (name == "value") {
305 auto value = storm::adapters::getName(child->getFirstChild());
306 value = value.substr(std::string("Default,").length());
307 result = std::stoull(value);
308 } else if (isOnlyWhitespace(name)) {
309 // ignore node (contains only whitespace)
310 } else if (name == "graphics") {
311 // ignore these tags
312 } else {
313 // Found node or attribute which is at the moment nod handled by this parser.
314 // Notify the user and continue the parsing.
315 STORM_PRINT_AND_LOG("unknown child (node=initialMarking): " + name + "\n");
316 }
317 }
318 return result;
319}
320
321int_fast64_t PnmlParser::traverseCapacity(xercesc::DOMNode const* const node) {
322 int_fast64_t result = defaultCapacity;
323 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
324 auto child = node->getChildNodes()->item(i);
325 auto name = storm::adapters::getName(child);
326 if (name == "value") {
327 auto value = storm::adapters::getName(child->getFirstChild());
328 if (value.find("Default,") == 0) {
329 value = value.substr(std::string("Default,").length());
330 }
331 result = std::stoull(value);
332 } else if (name == "graphics") {
333 // ignore these nodes
334 } else if (isOnlyWhitespace(name)) {
335 // ignore node (contains only whitespace)
336 } else {
337 // Found node or attribute which is at the moment nod handled by this parser.
338 // Notify the user and continue the parsing.
339 STORM_PRINT_AND_LOG("unknown child (node=capacity): " + name + "\n");
340 }
341 }
342 return result;
343}
344
345uint_fast64_t PnmlParser::traverseMultiplicity(xercesc::DOMNode const* const node) {
346 uint_fast64_t result = defaultMultiplicity;
347 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
348 auto child = node->getChildNodes()->item(i);
349 auto name = storm::adapters::getName(child);
350 if (name == "value") {
351 auto value = storm::adapters::getName(child->getFirstChild());
352 if (value.find("Default,") == 0) {
353 value = value.substr(std::string("Default,").length());
354 }
355 result = std::stoull(value);
356 } else if (name == "graphics") {
357 // ignore these nodes
358 } else if (isOnlyWhitespace(name)) {
359 // ignore node (contains only whitespace)
360 } else {
361 // Found node or attribute which is at the moment nod handled by this parser.
362 // Notify the user and continue the parsing.
363 STORM_PRINT_AND_LOG("unknown child (node=inscription): " + name + "\n");
364 }
365 }
366 return result;
367}
368
369std::string PnmlParser::traverseTransitionValue(xercesc::DOMNode const* const node) {
370 std::string result;
371 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
372 auto child = node->getChildNodes()->item(i);
373 auto name = storm::adapters::getName(child);
374 if (name == "value") {
375 result = storm::adapters::getName(child->getFirstChild());
376 } else if (isOnlyWhitespace(name)) {
377 // ignore node (contains only whitespace)
378 } else {
379 // Found node or attribute which is at the moment nod handled by this parser.
380 // Notify the user and continue the parsing.
381 STORM_PRINT_AND_LOG("unknown child (node=rate): " + name + "\n");
382 }
383 }
384 return result;
385}
386
387bool PnmlParser::traverseTransitionType(xercesc::DOMNode const* const node) {
388 bool result;
389 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
390 auto child = node->getChildNodes()->item(i);
391 auto name = storm::adapters::getName(child);
392 if (name == "value") {
393 result = storm::adapters::getName(child->getFirstChild()) == "true" ? true : false;
394 } else if (isOnlyWhitespace(name)) {
395 // ignore node (contains only whitespace)
396 } else {
397 // Found node or attribute which is at the moment nod handled by this parser.
398 // Notify the user and continue the parsing.
399 STORM_PRINT_AND_LOG("unknown child (node=timed): " + name + "\n");
400 }
401 }
402 return result;
403}
404
405std::string PnmlParser::traverseArcType(xercesc::DOMNode const* const node) {
406 for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
407 auto attr = node->getAttributes()->item(i);
408 auto name = storm::adapters::getName(attr);
409 if (name == "value") {
410 return storm::adapters::XMLtoString(attr->getNodeValue());
411 } else {
412 // Found node or attribute which is at the moment nod handled by this parser.
413 // Notify the user and continue the parsing.
414 STORM_PRINT_AND_LOG("unknown child (node=type): " + name + "\n");
415 }
416 }
417 return defaultArcType;
418}
419
420uint_fast64_t PnmlParser::traversePriority(xercesc::DOMNode const* const node) {
421 uint_fast64_t result = defaultPriority;
422 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
423 auto child = node->getChildNodes()->item(i);
424 auto name = storm::adapters::getName(child);
425 if (name == "text") {
426 result = std::stoull(storm::adapters::getName(child->getFirstChild()));
427 } else if (name == "value") {
428 auto value = storm::adapters::getName(child->getFirstChild());
429 value = value.substr(std::string("Default,").length());
430 result = std::stoull(value);
431 } else if (isOnlyWhitespace(name)) {
432 // ignore node (contains only whitespace)
433 } else if (name == "graphics") {
434 // ignore these tags
435 } else {
436 // Found node or attribute which is at the moment nod handled by this parser.
437 // Notify the user and continue the parsing.
438 STORM_PRINT_AND_LOG("unknown child (node=priority): " + name + "\n");
439 }
440 }
441 return result;
442}
443} // namespace parser
444} // namespace storm
445
446#endif
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
#define STORM_PRINT_AND_LOG(message)
Definition macros.h:68
LabParser.cpp.
Definition cli.cpp:18