#include "GreatSpnEditorProjectParser.h" #ifdef USE_XERCES #include <iostream> #include "src/adapters/XercesAdapter.h" #include "src/exceptions/UnexpectedException.h" #include "src/exceptions/WrongFormatException.h" #include "src/utility/macros.h" namespace storm { namespace parser { storm::gspn::GSPN* GreatSpnEditorProjectParser::parse(xercesc::DOMElement const* elementRoot) { if (storm::adapters::XMLtoString(elementRoot->getTagName()) == "project") { GreatSpnEditorProjectParser p; return p.parse(elementRoot); } else { // If the top-level node is not a "pnml" or "" node, then throw an exception. STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Failed to identify the root element.\n"); } } void GreatSpnEditorProjectParser::traverseProjectElement(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 = storm::adapters::getName(attr); if (name.compare("version") == 0 || name.compare("name") == 0) { // ignore node (contains only whitespace) } else { // Found node or attribute which is at the moment not handled by this parser. // Notify the user and continue the parsing. STORM_PRINT_AND_LOG("unknown attribute (node=" + storm::adapters::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 = storm::adapters::getName(child); if (name.compare("gspn") == 0) { traverseGspnElement(child); } else if (std::all_of(name.begin(), name.end(), isspace)) { // ignore node (contains only whitespace) } else { // Found node or attribute which is at the moment nod handled by this parser. // Notify the user and continue the parsing. STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n"); } } } void GreatSpnEditorProjectParser::traverseGspnElement(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 = storm::adapters::getName(attr); if (name.compare("name") == 0) { builder.setGspnName(storm::adapters::XMLtoString(attr->getNodeValue())); } else if (name.compare("show-color-cmd") == 0 || name.compare("show-fluid-cmd") == 0) { // ignore node } else { // Found node or attribute which is at the moment not handled by this parser. // Notify the user and continue the parsing. STORM_PRINT_AND_LOG( "unknown attribute (node=" + storm::adapters::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 = storm::adapters::getName(child); if (name.compare("nodes") == 0) { traverseNodesElement(child); } else if (name.compare("edges") == 0) { traverseEdgesElement(child); } else if (std::all_of(name.begin(), name.end(), isspace)) { // ignore node (contains only whitespace) } else { // Found node or attribute which is at the moment nod handled by this parser. // Notify the user and continue the parsing. STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n"); } } } void GreatSpnEditorProjectParser::traverseNodesElement(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 = storm::adapters::getName(attr); // Found node or attribute which is at the moment not handled by this parser. // Notify the user and continue the parsing. STORM_PRINT_AND_LOG("unknown attribute (node=" + storm::adapters::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 = storm::adapters::getName(child); if (name.compare("place") == 0) { traversePlaceElement(child); } else if(name.compare("transition") == 0) { traverseTransitionElement(child); } else if (std::all_of(name.begin(), name.end(), isspace)) { // ignore node (contains only whitespace) } else { // Found node or attribute which is at the moment nod handled by this parser. // Notify the user and continue the parsing. STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n"); } } } void GreatSpnEditorProjectParser::traverseEdgesElement(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 = storm::adapters::getName(attr); // Found node or attribute which is at the moment not handled by this parser. // Notify the user and continue the parsing. STORM_PRINT_AND_LOG("unknown attribute (node=" + storm::adapters::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 = storm::adapters::getName(child); if (name.compare("arc") == 0) { traverseArcElement(child); } else if (std::all_of(name.begin(), name.end(), isspace)) { // ignore node (contains only whitespace) } else { // Found node or attribute which is at the moment nod handled by this parser. // Notify the user and continue the parsing. STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n"); } } } bool ignorePlaceAttribute(std::string const& name) { // TODO we should probably not ignore x-servers but check that it is 0.5. if ((name == "label-x") || (name == "label-y") || (name == "x") || (name == "y")) { return true; } return false; } void GreatSpnEditorProjectParser::traversePlaceElement(xercesc::DOMNode const* const node) { // traverse attributes std::string placeName; uint64_t initialTokens = 0; for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) { auto attr = node->getAttributes()->item(i); auto name = storm::adapters::getName(attr); if (name.compare("name") == 0) { placeName = storm::adapters::XMLtoString(attr->getNodeValue()); } else if (name.compare("marking") == 0) { initialTokens = std::stoull(storm::adapters::XMLtoString(attr->getNodeValue())); } else if (ignorePlaceAttribute(name)) { // ignore node } else { // Found node or attribute which is at the moment not handled by this parser. // Notify the user and continue the parsing. STORM_PRINT_AND_LOG( "unknown attribute (node=" + storm::adapters::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 = storm::adapters::getName(child); if (std::all_of(name.begin(), name.end(), isspace)) { // ignore node (contains only whitespace) } else { // Found node or attribute which is at the moment nod handled by this parser. // Notify the user and continue the parsing. STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n"); } } builder.addPlace(-1, initialTokens, placeName); } bool ignoreTransitionAttribute(std::string const& name) { // TODO we should probably not ignore x-servers but check that it is 0.5. if ((name == "label-x") || (name == "label-y") || (name == "x") || (name == "y") || (name == "nservers-x")) { return true; } return false; } void GreatSpnEditorProjectParser::traverseTransitionElement(xercesc::DOMNode const* const node) { std::string transitionName; bool immediateTransition; double rate = 1.0; // The default rate in GreatSPN. // traverse attributes for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) { auto attr = node->getAttributes()->item(i); auto name = storm::adapters::getName(attr); if (name.compare("name") == 0) { transitionName = storm::adapters::XMLtoString(attr->getNodeValue()); } else if (name.compare("type") == 0) { if (storm::adapters::XMLtoString(attr->getNodeValue()).compare("EXP") == 0) { immediateTransition = false; } else { immediateTransition = true; } } else if(name.compare("delay") == 0) { rate = std::stod(storm::adapters::XMLtoString(attr->getNodeValue())); } else if (ignoreTransitionAttribute(name)) { // ignore node } else { // Found node or attribute which is at the moment not handled by this parser. // Notify the user and continue the parsing. STORM_PRINT_AND_LOG( "unknown attribute (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n"); } } if (immediateTransition) { builder.addImmediateTransition(0, 0, transitionName); } else { builder.addTimedTransition(0, rate, transitionName); } // traverse children for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) { auto child = node->getChildNodes()->item(i); auto name = storm::adapters::getName(child); if (std::all_of(name.begin(), name.end(), isspace)) { // ignore node (contains only whitespace) } else { // Found node or attribute which is at the moment nod handled by this parser. // Notify the user and continue the parsing. STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n"); } } } bool ignoreArcAttribute(std::string const& name) { if ((name == "mult-x") || (name == "mult-y") || (name == "mult-k")) { return true; } return false; } bool ignoreArcChild(std::string const& name) { if (name == "point") { return true; } return false; } void GreatSpnEditorProjectParser::traverseArcElement(xercesc::DOMNode const* const node) { std::string head = "____NOT_SET____"; std::string tail = "____NOT_SET____"; std::string kind = "____NOT_SET____"; uint_fast64_t mult = 1; // traverse attributes for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) { auto attr = node->getAttributes()->item(i); auto name = storm::adapters::getName(attr); if (name.compare("head") == 0) { head = storm::adapters::XMLtoString(attr->getNodeValue()); } else if (name.compare("tail") == 0) { tail = storm::adapters::XMLtoString(attr->getNodeValue()); } else if (name.compare("kind") == 0) { kind = storm::adapters::XMLtoString(attr->getNodeValue()); } else if (name.compare("mult") == 0) { mult = std::stoull(storm::adapters::XMLtoString(attr->getNodeValue())); } else if (ignoreArcAttribute(name)) { // ignore node } else { // Found node or attribute which is at the moment not handled by this parser. // Notify the user and continue the parsing. STORM_PRINT_AND_LOG( "unknown attribute (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n"); } } STORM_LOG_THROW(head.compare("____NOT_SET____") != 0, storm::exceptions::WrongFormatException, "Arc must have a head"); STORM_LOG_THROW(tail.compare("____NOT_SET____") != 0, storm::exceptions::WrongFormatException, "Arc must have a tail"); STORM_LOG_THROW(kind.compare("____NOT_SET____") != 0, storm::exceptions::WrongFormatException, "Arc must have a kind"); if (kind.compare("INPUT") == 0) { builder.addInputArc(head, tail, mult); } else if (kind.compare("INHIBITOR") == 0) { builder.addInhibitionArc(head, tail, mult); } else if (kind.compare("OUTPUT") == 0) { builder.addOutputArc(head, tail, mult); } else { // TODO error! } // traverse children for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) { auto child = node->getChildNodes()->item(i); auto name = storm::adapters::getName(child); if (std::all_of(name.begin(), name.end(), isspace)) { // ignore node (contains only whitespace) } else if(ignoreArcChild(name)) { // ignore } else { // Found node or attribute which is at the moment nod handled by this parser. // Notify the user and continue the parsing. STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n"); } } } } } #endif