You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
480 lines
22 KiB
480 lines
22 KiB
#include "src/parser/GspnParser.h"
|
|
|
|
#include <iostream>
|
|
|
|
#include <xercesc/dom/DOM.hpp>
|
|
#include <xercesc/sax/HandlerBase.hpp>
|
|
#include <xercesc/util/PlatformUtils.hpp>
|
|
|
|
#include "src/exceptions/UnexpectedException.h"
|
|
#include "src/storage/gspn/Place.h"
|
|
#include "src/storage/gspn/ImmediateTransition.h"
|
|
#include "src/utility/macros.h"
|
|
|
|
namespace storm {
|
|
namespace parser {
|
|
storm::gspn::GSPN const& GspnParser::parse(std::string const& filename) {
|
|
// initialize parser
|
|
newNode = 0;
|
|
gspn = storm::gspn::GSPN();
|
|
|
|
// initialize xercesc
|
|
try {
|
|
xercesc::XMLPlatformUtils::Initialize();
|
|
}
|
|
catch (xercesc::XMLException const& toCatch) {
|
|
STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Failed to initialize xercesc\n");
|
|
}
|
|
|
|
auto parser = new xercesc::XercesDOMParser();
|
|
parser->setValidationScheme(xercesc::XercesDOMParser::Val_Always);
|
|
parser->setDoNamespaces(false);
|
|
parser->setDoSchema(false);
|
|
parser->setLoadExternalDTD(false);
|
|
parser->setIncludeIgnorableWhitespace(false);
|
|
|
|
auto errHandler = (xercesc::ErrorHandler*) new xercesc::HandlerBase();
|
|
parser->setErrorHandler(errHandler);
|
|
|
|
// parse file
|
|
try {
|
|
parser->parse(filename.c_str());
|
|
}
|
|
catch (xercesc::XMLException const& toCatch) {
|
|
auto message = xercesc::XMLString::transcode(toCatch.getMessage());
|
|
STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, message);
|
|
xercesc::XMLString::release(&message);
|
|
}
|
|
catch (const xercesc::DOMException& toCatch) {
|
|
auto message = xercesc::XMLString::transcode(toCatch.msg);
|
|
STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, message);
|
|
xercesc::XMLString::release(&message);
|
|
}
|
|
catch (...) {
|
|
STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Failed to parse pnml file.\n");
|
|
}
|
|
|
|
// build gspn by traversing the DOM object
|
|
parser->getDocument()->normalizeDocument();
|
|
xercesc::DOMElement* elementRoot = parser->getDocument()->getDocumentElement();
|
|
STORM_LOG_THROW(getName(elementRoot).compare("pnml") == 0, storm::exceptions::UnexpectedException, "Failed to identify the root element.\n");
|
|
traversePnmlElement(elementRoot);
|
|
|
|
// clean up
|
|
delete parser;
|
|
delete errHandler;
|
|
xercesc::XMLPlatformUtils::Terminate();
|
|
|
|
return gspn;
|
|
}
|
|
|
|
void GspnParser::traversePnmlElement(xercesc::DOMElement const* const element) {
|
|
// traverse attributes
|
|
for (uint_fast64_t i = 0; i < element->getAttributes()->getLength(); ++i) {
|
|
auto attr = element->getAttributes()->item(i);
|
|
auto name = getName(attr);
|
|
|
|
STORM_PRINT_AND_LOG("unknown attribute (node=pnml): " + name + "\n");
|
|
}
|
|
|
|
// traverse children
|
|
for (uint_fast64_t i = 0; i < element->getChildNodes()->getLength(); ++i) {
|
|
auto child = element->getChildNodes()->item(i);
|
|
auto name = getName(child);
|
|
|
|
if (name.compare("net") == 0) {
|
|
traverseNetOrPage(child);
|
|
} else if (std::all_of(name.begin(), name.end(), isspace)) {
|
|
// ignore node (contains only whitespace)
|
|
} else {
|
|
STORM_PRINT_AND_LOG("unknown child (node=pnml): " + name + "\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
void GspnParser::traverseNetOrPage(xercesc::DOMNode const* const node) {
|
|
// traverse attributes
|
|
for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
|
|
auto attr = node->getAttributes()->item(i);
|
|
auto name = getName(attr);
|
|
|
|
if (name.compare("id") == 0) {
|
|
gspn.setName(XMLtoString(attr->getNodeValue()));
|
|
} else {
|
|
STORM_PRINT_AND_LOG("unknown attribute (node=" + XMLtoString(node->getNodeName()) + "): " + name + "\n");
|
|
}
|
|
}
|
|
|
|
// traverse children
|
|
for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
|
|
auto child = node->getChildNodes()->item(i);
|
|
auto name = getName(child);
|
|
|
|
if (name.compare("place") == 0) {
|
|
traversePlace(child);
|
|
} else if (name.compare("transition") == 0) {
|
|
traverseTransition(child);
|
|
} else if (name.compare("arc") == 0) {
|
|
traverseArc(child);
|
|
} else if (name.compare("page") == 0) {
|
|
// Some pnml files have a child named page.
|
|
// The page node has the same children like the net node (e.g., place, transition, arc)
|
|
traverseNetOrPage(child);
|
|
} else if (std::all_of(name.begin(), name.end(), isspace)) {
|
|
// ignore node (contains only whitespace)
|
|
} else {
|
|
STORM_PRINT_AND_LOG("unknown child (node=" + XMLtoString(node->getNodeName()) + "): " + name + "\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
void GspnParser::traversePlace(xercesc::DOMNode const* const node) {
|
|
std::string placeName;
|
|
// the first entry is false if the corresponding information was not found in the pnml file
|
|
std::pair<bool, uint_fast64_t> numberOfInitialTokens(false, defaultNumberOfInitialTokens);
|
|
std::pair<bool, int_fast64_t> capacity(false, defaultCapacity);
|
|
|
|
// traverse attributes
|
|
for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
|
|
auto attr = node->getAttributes()->item(i);
|
|
auto name = getName(attr);
|
|
|
|
if (name.compare("id") == 0) {
|
|
placeName = XMLtoString(attr->getNodeValue());
|
|
} else {
|
|
STORM_PRINT_AND_LOG("unknown attribute (node=place): " + name + "\n");
|
|
}
|
|
}
|
|
|
|
// traverse children
|
|
for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
|
|
auto child = node->getChildNodes()->item(i);
|
|
auto name = getName(child);
|
|
|
|
if (name.compare("initialMarking") == 0) {
|
|
numberOfInitialTokens.first = true;
|
|
numberOfInitialTokens.second = traverseInitialMarking(child);
|
|
} else if(name.compare("capacity") == 0) {
|
|
capacity.first = true;
|
|
capacity.second = traverseCapacity(child);
|
|
} else if (std::all_of(name.begin(), name.end(), isspace)) {
|
|
// ignore node (contains only whitespace)
|
|
} else if (name.compare("name") == 0 ||
|
|
name.compare("graphics") == 0) {
|
|
// ignore these tags
|
|
} else {
|
|
STORM_PRINT_AND_LOG("unknown child (node=place): " + name + "\n");
|
|
}
|
|
}
|
|
|
|
// build place and add it to the gspn
|
|
storm::gspn::Place place;
|
|
place.setName(placeName);
|
|
if (!numberOfInitialTokens.first) {
|
|
STORM_PRINT_AND_LOG("unknown numberOfInitialTokens (place=" + placeName + ")\n");
|
|
}
|
|
place.setNumberOfInitialTokens(numberOfInitialTokens.second);
|
|
if (!capacity.first) {
|
|
STORM_PRINT_AND_LOG("unknown capacity (place=" + placeName + ")\n");
|
|
}
|
|
place.setCapacity(capacity.second);
|
|
place.setID(newNode);
|
|
++newNode;
|
|
gspn.addPlace(place);
|
|
}
|
|
|
|
void GspnParser::traverseTransition(xercesc::DOMNode const* const node) {
|
|
// the first entry is false if the corresponding information was not found in the pnml file
|
|
std::pair<bool, bool> timed(false, defaultTransitionType);
|
|
std::pair<bool, std::string> value(false, defaultTransitionValue);
|
|
std::string id;
|
|
|
|
// parse attributes
|
|
for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
|
|
auto attr = node->getAttributes()->item(i);
|
|
auto name = getName(attr);
|
|
|
|
if (name.compare("id") == 0) {
|
|
id = XMLtoString(attr->getNodeValue());
|
|
} else {
|
|
STORM_PRINT_AND_LOG("unknown attribute (node=transition): " + name + "\n");
|
|
}
|
|
}
|
|
|
|
// traverse children
|
|
for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
|
|
auto child = node->getChildNodes()->item(i);
|
|
auto name = getName(child);
|
|
|
|
if (name.compare("rate") == 0) {
|
|
value.first =true;
|
|
value.second = traverseTransitionValue(child);
|
|
} else if (name.compare("timed") == 0) {
|
|
timed.first = true;
|
|
timed.second = traverseTransitionType(child);
|
|
} else if (std::all_of(name.begin(), name.end(), isspace)) {
|
|
// ignore node (contains only whitespace)
|
|
} else if (name.compare("graphics") == 0 ||
|
|
name.compare("name") == 0 ||
|
|
name.compare("orientation") == 0) {
|
|
// ignore these tags
|
|
} else {
|
|
STORM_PRINT_AND_LOG("unknown child (node=transition): " + name + "\n");
|
|
}
|
|
}
|
|
|
|
// build transition and add it to the gspn
|
|
if (!timed.first) {
|
|
STORM_PRINT_AND_LOG("unknown transition type (transition=" + id + ")\n");
|
|
}
|
|
|
|
if (timed.second) {
|
|
storm::gspn::TimedTransition<storm::gspn::GSPN::RateType> transition;
|
|
if (!value.first) {
|
|
STORM_LOG_THROW(false, storm::exceptions::UnexpectedException ,"unknown transition rate (transition=" + id + ")\n");
|
|
}
|
|
transition.setRate(std::stod(value.second));
|
|
transition.setName(id);
|
|
gspn.addTimedTransition(transition);
|
|
} else {
|
|
storm::gspn::ImmediateTransition<storm::gspn::GSPN::WeightType> transition;
|
|
if (!value.first) {
|
|
STORM_PRINT_AND_LOG("unknown transition weight (transition=" + id + ")\n");
|
|
}
|
|
transition.setWeight(std::stod(value.second));
|
|
transition.setName(id);
|
|
gspn.addImmediateTransition(transition);
|
|
}
|
|
}
|
|
|
|
void GspnParser::traverseArc(xercesc::DOMNode const* const node) {
|
|
// the first entry is false if the corresponding information was not found in the pnml file
|
|
std::pair<bool, std::string> source(false, "");
|
|
std::pair<bool, std::string> target(false, "");
|
|
std::pair<bool, std::string> type(false, defaultArcType);
|
|
std::pair<bool, uint_fast64_t> multiplicity(false, defaultMultiplicity);
|
|
std::string id;
|
|
|
|
// parse attributes
|
|
for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
|
|
auto attr = node->getAttributes()->item(i);
|
|
auto name = getName(attr);
|
|
|
|
if (name.compare("source") == 0) {
|
|
source.first = true;
|
|
source.second = XMLtoString(attr->getNodeValue());
|
|
} else if (name.compare("target") == 0) {
|
|
target.first = true;
|
|
target.second = XMLtoString(attr->getNodeValue());
|
|
} else if (name.compare("id") == 0) {
|
|
id = XMLtoString(attr->getNodeValue());
|
|
} else {
|
|
STORM_PRINT_AND_LOG("unknown attribute (node=arc): " + name + "\n");
|
|
}
|
|
}
|
|
|
|
// parse children
|
|
for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
|
|
auto child = node->getChildNodes()->item(i);
|
|
auto name = getName(child);
|
|
if (name.compare("type") == 0) {
|
|
type.first = true;
|
|
type.second = traverseArcType(child);
|
|
} else if(name.compare("inscription") == 0) {
|
|
multiplicity.first = true;
|
|
multiplicity.second = traverseMultiplicity(child);
|
|
} else if (std::all_of(name.begin(), name.end(), isspace)) {
|
|
// ignore node (contains only whitespace)
|
|
} else if (name.compare("graphics") == 0 ||
|
|
name.compare("arcpath") == 0 ||
|
|
name.compare("tagged") == 0) {
|
|
// ignore these tags
|
|
} else {
|
|
STORM_PRINT_AND_LOG("unknown child (node=arc): " + name + "\n");
|
|
}
|
|
}
|
|
|
|
// check if all necessary information where stored in the pnml file
|
|
if (!source.first) {
|
|
STORM_LOG_THROW(false, storm::exceptions::UnexpectedException ,"unknown arc source (arc=" + id + ")\n");
|
|
}
|
|
if (!target.first) {
|
|
STORM_LOG_THROW(false, storm::exceptions::UnexpectedException ,"unknown arc target (arc=" + id + ")\n");
|
|
}
|
|
if (!multiplicity.first) {
|
|
STORM_PRINT_AND_LOG("unknown multiplicity (node=arc): " + id + "\n");
|
|
}
|
|
|
|
//determine if it is an outgoing or incoming arc
|
|
{
|
|
auto place = gspn.getPlace(source.second);
|
|
auto trans = gspn.getTransition(target.second);
|
|
if (true == place.first && true == trans.first) {
|
|
if (!type.first) {
|
|
STORM_PRINT_AND_LOG("unknown arc type (arc=" + id + ")\n");
|
|
}
|
|
|
|
// incoming arc
|
|
if (type.second.compare("normal") == 0) {
|
|
trans.second->setInputArcMultiplicity(place.second, multiplicity.second);
|
|
} else if (type.second.compare("inhibition") == 0) {
|
|
trans.second->setInhibitionArcMultiplicity(place.second, multiplicity.second);
|
|
} else {
|
|
STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "unknown arc type (arc=" + id + ")\n");
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
{
|
|
auto trans = gspn.getTransition(source.second);
|
|
auto place = gspn.getPlace(target.second);
|
|
if (true == place.first && true == trans.first) {
|
|
// outgoing arc
|
|
trans.second->setOutputArcMultiplicity(place.second, multiplicity.second);
|
|
return;
|
|
}
|
|
}
|
|
|
|
STORM_LOG_THROW(false, storm::exceptions::UnexpectedException ,"unknown arc source or target (arc=" + id + ")\n");
|
|
}
|
|
|
|
std::string GspnParser::getName(xercesc::DOMNode *node) {
|
|
switch (node->getNodeType()) {
|
|
case xercesc::DOMNode::NodeType::ELEMENT_NODE: {
|
|
auto elementNode = (xercesc::DOMElement *) node;
|
|
return XMLtoString(elementNode->getTagName());
|
|
}
|
|
case xercesc::DOMNode::NodeType::TEXT_NODE: {
|
|
return XMLtoString(node->getNodeValue());
|
|
}
|
|
case xercesc::DOMNode::NodeType::ATTRIBUTE_NODE: {
|
|
return XMLtoString(node->getNodeName());
|
|
}
|
|
default: {
|
|
STORM_PRINT_AND_LOG("unknown node type \n");
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
|
|
uint_fast64_t GspnParser::traverseInitialMarking(xercesc::DOMNode const* const node) {
|
|
uint_fast64_t result = defaultNumberOfInitialTokens;
|
|
for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
|
|
auto child = node->getChildNodes()->item(i);
|
|
auto name = getName(child);
|
|
if (name.compare("text") == 0) {
|
|
result = std::stoull(getName(child->getFirstChild()));
|
|
} else if (name.compare("value") == 0) {
|
|
auto value = getName(child->getFirstChild());
|
|
value = value.substr(std::string("Default,").length());
|
|
result = std::stoull(value);
|
|
} else if (std::all_of(name.begin(), name.end(), isspace)) {
|
|
// ignore node (contains only whitespace)
|
|
} else if (name.compare("graphics") == 0) {
|
|
// ignore these tags
|
|
} else {
|
|
STORM_PRINT_AND_LOG("unknown child (node=initialMarking): " + name + "\n");
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int_fast64_t GspnParser::traverseCapacity(xercesc::DOMNode const* const node) {
|
|
int_fast64_t result= defaultCapacity;
|
|
for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
|
|
auto child = node->getChildNodes()->item(i);
|
|
auto name = getName(child);
|
|
if (name.compare("value") == 0) {
|
|
auto value = getName(child->getFirstChild());
|
|
if (value.find("Default,") == 0) {
|
|
value = value.substr(std::string("Default,").length());
|
|
}
|
|
result = std::stoull(value);
|
|
} else if (name.compare("graphics") == 0) {
|
|
// ignore these nodes
|
|
} else if (std::all_of(name.begin(), name.end(), isspace)) {
|
|
// ignore node (contains only whitespace)
|
|
} else {
|
|
STORM_PRINT_AND_LOG("unknown child (node=capacity): " + name + "\n");
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
uint_fast64_t GspnParser::traverseMultiplicity(xercesc::DOMNode const* const node) {
|
|
uint_fast64_t result = defaultMultiplicity;
|
|
for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
|
|
auto child = node->getChildNodes()->item(i);
|
|
auto name = getName(child);
|
|
if (name.compare("value") == 0) {
|
|
auto value = getName(child->getFirstChild());
|
|
if (value.find("Default,") == 0) {
|
|
value = value.substr(std::string("Default,").length());
|
|
}
|
|
result = std::stoull(value);
|
|
} else if (name.compare("graphics") == 0) {
|
|
// ignore these nodes
|
|
} else if (std::all_of(name.begin(), name.end(), isspace)) {
|
|
// ignore node (contains only whitespace)
|
|
} else {
|
|
STORM_PRINT_AND_LOG("unknown child (node=inscription): " + name + "\n");
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
std::string GspnParser::traverseTransitionValue(xercesc::DOMNode const* const node) {
|
|
std::string result = defaultTransitionValue;
|
|
for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
|
|
auto child = node->getChildNodes()->item(i);
|
|
auto name = getName(child);
|
|
if (name.compare("value") == 0) {
|
|
result = getName(child->getFirstChild());
|
|
} else if (std::all_of(name.begin(), name.end(), isspace)) {
|
|
// ignore node (contains only whitespace)
|
|
} else {
|
|
STORM_PRINT_AND_LOG("unknown child (node=rate): " + name + "\n");
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool GspnParser::traverseTransitionType(xercesc::DOMNode const* const node) {
|
|
bool result;
|
|
for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
|
|
auto child = node->getChildNodes()->item(i);
|
|
auto name = getName(child);
|
|
if (name.compare("value") == 0) {
|
|
result = getName(child->getFirstChild()).compare("true") == 0 ? true : false;
|
|
} else if (std::all_of(name.begin(), name.end(), isspace)) {
|
|
// ignore node (contains only whitespace)
|
|
} else {
|
|
STORM_PRINT_AND_LOG("unknown child (node=timed): " + name + "\n");
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::string GspnParser::traverseArcType(xercesc::DOMNode const* const node) {
|
|
for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
|
|
auto attr = node->getAttributes()->item(i);
|
|
auto name = getName(attr);
|
|
if (name.compare("value") == 0) {
|
|
return XMLtoString(attr->getNodeValue());
|
|
} else {
|
|
STORM_PRINT_AND_LOG("unknown child (node=type): " + name + "\n");
|
|
}
|
|
}
|
|
return defaultArcType;
|
|
}
|
|
|
|
std::string GspnParser::XMLtoString(const XMLCh *xmlString) {
|
|
char* tmp = xercesc::XMLString::transcode(xmlString);
|
|
auto result = std::string(tmp);
|
|
delete tmp;
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|