From f64620e28a55dbddaeeefef2e7b8a6a433f21c82 Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Sun, 31 Mar 2013 01:41:48 +0100 Subject: Implemented fromDOM and various bug fisex for official tests --- apps/mmi-browser.cpp | 5 +- src/uscxml/Interpreter.cpp | 215 ++++++++++++++------- src/uscxml/Interpreter.h | 22 ++- src/uscxml/interpreter/InterpreterDraft6.cpp | 17 +- src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp | 18 +- 5 files changed, 187 insertions(+), 90 deletions(-) diff --git a/apps/mmi-browser.cpp b/apps/mmi-browser.cpp index ef813af..56d7f02 100644 --- a/apps/mmi-browser.cpp +++ b/apps/mmi-browser.cpp @@ -57,7 +57,9 @@ int main(int argc, char** argv) { } bool verbose = false; - + google::InitGoogleLogging(argv[0]); + google::LogToStderr(); + #ifndef _WIN32 opterr = 0; #endif @@ -85,6 +87,7 @@ int main(int argc, char** argv) { // std::cout << argv[i] << std::endl; // std::cout << optind << std::endl; + LOG(INFO) << "Processing " << argv[optind]; Interpreter* interpreter = Interpreter::fromURI(argv[optind]); if (interpreter) { interpreter->setCmdLineOptions(argc, argv); diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index 37f2b77..482a42c 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -51,11 +51,9 @@ Interpreter::Interpreter() { #endif } -Interpreter* Interpreter::fromDOM(const Arabica::DOM::Node& node) { - Arabica::DOM::DOMImplementation domFactory = Arabica::SimpleDOM::DOMImplementation::getDOMImplementation(); +Interpreter* Interpreter::fromDOM(const Arabica::DOM::Document& dom) { Interpreter* interpreter = new InterpreterDraft6(); - interpreter->_document = domFactory.createDocument("http://www.w3.org/2005/07/scxml", "scxml", 0); - interpreter->_document.appendChild(node); + interpreter->_document = dom; return interpreter; } @@ -263,14 +261,11 @@ void Interpreter::init() { // setup xpath and check that it works _xpath.setNamespaceContext(_nsContext); - Arabica::XPath::NodeSet scxmls = _xpath.evaluate("/" + _xpathPrefix + "scxml", _document).asNodeSet(); - assert(scxmls.size() > 0); - assert(scxmls[0] == _scxml); if (_name.length() == 0) _name = (HAS_ATTR(_scxml, "name") ? ATTR(_scxml, "name") : getUUID()); - normalize(_document); + normalize(_scxml); if (_capabilities & CAN_GENERIC_HTTP) _httpServlet = new InterpreterServlet(this); @@ -281,13 +276,15 @@ void Interpreter::init() { } else { LOG(ERROR) << "Cannot find SCXML element" << std::endl; } + } else { + LOG(ERROR) << "Interpreter has no DOM at all!" << std::endl; } _isInitialized = true; } -void Interpreter::normalize(const Arabica::DOM::Document& node) { +void Interpreter::normalize(Arabica::DOM::Element& scxml) { // make sure every state has an id and set isFirstEntry to true - Arabica::XPath::NodeSet states = _xpath.evaluate("//" + _xpathPrefix + "state", _document).asNodeSet(); + Arabica::XPath::NodeSet states = _xpath.evaluate("//" + _xpathPrefix + "state", _scxml).asNodeSet(); for (int i = 0; i < states.size(); i++) { Arabica::DOM::Element stateElem = Arabica::DOM::Element(states[i]); stateElem.setAttribute("isFirstEntry", "true"); @@ -297,7 +294,7 @@ void Interpreter::normalize(const Arabica::DOM::Document& node) { } // make sure every invoke has an idlocation or id - Arabica::XPath::NodeSet invokes = _xpath.evaluate("//" + _xpathPrefix + "invoke", _document).asNodeSet(); + Arabica::XPath::NodeSet invokes = _xpath.evaluate("//" + _xpathPrefix + "invoke", _scxml).asNodeSet(); for (int i = 0; i < invokes.size(); i++) { Arabica::DOM::Element invokeElem = Arabica::DOM::Element(invokes[i]); if (!invokeElem.hasAttribute("id") && !invokeElem.hasAttribute("idlocation")) { @@ -311,7 +308,7 @@ void Interpreter::normalize(const Arabica::DOM::Document& node) { // } } - Arabica::XPath::NodeSet finals = _xpath.evaluate("//" + _xpathPrefix + "final", _document).asNodeSet(); + Arabica::XPath::NodeSet finals = _xpath.evaluate("//" + _xpathPrefix + "final", _scxml).asNodeSet(); for (int i = 0; i < finals.size(); i++) { Arabica::DOM::Element finalElem = Arabica::DOM::Element(finals[i]); finalElem.setAttribute("isFirstEntry", "true"); @@ -320,7 +317,7 @@ void Interpreter::normalize(const Arabica::DOM::Document& node) { } } - Arabica::XPath::NodeSet histories = _xpath.evaluate("//" + _xpathPrefix + "history", _document).asNodeSet(); + Arabica::XPath::NodeSet histories = _xpath.evaluate("//" + _xpathPrefix + "history", _scxml).asNodeSet(); for (int i = 0; i < histories.size(); i++) { Arabica::DOM::Element historyElem = Arabica::DOM::Element(histories[i]); if (!historyElem.hasAttribute("id")) { @@ -328,9 +325,8 @@ void Interpreter::normalize(const Arabica::DOM::Document& node) { } } - Arabica::XPath::NodeSet scxml = _xpath.evaluate("/" + _xpathPrefix + "scxml", _document).asNodeSet(); - if (!((Arabica::DOM::Element)scxml[0]).hasAttribute("id")) { - ((Arabica::DOM::Element)scxml[0]).setAttribute("id", getUUID()); + if (!scxml.hasAttribute("id")) { + scxml.setAttribute("id", getUUID()); } // create a pseudo initial and transition element @@ -440,9 +436,7 @@ void Interpreter::send(const Arabica::DOM::Node& element) { } try { // id - if (HAS_ATTR(element, "idlocation") && _dataModel) { - sendReq.sendid = _dataModel.evalAsString(ATTR(element, "idlocation")); - } else if (HAS_ATTR(element, "id")) { + if (HAS_ATTR(element, "id")) { sendReq.sendid = ATTR(element, "id"); } else { /* @@ -456,15 +450,19 @@ void Interpreter::send(const Arabica::DOM::Node& element) { * details. The SCXML processor may generate all other ids in any format, * as long as they are unique. */ + + /** + * + * If 'idlocation' is present, the SCXML Processor must generate an id when + * the parent element is evaluated and store it in this location. + * See 3.14 IDs for details. + * + */ sendReq.sendid = getUUID(); + if (HAS_ATTR(element, "idlocation") && _dataModel) { + _dataModel.assign(ATTR(element, "idlocation"), "'" + sendReq.sendid + "'"); + } } - /** @TODO: - * - * If 'idlocation' is present, the SCXML Processor must generate an id when - * the parent element is evaluated and store it in this location. - * See 3.14 IDs for details. - * - */ } catch (Event e) { LOG(ERROR) << "Syntax error in send element idlocation:" << std::endl << e << std::endl; return; @@ -535,8 +533,10 @@ void Interpreter::send(const Arabica::DOM::Node& element) { continue; } std::string paramKey = ATTR(params[i], "name"); - boost::algorithm::to_lower(paramKey); - sendReq.params.insert(std::make_pair(paramKey, paramValue)); + // use lower case parameter name in params - this is at least something to think about again + std::string lcParamKey = paramKey; + boost::algorithm::to_lower(lcParamKey); + sendReq.params.insert(std::make_pair(lcParamKey, paramValue)); sendReq.data.compound[paramKey] = Data(paramValue, Data::VERBATIM); } } catch (Event e) { @@ -670,11 +670,6 @@ void Interpreter::delayedSend(void* userdata, std::string eventName) { void Interpreter::invoke(const Arabica::DOM::Node& element) { InvokeRequest invokeReq; - Arabica::DOM::DOMImplementation domFactory = Arabica::SimpleDOM::DOMImplementation::getDOMImplementation(); - invokeReq.dom = domFactory.createDocument(element.getNamespaceURI(), "", 0); - Node newNode = invokeReq.dom.importNode(element, true); - invokeReq.dom.appendChild(newNode); - try { // type if (HAS_ATTR(element, "typeexpr") && _dataModel) { @@ -754,11 +749,68 @@ void Interpreter::invoke(const Arabica::DOM::Node& element) { } // content - NodeSet contents = filterChildElements(_xmlNSPrefix + "content", element); - if (contents.size() > 1) - LOG(ERROR) << "Only a single content element is allowed for send elements - using first one"; - if (contents.size() > 0) { - invokeReq.content = contents[0].getNodeValue(); + try { + + // content + NodeSet contents = filterChildElements(_xmlNSPrefix + "content", element); + if (contents.size() > 1) + LOG(ERROR) << "Only a single content element is allowed for send elements - using first one"; + if (contents.size() > 0) { + if (HAS_ATTR(contents[0], "expr")) { + if (_dataModel) { + /// this is out of spec + std::string contentValue = _dataModel.evalAsString(ATTR(contents[0], "expr")); + invokeReq.content = contentValue; + // sendReq.data.atom = contentValue; + // sendReq.data.type = Data::VERBATIM; + } else { + LOG(ERROR) << "content element has expr attribute but no datamodel is specified."; + } + } else if (contents[0].hasChildNodes()) { + bool presentAsDOM = false; + NodeList contentChilds = contents[0].getChildNodes(); + for (int i = 0; i < contentChilds.getLength(); i++) { + if (contentChilds.item(i).getNodeType() == Node_base::ELEMENT_NODE) { + presentAsDOM = true; + break; + } + } + if (presentAsDOM) { + // use the whole dom + Arabica::DOM::DOMImplementation domFactory = Arabica::SimpleDOM::DOMImplementation::getDOMImplementation(); + invokeReq.dom = domFactory.createDocument(contents[0].getNamespaceURI(), "", 0); + Node newNode = invokeReq.dom.importNode(contents[0], true); + invokeReq.dom.appendChild(newNode); + } else { + Node textChild = contents[0].getFirstChild(); + while(textChild && textChild.getNodeType() != Node_base::TEXT_NODE) { + textChild = textChild.getNextSibling(); + } + if (textChild && textChild.getNodeType() == Node_base::TEXT_NODE) { + /// create space normalized string + std::istringstream iss(contents[0].getFirstChild().getNodeValue()); + std::stringstream content; + std::string seperator; + do { + std::string token; + iss >> token; + if (token.length() > 0) { + content << seperator << token; + seperator = " "; + } + } while (iss); + invokeReq.content = content.str(); + } else { + LOG(ERROR) << "content element has neither text nor element children."; + } + } + } else { + LOG(ERROR) << "content element does not specify any content."; + } + } + } catch (Event e) { + LOG(ERROR) << "Syntax error in send element content:" << std::endl << e << std::endl; + return; } Invoker invoker(Factory::createInvoker(invokeReq.type, this)); @@ -881,23 +933,23 @@ bool Interpreter::hasConditionMatch(const Arabica::DOM::Node& condi } -void Interpreter::executeContent(const NodeList& content) { +void Interpreter::executeContent(const NodeList& content, bool rethrow) { for (unsigned int i = 0; i < content.getLength(); i++) { if (content.item(i).getNodeType() != Node_base::ELEMENT_NODE) continue; - executeContent(content.item(i)); + executeContent(content.item(i), rethrow); } } -void Interpreter::executeContent(const NodeSet& content) { +void Interpreter::executeContent(const NodeSet& content, bool rethrow) { for (unsigned int i = 0; i < content.size(); i++) { if (content[i].getNodeType() != Node_base::ELEMENT_NODE) continue; - executeContent(content[i]); + executeContent(content[i], rethrow); } } -void Interpreter::executeContent(const Arabica::DOM::Node& content) { +void Interpreter::executeContent(const Arabica::DOM::Node& content, bool rethrow) { if (content.getNodeType() != Node_base::ELEMENT_NODE) return; @@ -909,7 +961,7 @@ void Interpreter::executeContent(const Arabica::DOM::Node& content) // --- CONVENIENCE LOOP -------------------------- NodeList executable = content.getChildNodes(); for (int i = 0; i < executable.getLength(); i++) { - executeContent(executable.item(i)); + executeContent(executable.item(i), rethrow); } } else if (boost::iequals(TAGNAME(content), _xmlNSPrefix + "raise")) { // --- RAISE -------------------------- @@ -946,7 +998,7 @@ void Interpreter::executeContent(const Arabica::DOM::Node& content) } } else { if (blockIsTrue) { - executeContent(childs.item(i)); + executeContent(childs.item(i), rethrow); } } } @@ -965,30 +1017,37 @@ void Interpreter::executeContent(const Arabica::DOM::Node& content) uint32_t iterations = 0; try { iterations = _dataModel.getLength(array); - try { - _dataModel.pushContext(); // copy old and enter new context - for (uint32_t iteration = 0; iteration < iterations; iteration++) { - { - // assign array element to item - std::stringstream ss; - ss << array << "[" << iteration << "]"; - _dataModel.assign(item, ss.str()); - } - if (index.length() > 0) { - // assign iteration element to index - std::stringstream ss; - ss << iteration; - _dataModel.assign(index,ss.str()); - } - if (content.hasChildNodes()) - executeContent(content.getChildNodes()); + } catch (Event e) { + LOG(ERROR) << "Syntax error in array attribute of foreach element:" << std::endl << e << std::endl; + if (rethrow) + throw e; + return; + } + try { + _dataModel.pushContext(); // copy old and enter new context + for (uint32_t iteration = 0; iteration < iterations; iteration++) { + { + // assign array element to item + std::stringstream ss; + ss << array << "[" << iteration << "]"; + _dataModel.assign(item, ss.str()); } - _dataModel.popContext(); // leave stacked context - } catch (Event e) { - LOG(ERROR) << "Syntax error in foreach element:" << std::endl << e << std::endl; + if (index.length() > 0) { + // assign iteration element to index + std::stringstream ss; + ss << iteration; + _dataModel.assign(index,ss.str()); + } + if (content.hasChildNodes()) + // execute content and have exception rethrown to break foreach + executeContent(content.getChildNodes(), true); } + _dataModel.popContext(); // leave stacked context } catch (Event e) { - LOG(ERROR) << "Syntax error in array attribute of foreach element:" << std::endl << e << std::endl; + _dataModel.popContext(); // leave stacked context even when exception was thrown + LOG(ERROR) << "Syntax error in foreach element:" << std::endl << e << std::endl; + if (rethrow) + throw e; } } else { LOG(ERROR) << "Expected array and item attributes with foreach element!" << std::endl; @@ -1003,6 +1062,8 @@ void Interpreter::executeContent(const Arabica::DOM::Node& content) std::cout << _dataModel.evalAsString(logElem.getAttribute("expr")) << std::endl; } catch (Event e) { LOG(ERROR) << "Syntax error in expr attribute of log element:" << std::endl << e << std::endl; + if (rethrow) + throw e; } } else { std::cout << logElem.getAttribute("expr") << std::endl; @@ -1015,6 +1076,8 @@ void Interpreter::executeContent(const Arabica::DOM::Node& content) _dataModel.assign(ATTR(content, "location"), ATTR(content, "expr")); } catch (Event e) { LOG(ERROR) << "Syntax error in attributes of assign element:" << std::endl << e << std::endl; + if (rethrow) + throw e; } } } else if (boost::iequals(TAGNAME(content), _xmlNSPrefix + "validate")) { @@ -1047,6 +1110,8 @@ void Interpreter::executeContent(const Arabica::DOM::Node& content) _dataModel.eval(srcContent.str()); } catch (Event e) { LOG(ERROR) << "Syntax error while executing script element from '" << ATTR(content, "src") << "':" << std::endl << e << std::endl; + if (rethrow) + throw e; } } else { if (content.hasChildNodes()) { @@ -1056,6 +1121,8 @@ void Interpreter::executeContent(const Arabica::DOM::Node& content) _dataModel.eval(content.getFirstChild().getNodeValue()); } catch (Event e) { LOG(ERROR) << "Syntax error while executing script element" << std::endl << e << std::endl; + if (rethrow) + throw e; } } } @@ -1080,6 +1147,8 @@ void Interpreter::executeContent(const Arabica::DOM::Node& content) } catch (Event e) { LOG(ERROR) << "Syntax error while executing cancel element" << std::endl << e << std::endl; + if (rethrow) + throw e; } } else if (boost::iequals(TAGNAME(content), _xmlNSPrefix + "invoke")) { @@ -1102,7 +1171,7 @@ void Interpreter::executeContent(const Arabica::DOM::Node& content) if (execContent.processChildren()) { NodeList executable = content.getChildNodes(); for (int i = 0; i < executable.getLength(); i++) { - executeContent(executable.item(i)); + executeContent(executable.item(i), rethrow); } } execContent.exitElement(content); @@ -1221,22 +1290,22 @@ Arabica::DOM::Node Interpreter::getState(const std::string& stateId } // first try atomic and compund states - NodeSet target = _xpath.evaluate("//" + _xpathPrefix + "state[@id='" + stateId + "']", _document).asNodeSet(); + NodeSet target = _xpath.evaluate("//" + _xpathPrefix + "state[@id='" + stateId + "']", _scxml).asNodeSet(); if (target.size() > 0) goto FOUND; // now parallel states - target = _xpath.evaluate("//" + _xpathPrefix + "parallel[@id='" + stateId + "']", _document).asNodeSet(); + target = _xpath.evaluate("//" + _xpathPrefix + "parallel[@id='" + stateId + "']", _scxml).asNodeSet(); if (target.size() > 0) goto FOUND; // now final states - target = _xpath.evaluate("//" + _xpathPrefix + "final[@id='" + stateId + "']", _document).asNodeSet(); + target = _xpath.evaluate("//" + _xpathPrefix + "final[@id='" + stateId + "']", _scxml).asNodeSet(); if (target.size() > 0) goto FOUND; // now history states - target = _xpath.evaluate("//" + _xpathPrefix + "history[@id='" + stateId + "']", _document).asNodeSet(); + target = _xpath.evaluate("//" + _xpathPrefix + "history[@id='" + stateId + "']", _scxml).asNodeSet(); if (target.size() > 0) goto FOUND; @@ -1267,9 +1336,7 @@ Arabica::DOM::Node Interpreter::getSourceState(const Arabica::DOM:: */ Arabica::XPath::NodeSet Interpreter::getInitialStates(Arabica::DOM::Node state) { if (!state) { - state = _document.getFirstChild(); - while(state && !isState(state)) - state = state.getNextSibling(); + state = _scxml; } #if VERBOSE diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index 7a0301c..9443a05 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -93,7 +93,7 @@ public: virtual ~Interpreter(); - static Interpreter* fromDOM(const Arabica::DOM::Node& node); + static Interpreter* fromDOM(const Arabica::DOM::Document& dom); static Interpreter* fromXML(const std::string& xml); static Interpreter* fromURI(const std::string& uri); static Interpreter* fromInputSource(Arabica::SAX::InputSource& source); @@ -107,6 +107,7 @@ public: return _running || !_done; } + /// This one ought to be pure, but SWIG will generate gibberish if it is virtual void interpret() {}; void addMonitor(InterpreterMonitor* monitor) { @@ -140,10 +141,10 @@ public: void setParentQueue(uscxml::concurrency::BlockingQueue* parentQueue) { _parentQueue = parentQueue; } - std::string getXPathPrefix() { + std::string getXPathPrefix() { return _xpathPrefix; } - std::string getXMLPrefix() { + std::string getXMLPrefix() { return _xmlNSPrefix; } Arabica::XPath::StandardNamespaceContext& getNSContext() { @@ -155,14 +156,14 @@ public: return ""; } - void receive(const Event& event, bool toFront = false) { + void receive(const Event& event, bool toFront = false) { if (toFront) { _externalQueue.push_front(event); } else { _externalQueue.push(event); } } - void receiveInternal(const Event& event) { + void receiveInternal(const Event& event) { _internalQueue.push_back(event); } @@ -184,7 +185,7 @@ public: return _document; } - void setCapabilities(unsigned int capabilities) { + void setCapabilities(unsigned int capabilities) { _capabilities = capabilities; } @@ -232,7 +233,7 @@ protected: Interpreter(); void init(); - void normalize(const Arabica::DOM::Document& node); + void normalize(Arabica::DOM::Element& scxml); void setupIOProcessors(); bool _stable; @@ -271,9 +272,9 @@ protected: static URL toBaseURI(const URL& url); - void executeContent(const Arabica::DOM::Node& content); - void executeContent(const Arabica::DOM::NodeList& content); - void executeContent(const Arabica::XPath::NodeSet& content); + void executeContent(const Arabica::DOM::Node& content, bool rethrow = false); + void executeContent(const Arabica::DOM::NodeList& content, bool rethrow = false); + void executeContent(const Arabica::XPath::NodeSet& content, bool rethrow = false); void send(const Arabica::DOM::Node& element); void invoke(const Arabica::DOM::Node& element); @@ -311,6 +312,7 @@ protected: std::map _cachedURLs; friend class SCXMLParser; + friend class USCXMLInvoker; }; } diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp index 18a42fd..7e32ef8 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.cpp +++ b/src/uscxml/interpreter/InterpreterDraft6.cpp @@ -47,7 +47,7 @@ void InterpreterDraft6::interpret() { if (_dataModel && _binding == EARLY) { // initialize all data elements - NodeSet dataElems = _xpath.evaluate("//" + _xpathPrefix + "data", _document).asNodeSet(); + NodeSet dataElems = _xpath.evaluate("//" + _xpathPrefix + "data", _scxml).asNodeSet(); for (unsigned int i = 0; i < dataElems.size(); i++) { initializeData(dataElems[i]); } @@ -60,7 +60,7 @@ void InterpreterDraft6::interpret() { } // executeGlobalScriptElements - NodeSet globalScriptElems = _xpath.evaluate("/" + _xpathPrefix + "scxml/" + _xpathPrefix + "script", _document).asNodeSet(); + NodeSet globalScriptElems = _xpath.evaluate("/" + _xpathPrefix + "script", _scxml).asNodeSet(); for (unsigned int i = 0; i < globalScriptElems.size(); i++) { if (_dataModel) executeContent(globalScriptElems[i]); @@ -70,7 +70,7 @@ void InterpreterDraft6::interpret() { if (_userDefinedStartConfiguration.size() == 0) { // try to get initial transition form initial element - initialTransitions = _xpath.evaluate("/" + _xpathPrefix + "scxml/" + _xpathPrefix + "initial/" + _xpathPrefix + "transition", _document).asNodeSet(); + initialTransitions = _xpath.evaluate("/" + _xpathPrefix + "initial/" + _xpathPrefix + "transition", _scxml).asNodeSet(); } if (initialTransitions.size() == 0) { @@ -155,6 +155,8 @@ void InterpreterDraft6::initializeData(const Arabica::DOM::Node& da break; } } + } else { + _dataModel.assign(ATTR(data, "id"), "undefined"); } } catch (Event e) { @@ -318,7 +320,14 @@ void InterpreterDraft6::mainEventLoop() { } exitInterpreter(); - + if (_sendQueue) { + std::map >::iterator sendIter = _sendIds.begin(); + while(sendIter != _sendIds.end()) { + _sendQueue->cancelEvent(sendIter->first); + sendIter++; + } + } + monIter = _monitors.begin(); while(monIter != _monitors.end()) { try { diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp index 447c52f..c0e87d7 100644 --- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp @@ -43,13 +43,29 @@ void USCXMLInvoker::cancel(const std::string sendId) { } void USCXMLInvoker::invoke(const InvokeRequest& req) { - _invokedInterpreter = Interpreter::fromURI(req.src); + if (req.src.length() > 0) { + _invokedInterpreter = Interpreter::fromURI(req.src); + } else if (req.dom) { + _invokedInterpreter = Interpreter::fromDOM(req.dom); + } else { + LOG(ERROR) << "Cannot invoke nested SCXML interpreter, neither src attribute nor DOM is given"; + } DataModel dataModel(_invokedInterpreter->getDataModel()); if (dataModel) { } if (_invokedInterpreter) { _invokedInterpreter->setParentQueue(this); + // transfer namespace prefixes + _invokedInterpreter->_nsURL = _parentInterpreter->_nsURL; + _invokedInterpreter->_xpathPrefix = _parentInterpreter->_xpathPrefix; + _invokedInterpreter->_nsToPrefix = _parentInterpreter->_nsToPrefix; + std::map::iterator nsIter = _parentInterpreter->_nsToPrefix.begin(); + while(nsIter != _parentInterpreter->_nsToPrefix.end()) { + _invokedInterpreter->_nsContext.addNamespaceDeclaration(nsIter->first, nsIter->second); + nsIter++; + } + _invokedInterpreter->_xmlNSPrefix = _parentInterpreter->_xmlNSPrefix; _invokedInterpreter->start(); } } -- cgit v0.12