From ba050afaaad699e60ca657b311d5c34d038bb89c Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Fri, 12 Apr 2013 13:57:08 +0200 Subject: Refactoring for other datamodels --- contrib/ctest/CTestCustom.ctest.in | 9 - src/bindings/swig/php/uscxmlNativePHP.php | 58 +-- src/uscxml/Factory.h | 78 ++-- src/uscxml/Interpreter.cpp | 287 ++++++------- src/uscxml/Interpreter.h | 25 +- src/uscxml/Message.cpp | 18 +- src/uscxml/interpreter/InterpreterDraft6.cpp | 6 +- src/uscxml/interpreter/InterpreterDraft7.cpp | 55 +-- .../datamodel/ecmascript/v8/V8DataModel.cpp | 132 +++++- .../plugins/datamodel/ecmascript/v8/V8DataModel.h | 40 +- .../plugins/datamodel/null/NULLDataModel.cpp | 16 +- src/uscxml/plugins/datamodel/null/NULLDataModel.h | 30 +- .../plugins/datamodel/prolog/swi/SWIDataModel.cpp | 37 +- .../plugins/datamodel/prolog/swi/SWIDataModel.h | 27 +- .../plugins/datamodel/xpath/XPathDataModel.cpp | 443 +++++++++++++-------- .../plugins/datamodel/xpath/XPathDataModel.h | 82 ++-- src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp | 4 +- test/samples/w3c/ecma/test530.scxml | 4 +- test/src/test-arabica-xpath.cpp | 196 +++++---- 19 files changed, 820 insertions(+), 727 deletions(-) diff --git a/contrib/ctest/CTestCustom.ctest.in b/contrib/ctest/CTestCustom.ctest.in index fd93ab6..d90a6b6 100644 --- a/contrib/ctest/CTestCustom.ctest.in +++ b/contrib/ctest/CTestCustom.ctest.in @@ -8,15 +8,6 @@ # skip xpath datamodel tests set(CTEST_CUSTOM_TESTS_IGNORE - "test539.scxml" - "test540.scxml" - "test542.scxml" - "test544.scxml" - "test546.scxml" - "test547.scxml" - "test555.scxml" - "test568.scxml" - "test178.scxml" "test230.scxml" "test250.scxml" diff --git a/src/bindings/swig/php/uscxmlNativePHP.php b/src/bindings/swig/php/uscxmlNativePHP.php index 89cad82..c15f979 100644 --- a/src/bindings/swig/php/uscxmlNativePHP.php +++ b/src/bindings/swig/php/uscxmlNativePHP.php @@ -32,56 +32,6 @@ abstract class uscxmlNativePHP { const CAN_BASIC_HTTP = 1; const CAN_GENERIC_HTTP = 2; - - const ANY = 0; - - const BOOL = BOOL; - - const NUMBER = NUMBER; - - const STRING = STRING; - - const NODE_SET = NODE_SET; - - static function NaN_get() { - return NaN_get(); - } - - static function Zero_get() { - return Zero_get(); - } - - static function Negative_Zero_get() { - return Negative_Zero_get(); - } - - static function Infinity_get() { - return Infinity_get(); - } - - static function Negative_Infinity_get() { - return Negative_Infinity_get(); - } - - static function isNaN($value) { - return isNaN($value); - } - - static function isInfinity($value) { - return isInfinity($value); - } - - static function isNegativeInfinity($value) { - return isNegativeInfinity($value); - } - - static function isInfinite($value) { - return isInfinite($value); - } - - static function roundNumber($value) { - return roundNumber($value); - } } /* PHP Proxy Classes */ @@ -700,7 +650,13 @@ class Interpreter { } function getConfiguration() { - return Interpreter_getConfiguration($this->_cPtr); + $r=Interpreter_getConfiguration($this->_cPtr); + if (is_resource($r)) { + $c=substr(get_resource_type($r), (strpos(get_resource_type($r), '__') ? strpos(get_resource_type($r), '__') + 2 : 3)); + if (class_exists($c)) return new $c($r); + return new ParamList($r); + } + return $r; } function setConfiguration($states) { diff --git a/src/uscxml/Factory.h b/src/uscxml/Factory.h index 540cf61..e21fe72 100644 --- a/src/uscxml/Factory.h +++ b/src/uscxml/Factory.h @@ -240,32 +240,21 @@ public: virtual void pushContext() = 0; virtual void popContext() = 0; - virtual bool supportsJSON() { return false; } - virtual void eval(const std::string& expr) = 0; virtual std::string evalAsString(const std::string& expr) = 0; virtual bool evalAsBool(const std::string& expr) = 0; + virtual bool isDeclared(const std::string& expr) = 0; - virtual void assign(const std::string& location, - const Arabica::DOM::Document& doc, - const Arabica::DOM::Element& assignElem) = 0; - virtual void assign(const std::string& location, - const std::string& expr, - const Arabica::DOM::Element& assignElem) = 0; - virtual void assign(const std::string& location, - const Data& data, - const Arabica::DOM::Element& assignElem) = 0; - - virtual void init(const std::string& location, - const Arabica::DOM::Document& doc, - const Arabica::DOM::Element& dataElem) = 0; - virtual void init(const std::string& location, - const std::string& expr, - const Arabica::DOM::Element& dataElem) = 0; - virtual void init(const std::string& location, - const Data& data, - const Arabica::DOM::Element& dataElem) = 0; + virtual void assign(const Arabica::DOM::Element& assignElem, + const Arabica::DOM::Document& doc, + const std::string& content) = 0; + virtual void assign(const std::string& location, const Data& data) = 0; + + virtual void init(const Arabica::DOM::Element& dataElem, + const Arabica::DOM::Document& doc, + const std::string& content) = 0; + virtual void init(const std::string& location, const Data& data) = 0; protected: InterpreterImpl* _interpreter; @@ -305,18 +294,12 @@ public: return _impl->getStringAsData(content); } - virtual uint32_t getLength(const std::string& expr) { - return _impl->getLength(expr); - } virtual void pushContext() { return _impl->pushContext(); } virtual void popContext() { return _impl->popContext(); } - virtual bool supportsJSON() { - return _impl->supportsJSON(); - } virtual void eval(const std::string& expr) { return _impl->eval(expr); @@ -327,37 +310,26 @@ public: virtual bool evalAsBool(const std::string& expr) { return _impl->evalAsBool(expr); } - - virtual void assign(const std::string& location, - const Arabica::DOM::Document& doc, - const Arabica::DOM::Element& assignElem) { - return _impl->assign(location, doc, assignElem); + virtual uint32_t getLength(const std::string& expr) { + return _impl->getLength(expr); } - virtual void assign(const std::string& location, - const std::string& expr, - const Arabica::DOM::Element& assignElem) { - return _impl->assign(location, expr, assignElem); + + virtual void assign(const Arabica::DOM::Element& assignElem, + const Arabica::DOM::Document& doc, + const std::string& content) { + return _impl->assign(assignElem, doc, content); } - virtual void assign(const std::string& location, - const Data& data, - const Arabica::DOM::Element& assignElem) { - return _impl->assign(location, data, assignElem); + virtual void assign(const std::string& location, const Data& data) { + return _impl->assign(location, data); } - virtual void init(const std::string& location, - const Arabica::DOM::Document& doc, - const Arabica::DOM::Element& dataElem) { - return _impl->init(location, doc, dataElem); - } - virtual void init(const std::string& location, - const std::string& expr, - const Arabica::DOM::Element& dataElem) { - return _impl->init(location, expr, dataElem); + virtual void init(const Arabica::DOM::Element& dataElem, + const Arabica::DOM::Document& doc, + const std::string& content) { + return _impl->init(dataElem, doc, content); } - virtual void init(const std::string& location, - const Data& data, - const Arabica::DOM::Element& dataElem) { - return _impl->init(location, data, dataElem); + virtual void init(const std::string& location, const Data& data) { + return _impl->init(location, data); } virtual bool isDeclared(const std::string& expr) { diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index a78d4a0..7fe5cc1 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -319,15 +319,10 @@ void InterpreterImpl::initializeData(const Element& data) { return; } - if (!HAS_ATTR(data, "id")) { - LOG(ERROR) << "Data element has no id!"; - return; - } - - /// test 240 - initialize from invoke request + /// test 226/240 - initialize from invoke request if (_invokeReq.params.find(ATTR(data, "id")) != _invokeReq.params.end()) { try { - _dataModel.init(ATTR(data, "id"), _invokeReq.params.find(ATTR(data, "id"))->second, data); + _dataModel.init(ATTR(data, "id"), _invokeReq.params.find(ATTR(data, "id"))->second); } catch (Event e) { LOG(ERROR) << "Syntax error when initializing data from parameters:" << std::endl << e << std::endl; receiveInternal(e); @@ -336,7 +331,7 @@ void InterpreterImpl::initializeData(const Element& data) { } if (_invokeReq.namelist.find(ATTR(data, "id")) != _invokeReq.namelist.end()) { try { - _dataModel.init(ATTR(data, "id"), _invokeReq.namelist.find(ATTR(data, "id"))->second, data); + _dataModel.init(ATTR(data, "id"), _invokeReq.namelist.find(ATTR(data, "id"))->second); } catch (Event e) { LOG(ERROR) << "Syntax error when initializing data from namelist:" << std::endl << e << std::endl; receiveInternal(e); @@ -345,113 +340,12 @@ void InterpreterImpl::initializeData(const Element& data) { } try { - std::string contentToProcess; - if (HAS_ATTR(data, "expr")) { - // expression given directly - std::string value = ATTR(data, "expr"); - try { - _dataModel.init(ATTR(data, "id"), value, data); - } catch (Event e) { - LOG(ERROR) << "Syntax error in data element:" << std::endl << e << std::endl; - /// test 277 - /// todo: if the identifier is invalid we'll raise to error events - receiveInternal(e); - _dataModel.init(ATTR(data, "id"), "undefined", data); - } - return; - } - - if (HAS_ATTR(data, "src")) { - // fetch us some string and proess below - URL srcURL(ATTR(data, "src")); - if (!srcURL.isAbsolute()) - toAbsoluteURI(srcURL); - - std::stringstream ss; - if (_cachedURLs.find(srcURL.asString()) != _cachedURLs.end()) { - ss << _cachedURLs[srcURL.asString()]; - } else { - ss << srcURL; - _cachedURLs[srcURL.asString()] = srcURL; - } - contentToProcess = ss.str(); - - // try to parse as XML - std::stringstream* xmlStr = new std::stringstream(); - (*xmlStr) << contentToProcess; - std::auto_ptr ssPtr(xmlStr); - Arabica::SAX::InputSource inputSource; - inputSource.setByteStream(ssPtr); - Arabica::SAX2DOM::Parser parser; - if(parser.parse(inputSource) && parser.getDocument()) { - try { - _dataModel.init(ATTR(data, "id"), parser.getDocument(), data); - return; - } catch (Event e) { - LOG(ERROR) << "Syntax error in data element:" << std::endl << e << std::endl; - receiveInternal(e); - _dataModel.init(ATTR(data, "id"), "undefined", data); - } - return; - } - } else if (data.hasChildNodes()) { - bool presentAsDom = false; - Node contentChild = data.getFirstChild(); - while(contentChild) { - if (contentChild.getNodeType() == Node_base::TEXT_NODE) { - std::string trimmed = contentChild.getNodeValue(); - boost::trim(trimmed); - if (trimmed.length() > 0) - break; - } - if (contentChild.getNodeType() == Node_base::ELEMENT_NODE) { - presentAsDom = true; - break; - } - contentChild = contentChild.getNextSibling(); - } - - if (contentChild && presentAsDom) { - Arabica::DOM::DOMImplementation domFactory = Arabica::SimpleDOM::DOMImplementation::getDOMImplementation(); - Document dom = domFactory.createDocument(contentChild.getNamespaceURI(), "", 0); - Node newNode = dom.importNode(contentChild, true); - dom.appendChild(newNode); - _dataModel.init(ATTR(data, "id"), dom, data); - return; - } else if (contentChild) { - // get first child and process below - contentToProcess = contentChild.getNodeValue(); - } else { - LOG(ERROR) << "content element has no text or element children."; - } - } - if (contentToProcess.length() > 0) { - /// try to interpret as JSON - try { - _dataModel.init(ATTR(data, "id"), contentToProcess, data); - } catch(Event e) { - /// create space normalized string if that failed - /// test 558 - std::istringstream iss(contentToProcess); - std::stringstream spaceNormalized; - std::string seperator; - do { - std::string token; - iss >> token; - if (token.length() > 0) { - spaceNormalized << seperator << token; - seperator = " "; - } - } while (iss); - _dataModel.init(ATTR(data, "id"), Data(spaceNormalized.str(), Data::VERBATIM), data); - } - } else { - _dataModel.init(ATTR(data, "id"), "undefined", data); - } - + Arabica::DOM::Document dom; + std::string text; + processDOMorText(data, dom, text); + _dataModel.init(data, dom, text); } catch (Event e) { - LOG(ERROR) << "Syntax error in data element:" << std::endl << e << std::endl; - /// test 487 + LOG(ERROR) << "Syntax error when initializing data:" << std::endl << e << std::endl; receiveInternal(e); } } @@ -518,12 +412,12 @@ void InterpreterImpl::normalize(Arabica::DOM::Element& scxml) { } void InterpreterImpl::receiveInternal(const Event& event) { -// std::cout << "receiveInternal: " << event.name << std::endl; + std::cout << _name << " receiveInternal: " << event.name << std::endl; _internalQueue.push_back(event); } void InterpreterImpl::receive(const Event& event, bool toFront) { -// std::cout << "receive: " << event.name << std::endl; + std::cout << _name << " receive: " << event.name << std::endl; if (toFront) { _externalQueue.push_front(event); } else { @@ -547,8 +441,18 @@ void InterpreterImpl::internalDoneSend(const Arabica::DOM::Node& st Arabica::XPath::NodeSet contents = filterChildElements(_xmlNSPrefix + "content", doneDatas[0]); if (contents.size() > 1) LOG(ERROR) << "Only a single content element is allowed for send elements - using first one"; - if (contents.size() > 0) - processContentElement(contents[0], event.dom, event.content, event.data); + if (contents.size() > 0) { + std::string expr; + processContentElement(contents[0], event.dom, event.content, expr); + if (expr.length() > 0 && _dataModel) { + try { + event.content =_dataModel.evalAsString(expr); + } catch (Event e) { + e.name = "error.execution"; + receiveInternal(e); + } + } + } } event.name = "done.state." + ATTR(stateElem.getParentNode(), "id"); // parent?! @@ -559,13 +463,22 @@ void InterpreterImpl::internalDoneSend(const Arabica::DOM::Node& st void InterpreterImpl::processContentElement(const Arabica::DOM::Node& content, Arabica::DOM::Document& dom, std::string& text, - Data& data) { + std::string& expr) { + if (HAS_ATTR(content, "expr")) { + expr = ATTR(content, "expr"); + } else if (content.hasChildNodes()) { + processDOMorText(content, dom, text); + } else { + LOG(ERROR) << "content element does not specify any content."; + } + +#if 0 try { std::string contentToProcess; if (HAS_ATTR(content, "expr")) { if (_dataModel) { /// this is out of spec - contentToProcess = _dataModel.evalAsString(ATTR(content, "expr")); + contentToProcess = ATTR(content, "expr"); // sendReq.data.atom = contentValue; // sendReq.data.type = Data::VERBATIM; } else { @@ -629,6 +542,75 @@ void InterpreterImpl::processContentElement(const Arabica::DOM::Node& node, + Arabica::DOM::Document& dom, + std::string& text) { + // do we need to download? + if (HAS_ATTR(node, "src") || + (HAS_ATTR(node, "srcexpr") && _dataModel)) { + std::stringstream srcContent; + URL sourceURL(HAS_ATTR(node, "srcexpr") ? _dataModel.evalAsString(ATTR(node, "srcexpr")) : ATTR(node, "src")); + if (!toAbsoluteURI(sourceURL)) { + LOG(ERROR) << LOCALNAME(node) << " element has relative src or srcexpr URI with no baseURI set."; + return; + } + if (_cachedURLs.find(sourceURL.asString()) != _cachedURLs.end()) { + srcContent << _cachedURLs[sourceURL.asString()]; + } else { + srcContent << sourceURL; + if (sourceURL.downloadFailed()) { + LOG(ERROR) << LOCALNAME(node) << " source cannot be downloaded"; + return; + } + _cachedURLs[sourceURL.asString()] = sourceURL; + } + if (srcContent.str().length() > 0) { + // try to parse as XML + Arabica::SAX2DOM::Parser parser; + std::stringstream* ss = new std::stringstream(); + (*ss) << srcContent.str(); + std::auto_ptr ssPtr(ss); + Arabica::SAX::InputSource inputSource; + inputSource.setByteStream(ssPtr); + if (parser.parse(inputSource) && parser.getDocument()) { + dom = parser.getDocument(); + return; + } else { + text = srcContent.str(); + return; + } + } + } + + if (!node.hasChildNodes()) + return; + + Node child = node.getFirstChild(); + while(child) { + if (child.getNodeType() == Node_base::TEXT_NODE) { + std::string trimmed = child.getNodeValue(); + boost::trim(trimmed); + if (trimmed.length() > 0) + break; + } + if (child.getNodeType() == Node_base::ELEMENT_NODE) { + break; + } + child = child.getNextSibling(); + } + if (child && child.getNodeType() == Node_base::ELEMENT_NODE) { + DOMImplementation domFactory = Arabica::SimpleDOM::DOMImplementation::getDOMImplementation(); + dom = domFactory.createDocument(child.getNamespaceURI(), "", 0); + Node newNode = dom.importNode(child, true); + dom.appendChild(newNode); + } else if(child && child.getNodeType() == Node_base::TEXT_NODE) { + text = child.getNodeValue(); + } else { + LOG(ERROR) << LOCALNAME(node) << " has neither text nor element children."; + } } void InterpreterImpl::processParamChilds(const Arabica::DOM::Node& element, std::multimap& params) { @@ -726,7 +708,7 @@ void InterpreterImpl::send(const Arabica::DOM::Node& element) { */ sendReq.sendid = ATTR(getParentState(element), "id") + "." + getUUID(); if (HAS_ATTR(element, "idlocation") && _dataModel) { - _dataModel.assign(ATTR(element, "idlocation"), "'" + sendReq.sendid + "'", Element()); + _dataModel.assign(ATTR(element, "idlocation"), "'" + sendReq.sendid + "'"); } else { sendReq.hideSendId = true; } @@ -796,7 +778,16 @@ void InterpreterImpl::send(const Arabica::DOM::Node& element) { if (contents.size() > 1) LOG(ERROR) << "Only a single content element is allowed for send elements - using first one"; if (contents.size() > 0) { - processContentElement(contents[0], sendReq.dom, sendReq.content, sendReq.data); + std::string expr; + processContentElement(contents[0], sendReq.dom, sendReq.content, expr); + if (expr.length() > 0 && _dataModel) { + try { + sendReq.content =_dataModel.evalAsString(expr); + } catch (Event e) { + e.name = "error.execution"; + receiveInternal(e); + } + } } } catch (Event e) { LOG(ERROR) << "Syntax error in send element content:" << std::endl << e << std::endl; @@ -880,7 +871,7 @@ void InterpreterImpl::invoke(const Arabica::DOM::Node& element) { } else { invokeReq.invokeid = ATTR(getParentState(element), "id") + "." + getUUID(); if (HAS_ATTR(element, "idlocation") && _dataModel) { - _dataModel.assign(ATTR(element, "idlocation"), "'" + invokeReq.invokeid + "'", Element()); + _dataModel.assign(ATTR(element, "idlocation"), "'" + invokeReq.invokeid + "'"); } } } catch (Event e) { @@ -914,7 +905,16 @@ void InterpreterImpl::invoke(const Arabica::DOM::Node& element) { if (contents.size() > 1) LOG(ERROR) << "Only a single content element is allowed for send elements - using first one"; if (contents.size() > 0) { - processContentElement(contents[0], invokeReq.dom, invokeReq.content, invokeReq.data); + std::string expr; + processContentElement(contents[0], invokeReq.dom, invokeReq.content, expr); + if (expr.length() > 0 && _dataModel) { + try { + invokeReq.content =_dataModel.evalAsString(expr); + } catch (Event e) { + e.name = "error.execution"; + receiveInternal(e); + } + } } } catch (Event e) { LOG(ERROR) << "Syntax error in send element content:" << std::endl << e << std::endl; @@ -941,7 +941,7 @@ void InterpreterImpl::invoke(const Arabica::DOM::Node& element) { } if (_dataModel) { try { - _dataModel.assign("_invokers['" + invokeReq.invokeid + "']", invoker.getDataModelVariables(), Element()); + _dataModel.assign("_invokers['" + invokeReq.invokeid + "']", invoker.getDataModelVariables()); } catch(...) { LOG(ERROR) << "Exception caught while assigning datamodel variables from invoker " << invokeReq.invokeid; } @@ -971,7 +971,7 @@ void InterpreterImpl::cancelInvoke(const Arabica::DOM::Node& elemen LOG(INFO) << "Removed invoker at " << invokeId; if (_dataModel) { try { - _dataModel.assign("_invokers['" + invokeId + "']", "''", Element()); + _dataModel.assign("_invokers['" + invokeId + "']", std::string("''")); } catch (Event e) { LOG(ERROR) << "Syntax when removing invoker:" << std::endl << e << std::endl; } @@ -1139,13 +1139,13 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node& cont // assign array element to item std::stringstream ss; ss << array << "[" << iteration << "]"; - _dataModel.assign(item, ss.str(), Element()); + _dataModel.assign(item, ss.str()); } if (index.length() > 0) { // assign iteration element to index std::stringstream ss; ss << iteration; - _dataModel.assign(index,ss.str(), Element()); + _dataModel.assign(index, ss.str()); } if (content.hasChildNodes()) // execute content and have exception rethrown to break foreach @@ -1183,21 +1183,10 @@ void InterpreterImpl::executeContent(const Arabica::DOM::Node& cont LOG(ERROR) << "Assigning to undeclared location '" << ATTR(content, "location") << "' not allowed." << std::endl; throw Event("error.execution", Event::PLATFORM); } else { - Data data; Document dom; std::string text; - processContentElement(content, dom, text, data); - - if (dom) { - _dataModel.assign(ATTR(content, "location"), dom, Element(content)); - } else if(data && _dataModel.supportsJSON()) { - _dataModel.assign(ATTR(content, "location"), data, Element(content)); - } else if (text.length() > 0) { - _dataModel.assign(ATTR(content, "location"), text, Element(content)); - } else { - LOG(ERROR) << "Assign element does not specify any content" << std::endl; - throw Event("error.execution", Event::PLATFORM); - } + processDOMorText(content, dom, text); + _dataModel.assign(Element(content), dom, text); } } CATCH_AND_DISTRIBUTE("Syntax error in attributes of assign element:") @@ -1554,6 +1543,22 @@ std::vector InterpreterImpl::tokenizeIdRefs(const std::string& idRe return ids; } +std::string InterpreterImpl::spaceNormalize(const std::string& text) { + std::istringstream iss(text); + std::stringstream content; + std::string seperator; + do { + std::string token; + iss >> token; + if (token.length() > 0) { + content << seperator << token; + seperator = " "; + } + } while (iss); + return content.str(); +} + + NodeSet InterpreterImpl::filterChildElements(const std::string& tagName, const NodeSet& nodeSet) { NodeSet filteredChildElems; for (unsigned int i = 0; i < nodeSet.size(); i++) { diff --git a/src/uscxml/Interpreter.h b/src/uscxml/Interpreter.h index 673cba1..5207930 100644 --- a/src/uscxml/Interpreter.h +++ b/src/uscxml/Interpreter.h @@ -202,6 +202,7 @@ public: static bool isDescendant(const Arabica::DOM::Node& s1, const Arabica::DOM::Node& s2); static std::vector tokenizeIdRefs(const std::string& idRefs); + static std::string spaceNormalize(const std::string& text); bool isInitial(const Arabica::DOM::Node& state); Arabica::XPath::NodeSet getInitialStates(Arabica::DOM::Node state = Arabica::DOM::Node()); @@ -270,8 +271,12 @@ protected: void processContentElement(const Arabica::DOM::Node& element, Arabica::DOM::Document& dom, std::string& text, - Data& data); - void processParamChilds(const Arabica::DOM::Node& element, std::multimap& params); + std::string& expr); + void processParamChilds(const Arabica::DOM::Node& element, + std::multimap& params); + void processDOMorText(const Arabica::DOM::Node& node, + Arabica::DOM::Document& dom, + std::string& text); void send(const Arabica::DOM::Node& element); void invoke(const Arabica::DOM::Node& element); @@ -414,9 +419,22 @@ public: return _impl->getCurrentEvent(); } +#ifndef SWIG Arabica::XPath::NodeSet getConfiguration() { return _impl->getConfiguration(); } +#else + // simplified access to state names for language bindings + std::vector getConfiguration() { + std::vector stateNames; + Arabica::XPath::NodeSet nodeSet = _impl->getConfiguration(); + for (int i = 0; i < nodeSet.size(); i++) { + stateNames.push_back(ATTR(nodeSet[i], "id")); + } + return stateNames; + } +#endif + void setConfiguration(const std::vector& states) { return _impl->setConfiguration(states); } @@ -507,6 +525,9 @@ public: static std::vector tokenizeIdRefs(const std::string& idRefs) { return InterpreterImpl::tokenizeIdRefs(idRefs); } + static std::string spaceNormalize(const std::string& text) { + return InterpreterImpl::spaceNormalize(text); + } bool isInitial(const Arabica::DOM::Node& state) { return _impl->isInitial(state); diff --git a/src/uscxml/Message.cpp b/src/uscxml/Message.cpp index 65a66ce..0898cc7 100644 --- a/src/uscxml/Message.cpp +++ b/src/uscxml/Message.cpp @@ -7,6 +7,8 @@ #include #include +#include + #ifdef HAS_STRING_H #include #endif @@ -180,7 +182,10 @@ Data Data::fromXML(const std::string& xmlString) { Data Data::fromJSON(const std::string& jsonString) { Data data; - if (jsonString.length() == 0) + std::string trimmed = jsonString; + boost::trim(trimmed); + + if (trimmed.length() == 0) return data; jsmn_parser p; @@ -194,7 +199,7 @@ Data Data::fromJSON(const std::string& jsonString) { jsmn_init(&p); frac /= 2; - int nrTokens = jsonString.size() / frac; + int nrTokens = trimmed.size() / frac; if (t != NULL) { free(t); // LOG(INFO) << "Increasing JSON length to token ratio to 1/" << frac; @@ -206,7 +211,7 @@ Data Data::fromJSON(const std::string& jsonString) { } memset(t, 0, nrTokens * sizeof(jsmntok_t) + 1); - rv = jsmn_parse(&p, jsonString.c_str(), t, nrTokens); + rv = jsmn_parse(&p, trimmed.c_str(), t, nrTokens); } while (rv == JSMN_ERROR_NOMEM && frac > 1); if (rv != 0) { @@ -227,6 +232,9 @@ Data Data::fromJSON(const std::string& jsonString) { return data; } + if (t[0].end != trimmed.length()) + return data; + std::list dataStack; std::list tokenStack; dataStack.push_back(&data); @@ -237,7 +245,7 @@ Data Data::fromJSON(const std::string& jsonString) { case JSMN_STRING: dataStack.back()->type = Data::VERBATIM; case JSMN_PRIMITIVE: - dataStack.back()->atom = jsonString.substr(t[currTok].start, t[currTok].end - t[currTok].start); + dataStack.back()->atom = trimmed.substr(t[currTok].start, t[currTok].end - t[currTok].start); dataStack.pop_back(); currTok++; break; @@ -258,7 +266,7 @@ Data Data::fromJSON(const std::string& jsonString) { if (tokenStack.back().type == JSMN_OBJECT && (t[currTok].type == JSMN_PRIMITIVE || t[currTok].type == JSMN_STRING)) { // grab key and push new data - dataStack.push_back(&(dataStack.back()->compound[jsonString.substr(t[currTok].start, t[currTok].end - t[currTok].start)])); + dataStack.push_back(&(dataStack.back()->compound[trimmed.substr(t[currTok].start, t[currTok].end - t[currTok].start)])); currTok++; } if (tokenStack.back().type == JSMN_ARRAY) { diff --git a/src/uscxml/interpreter/InterpreterDraft6.cpp b/src/uscxml/interpreter/InterpreterDraft6.cpp index dfcc457..d3019d9 100644 --- a/src/uscxml/interpreter/InterpreterDraft6.cpp +++ b/src/uscxml/interpreter/InterpreterDraft6.cpp @@ -22,6 +22,8 @@ void InterpreterDraft6::interpret() { // just make sure we have a session id assert(_sessionId.length() > 0); + setupIOProcessors(); + std::string datamodelName; if (datamodelName.length() == 0 && HAS_ATTR(_scxml, "datamodel")) datamodelName = ATTR(_scxml, "datamodel"); @@ -34,11 +36,9 @@ void InterpreterDraft6::interpret() { } if (_dataModel) { - _dataModel.assign("_x.args", _cmdLineOptions, Element()); + _dataModel.assign("_x.args", _cmdLineOptions); } - setupIOProcessors(); - _running = true; _binding = (HAS_ATTR(_scxml, "binding") && boost::iequals(ATTR(_scxml, "binding"), "late") ? LATE : EARLY); diff --git a/src/uscxml/interpreter/InterpreterDraft7.cpp b/src/uscxml/interpreter/InterpreterDraft7.cpp index e02a343..2f8c7b2 100644 --- a/src/uscxml/interpreter/InterpreterDraft7.cpp +++ b/src/uscxml/interpreter/InterpreterDraft7.cpp @@ -45,12 +45,7 @@ void InterpreterDraft7::interpret() { } if (_dataModel) { - _dataModel.assign("_x.args", _cmdLineOptions, Element()); - if (_httpServlet) { - Data data; - data.compound["location"] = Data(_httpServlet->getURL(), Data::VERBATIM); - _dataModel.assign("_ioprocessors['http']", data, Element()); - } + _dataModel.assign("_x.args", _cmdLineOptions); } setupIOProcessors(); @@ -117,54 +112,6 @@ void InterpreterDraft7::interpret() { } /** - * Called with a single data element from the topmost datamodel element. - */ -void InterpreterDraft7::initializeData(const Arabica::DOM::Element& data) { - if (!_dataModel) { - LOG(ERROR) << "Cannot initialize data when no datamodel is given!"; - return; - } - try { - if (!HAS_ATTR(data, "id")) { - LOG(ERROR) << "Data element has no id!"; - return; - } - - if (HAS_ATTR(data, "expr")) { - std::string value = ATTR(data, "expr"); - _dataModel.assign(ATTR(data, "id"), value, data); - } else if (HAS_ATTR(data, "src")) { - URL srcURL(ATTR(data, "src")); - if (!srcURL.isAbsolute()) - toAbsoluteURI(srcURL); - - std::stringstream ss; - if (_cachedURLs.find(srcURL.asString()) != _cachedURLs.end()) { - ss << _cachedURLs[srcURL.asString()]; - } else { - ss << srcURL; - _cachedURLs[srcURL.asString()] = srcURL; - } - _dataModel.assign(ATTR(data, "id"), ss.str(), data); - - } else if (data.hasChildNodes()) { - // search for the text node with the actual script - NodeList dataChilds = data.getChildNodes(); - for (int i = 0; i < dataChilds.getLength(); i++) { - if (dataChilds.item(i).getNodeType() == Node_base::TEXT_NODE) { - Data value = Data(dataChilds.item(i).getNodeValue()); - _dataModel.assign(ATTR(data, "id"), value, data); - break; - } - } - } - - } catch (Event e) { - LOG(ERROR) << "Syntax error in data element:" << std::endl << e << std::endl; - } -} - -/** procedure mainEventLoop(): while running: enabledTransitions = null diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp index 2491fc4..22777fa 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp @@ -147,9 +147,13 @@ void V8DataModel::setEvent(const Event& event) { if (event.dom) { eventObj->Set(v8::String::New("data"), getDocumentAsValue(event.dom)); } else if (event.content.length() > 0) { - // _event.data is a string - eventObj->Set(v8::String::New("data"), v8::String::New(event.content.c_str())); -// eventObj->Set(v8::String::New("data"), v8::Undefined()); + // _event.data is a string or JSON + Data json = Data::fromJSON(event.content); + if (json) { + eventObj->Set(v8::String::New("data"), getDataAsValue(json)); + } else { + eventObj->Set(v8::String::New("data"), v8::String::New(Interpreter::spaceNormalize(event.content).c_str())); + } } else { // _event.data is KVP Event eventCopy(event); @@ -188,12 +192,23 @@ Data V8DataModel::getStringAsData(const std::string& content) { } Data V8DataModel::getValueAsData(const v8::Handle& value) { + std::set foo = std::set(); + return getValueAsData(value, foo); +} + +Data V8DataModel::getValueAsData(const v8::Handle& value, std::set& alreadySeen) { Data data; + + /// TODO: Breaking cycles does not work yet + if (alreadySeen.find(*value) != alreadySeen.end()) + return data; + alreadySeen.insert(*value); + if (false) { } else if (value->IsArray()) { v8::Handle array = v8::Handle::Cast(value); for (int i = 0; i < array->Length(); i++) { - data.array.push_back(getValueAsData(array->Get(i))); + data.array.push_back(getValueAsData(array->Get(i), alreadySeen)); } } else if (value->IsBoolean()) { data.atom = (value->ToBoolean()->Value() ? "true" : "false"); @@ -226,7 +241,7 @@ Data V8DataModel::getValueAsData(const v8::Handle& value) { assert(properties->Get(i)->IsString()); v8::String::AsciiValue key(v8::Handle::Cast(properties->Get(i))); v8::Local property = object->Get(properties->Get(i)); - data.compound[*key] = getValueAsData(property); + data.compound[*key] = getValueAsData(property, alreadySeen); } } else if (value->IsRegExp()) { LOG(ERROR) << "IsRegExp is unimplemented" << std::endl; @@ -374,9 +389,33 @@ std::string V8DataModel::evalAsString(const std::string& expr) { v8::Context::Scope contextScope(_contexts.back()); v8::Handle result = evalAsValue(expr); if (result->IsObject()) { + v8::Local obj = result->ToObject(); + v8::Local proto; + + proto = obj->FindInstanceInPrototypeChain(Arabica::DOM::V8Document::getTmpl()); + if (!proto.IsEmpty()) { + struct Arabica::DOM::V8Document::V8DocumentPrivate* privData = + Arabica::DOM::V8DOM::toClassPtr(obj->GetInternalField(0)); + std::stringstream ss; + ss << privData->nativeObj->getDocumentElement(); + return ss.str(); + } + + proto = obj->FindInstanceInPrototypeChain(Arabica::DOM::V8Node::getTmpl()); + if (!proto.IsEmpty()) { + struct Arabica::DOM::V8Node::V8NodePrivate* privData = + Arabica::DOM::V8DOM::toClassPtr(obj->GetInternalField(0)); + std::stringstream ss; + ss << privData->nativeObj; + return ss.str(); + } + Data data = getValueAsData(result); return toStr(data); } + if (result->IsNumber()) { + return toStr(result->ToNumber()->NumberValue()); + } v8::String::AsciiValue data(result->ToString()); return std::string(*data); } @@ -392,40 +431,89 @@ double V8DataModel::evalAsNumber(const std::string& expr) { return 0; } -void V8DataModel::assign(const std::string& location, - const Arabica::DOM::Document& doc, - const Arabica::DOM::Element& dataElem) { +void V8DataModel::assign(const Arabica::DOM::Element& assignElem, + const Arabica::DOM::Document& doc, + const std::string& content) { v8::Locker locker; v8::HandleScope handleScope; v8::Context::Scope contextScope(_contexts.front()); v8::Handle global = _contexts.front()->Global(); - global->Set(v8::String::New(location.c_str()), getDocumentAsValue(doc)); - + std::string key; + if (HAS_ATTR(assignElem, "id")) { + key = ATTR(assignElem, "id"); + } else if (HAS_ATTR(assignElem, "location")) { + key = ATTR(assignElem, "location"); + } + if (key.length() == 0) + throw Event("error.execution", Event::PLATFORM); + + if (HAS_ATTR(assignElem, "expr")) { + evalAsValue(key + " = " + ATTR(assignElem, "expr")); + } else if (doc) { + global->Set(v8::String::New(key.c_str()), getDocumentAsValue(doc)); + } else if (content.size() > 0) { + try { + evalAsValue(key + " = " + content); + } catch (...) { + evalAsValue(key + " = " + "\"" + Interpreter::spaceNormalize(content) + "\""); + } + } else { + global->Set(v8::String::New(key.c_str()), v8::Undefined()); + } } void V8DataModel::assign(const std::string& location, - const Data& data, - const Arabica::DOM::Element& dataElem) { + const Data& data) { v8::Locker locker; v8::HandleScope handleScope; v8::Context::Scope contextScope(_contexts.front()); std::stringstream ssJSON; ssJSON << data; - assign(location, ssJSON.str(), dataElem); + evalAsValue(location + " = " + ssJSON.str()); } -void V8DataModel::assign(const std::string& location, - const std::string& expr, - const Arabica::DOM::Element& dataElem) { - v8::Locker locker; - v8::HandleScope handleScope; - v8::Context::Scope contextScope(_contexts.back()); - evalAsValue(location + " = " + expr); +void V8DataModel::init(const Arabica::DOM::Element& dataElem, + const Arabica::DOM::Document& doc, + const std::string& content) { + try { + assign(dataElem, doc, content); + } catch (Event e) { + // test 277 + std::string key; + if (HAS_ATTR(dataElem, "id")) { + key = ATTR(dataElem, "id"); + } else if (HAS_ATTR(dataElem, "location")) { + key = ATTR(dataElem, "location"); + } + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.front()); + + evalAsValue(key + " = undefined", true); + throw e; + } +}; + +void V8DataModel::init(const std::string& location, + const Data& data) { + try { + assign(location, data); + } catch (Event e) { + // test 277 + v8::Locker locker; + v8::HandleScope handleScope; + v8::Context::Scope contextScope(_contexts.front()); + + evalAsValue(location + " = undefined", true); + throw e; + } + } -v8::Handle V8DataModel::evalAsValue(const std::string& expr) { + +v8::Handle V8DataModel::evalAsValue(const std::string& expr, bool dontThrow) { v8::TryCatch tryCatch; v8::Handle source = v8::String::New(expr.c_str()); v8::Handle script = v8::Script::Compile(source); @@ -436,7 +524,7 @@ v8::Handle V8DataModel::evalAsValue(const std::string& expr) { if (script.IsEmpty() || result.IsEmpty()) { // throw an exception - if (tryCatch.HasCaught()) + if (tryCatch.HasCaught() && !dontThrow) throwExceptionEvent(tryCatch); } diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h index 7bea50c..7c4f2b3 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h @@ -39,36 +39,26 @@ public: virtual void pushContext(); virtual void popContext(); - virtual bool supportsJSON() { return true; } + virtual bool supportsJSON() { + return true; + } virtual void eval(const std::string& expr); + virtual void assign(const Arabica::DOM::Element& assignElem, + const Arabica::DOM::Document& doc, + const std::string& content); virtual void assign(const std::string& location, - const Arabica::DOM::Document& doc, - const Arabica::DOM::Element& assignElem); - virtual void assign(const std::string& location, - const std::string& expr, - const Arabica::DOM::Element& assignElem); - virtual void assign(const std::string& location, - const Data& data, - const Arabica::DOM::Element& assignElem); - - virtual void init(const std::string& location, - const Arabica::DOM::Document& doc, - const Arabica::DOM::Element& dataElem) { - assign(location, doc, dataElem); - }; - virtual void init(const std::string& location, - const std::string& expr, - const Arabica::DOM::Element& dataElem) { - assign(location, expr, dataElem); - } + const Data& data); + + virtual void init(const Arabica::DOM::Element& dataElem, + const Arabica::DOM::Document& doc, + const std::string& content); virtual void init(const std::string& location, - const Data& data, - const Arabica::DOM::Element& dataElem) { - assign(location, data, dataElem); - } + const Data& data); virtual Data getStringAsData(const std::string& content); + virtual Data getValueAsData(const v8::Handle& value, + std::set& alreadySeen); virtual Data getValueAsData(const v8::Handle& value); virtual bool isDeclared(const std::string& expr); @@ -90,7 +80,7 @@ protected: static v8::Handle getAttribute(v8::Local property, const v8::AccessorInfo& info); static void setWithException(v8::Local property, v8::Local value, const v8::AccessorInfo& info); - v8::Handle evalAsValue(const std::string& expr); + v8::Handle evalAsValue(const std::string& expr, bool dontThrow = false); v8::Handle getDataAsValue(const Data& data); v8::Handle getDocumentAsValue(const Arabica::DOM::Document& doc); void throwExceptionEvent(const v8::TryCatch& tryCatch); diff --git a/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp b/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp index 69970dd..6911480 100644 --- a/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp +++ b/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp @@ -52,7 +52,7 @@ bool NULLDataModel::validate(const std::string& location, const std::string& sch } uint32_t NULLDataModel::getLength(const std::string& expr) { - return 0; + return 0; } void NULLDataModel::eval(const std::string& expr) { @@ -63,9 +63,9 @@ bool NULLDataModel::isDeclared(const std::string& expr) { } /** - * The boolean expression language consists of the In predicate only. It has the - * form 'In(id)', where id is the id of a state in the enclosing state machine. - * The predicate must return 'true' if and only if that state is in the current + * The boolean expression language consists of the In predicate only. It has the + * form 'In(id)', where id is the id of a state in the enclosing state machine. + * The predicate must return 'true' if and only if that state is in the current * state configuration. */ bool NULLDataModel::evalAsBool(const std::string& expr) { @@ -73,14 +73,14 @@ bool NULLDataModel::evalAsBool(const std::string& expr) { boost::trim(trimmedExpr); if (!boost::istarts_with(trimmedExpr, "in")) return false; - + // find string in between brackets size_t start = trimmedExpr.find_first_of("("); size_t end = trimmedExpr.find_last_of(")"); if (start == std::string::npos || end == std::string::npos || start >= end) return false; start++; - + // split at comma std::stringstream ss(trimmedExpr.substr(start, end - start)); std::vector stateExprs; @@ -88,7 +88,7 @@ bool NULLDataModel::evalAsBool(const std::string& expr) { while(std::getline(ss, item, ',')) { stateExprs.push_back(item); } - + for (unsigned int i = 0; i < stateExprs.size(); i++) { // remove ticks size_t start = stateExprs[i].find_first_of("'"); @@ -101,7 +101,7 @@ bool NULLDataModel::evalAsBool(const std::string& expr) { } else { stateName = stateExprs[i]; } - + if (Interpreter::isMember(_interpreter->getState(stateName), _interpreter->getConfiguration())) { continue; } diff --git a/src/uscxml/plugins/datamodel/null/NULLDataModel.h b/src/uscxml/plugins/datamodel/null/NULLDataModel.h index eaa9dbd..423c5ff 100644 --- a/src/uscxml/plugins/datamodel/null/NULLDataModel.h +++ b/src/uscxml/plugins/datamodel/null/NULLDataModel.h @@ -36,30 +36,20 @@ public: virtual void pushContext(); virtual void popContext(); - virtual void eval(const std::string& expr); - virtual void assign(const std::string& location, - const Arabica::DOM::Document& doc, - const Arabica::DOM::Element& assignElem) {} - virtual void assign(const std::string& location, - const std::string& expr, - const Arabica::DOM::Element& assignElem) {} - virtual void assign(const std::string& location, - const Data& data, - const Arabica::DOM::Element& assignElem) {} - - virtual void init(const std::string& location, - const Arabica::DOM::Document& doc, - const Arabica::DOM::Element& dataElem) {}; - virtual void init(const std::string& location, - const std::string& expr, - const Arabica::DOM::Element& dataElem) {}; - virtual void init(const std::string& location, - const Data& data, - const Arabica::DOM::Element& dataElem) {}; + virtual void assign(const Arabica::DOM::Element& assignElem, + const Arabica::DOM::Document& doc, + const std::string& content) {} + virtual void assign(const std::string& location, const Data& data) {} + + virtual void init(const Arabica::DOM::Element& dataElem, + const Arabica::DOM::Document& doc, + const std::string& content) {} + virtual void init(const std::string& location, const Data& data) {} virtual Data getStringAsData(const std::string& content); virtual bool isDeclared(const std::string& expr); + virtual void eval(const std::string& expr); virtual std::string evalAsString(const std::string& expr); virtual bool evalAsBool(const std::string& expr); virtual double evalAsNumber(const std::string& expr); diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp index 75d6da9..f3af4b6 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.cpp @@ -21,7 +21,7 @@ bool connect(pluma::Host& host) { SWIDataModel::SWIDataModel() { } -boost::shared_ptr SWIDataModel::create(Interpreter* interpreter) { +boost::shared_ptr SWIDataModel::create(InterpreterImpl* interpreter) { boost::shared_ptr dm = boost::shared_ptr(new SWIDataModel()); dm->_interpreter = interpreter; @@ -134,16 +134,41 @@ std::string SWIDataModel::evalAsString(const std::string& expr) { return std::string(compound); } -void SWIDataModel::assign(const std::string& location, const Data& data) { - eval(data.atom); +void SWIDataModel::assign(const std::string& location, + const Arabica::DOM::Document& doc, + const Arabica::DOM::Element& assignElem) { + } +void SWIDataModel::assign(const std::string& location, + const std::string& expr, + const Arabica::DOM::Element& assignElem) { -void SWIDataModel::assign(const std::string& location, const std::string& expr) { eval(expr); } +void SWIDataModel::assign(const std::string& location, + const Data& data, + const Arabica::DOM::Element& assignElem) { + eval(data.atom); +} + +void SWIDataModel::init(const std::string& location, + const Arabica::DOM::Document& doc, + const Arabica::DOM::Element& dataElem) { + +} +void SWIDataModel::init(const std::string& location, + const std::string& expr, + const Arabica::DOM::Element& dataElem) { + +} +void SWIDataModel::init(const std::string& location, + const Data& data, + const Arabica::DOM::Element& dataElem) { -bool SWIDataModel::isDefined(const std::string& expr) { +} + +bool SWIDataModel::isDeclared(const std::string& expr) { return true; } -} \ No newline at end of file +} diff --git a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h index 52d1e34..5d95476 100644 --- a/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h +++ b/src/uscxml/plugins/datamodel/prolog/swi/SWIDataModel.h @@ -15,7 +15,7 @@ class SWIDataModel : public DataModelImpl { public: SWIDataModel(); virtual ~SWIDataModel(); - virtual boost::shared_ptr create(Interpreter* interpreter); + virtual boost::shared_ptr create(InterpreterImpl* interpreter); virtual std::set getNames() { std::set names; @@ -37,20 +37,39 @@ public: virtual void popContext(); virtual void eval(const std::string& expr); - virtual void assign(const std::string& location, const std::string& expr); - virtual void assign(const std::string& location, const Data& data); - virtual bool isDefined(const std::string& expr); + virtual bool isDeclared(const std::string& expr); virtual Data getStringAsData(const std::string& content); virtual std::string evalAsString(const std::string& expr); virtual bool evalAsBool(const std::string& expr); + virtual void assign(const std::string& location, + const Arabica::DOM::Document& doc, + const Arabica::DOM::Element& assignElem); + virtual void assign(const std::string& location, + const std::string& expr, + const Arabica::DOM::Element& assignElem); + virtual void assign(const std::string& location, + const Data& data, + const Arabica::DOM::Element& assignElem); + + virtual void init(const std::string& location, + const Arabica::DOM::Document& doc, + const Arabica::DOM::Element& dataElem); + virtual void init(const std::string& location, + const std::string& expr, + const Arabica::DOM::Element& dataElem); + virtual void init(const std::string& location, + const Data& data, + const Arabica::DOM::Element& dataElem); protected: Event _event; PlEngine* _plEngine; + std::string _name; + std::string _sessionId; }; #ifdef BUILD_AS_PLUGINS diff --git a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp index f874c86..eef8e51 100644 --- a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp +++ b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp @@ -27,7 +27,7 @@ XPathDataModel::XPathDataModel() { boost::shared_ptr XPathDataModel::create(InterpreterImpl* interpreter) { boost::shared_ptr dm = boost::shared_ptr(new XPathDataModel()); dm->_interpreter = interpreter; -// dm->_xpath.setVariableResolver(_varResolver); + // dm->_xpath->setVariableCompileTimeResolver(_varCTResolver); // dm->_xpath->setNamespaceContext(interpreter->getNSContext()); @@ -39,21 +39,21 @@ boost::shared_ptr XPathDataModel::create(InterpreterImpl* interpr dm->_doc = dm->_domFactory.createDocument("http://www.w3.org/2005/07/scxml", "", 0); dm->_datamodel = dm->_doc.createElement("datamodel"); dm->_doc.appendChild(dm->_datamodel); - + Element ioProcElem = dm->_doc.createElement("data"); ioProcElem.setAttribute("id", "_ioprocessors"); std::map::const_iterator ioProcIter = interpreter->getIOProcessors().begin(); while(ioProcIter != interpreter->getIOProcessors().end()) { Element ioProc = dm->_doc.createElement("processor"); ioProc.setAttribute("name", ioProcIter->first); - + Data ioProcData = ioProcIter->second.getDataModelVariables(); Element ioProcLoc = dm->_doc.createElement("location"); Text ioProcLocText = dm->_doc.createTextNode(ioProcData.compound["location"].atom); ioProcLoc.appendChild(ioProcLocText); ioProc.appendChild(ioProcLoc); ioProcElem.appendChild(ioProc); - + ioProcIter++; } dm->_datamodel.appendChild(ioProcElem); @@ -61,8 +61,7 @@ boost::shared_ptr XPathDataModel::create(InterpreterImpl* interpr NodeSet ioProcNodeSet; ioProcNodeSet.push_back(ioProcElem); dm->_varResolver.setVariable("_ioprocessors", ioProcNodeSet); - - + Element sessIdElem = dm->_doc.createElement("data"); sessIdElem.setAttribute("id", "_sessionid"); Text sessIdText = dm->_doc.createTextNode(interpreter->getSessionId()); @@ -73,13 +72,13 @@ boost::shared_ptr XPathDataModel::create(InterpreterImpl* interpr sessIdNodeSet.push_back(sessIdElem); dm->_varResolver.setVariable("_sessionid", sessIdNodeSet); - + Element nameElem = dm->_doc.createElement("data"); nameElem.setAttribute("id", "_name"); Text nameText = dm->_doc.createTextNode(interpreter->getName()); nameElem.appendChild(nameText); dm->_datamodel.appendChild(nameElem); - + NodeSet nameNodeSet; nameNodeSet.push_back(nameElem); dm->_varResolver.setVariable("_name", nameNodeSet); @@ -104,7 +103,7 @@ void XPathDataModel::setEvent(const Event& event) { eventElem.setAttribute("id", "_event"); Element eventDataElem = _doc.createElement("data"); - + NodeSet eventNodeSet; if (event.params.size() > 0) { std::multimap::const_iterator paramIter = event.params.begin(); @@ -131,14 +130,17 @@ void XPathDataModel::setEvent(const Event& event) { } } if (event.content.size() > 0) { - eventDataElem.setNodeValue(event.content); + Text textNode = _doc.createTextNode(Interpreter::spaceNormalize(event.content).c_str()); + eventDataElem.appendChild(textNode); + } + if (event.dom) { + Node importedNode = _doc.importNode(event.dom.getFirstChild(), true); + eventDataElem.appendChild(importedNode); } - + eventElem.appendChild(eventDataElem); eventNodeSet.push_back(eventElem); - -// std::cout << eventElem << std::endl; - + // do we need to replace an existing event? Node oldEventElem = _datamodel.getFirstChild(); while(oldEventElem) { @@ -148,7 +150,7 @@ void XPathDataModel::setEvent(const Event& event) { } oldEventElem = oldEventElem.getNextSibling(); } - + if (oldEventElem) { _datamodel.replaceChild(eventElem, oldEventElem); } else { @@ -167,7 +169,7 @@ bool XPathDataModel::validate(const std::string& location, const std::string& sc } uint32_t XPathDataModel::getLength(const std::string& expr) { - return 0; + return 0; } void XPathDataModel::eval(const std::string& expr) { @@ -193,9 +195,87 @@ double XPathDataModel::evalAsNumber(const std::string& expr) { return result.asNumber(); } +void XPathDataModel::assign(const Arabica::DOM::Element& assignElem, + const Arabica::DOM::Document& doc, + const std::string& content) { + std::string location; + if (HAS_ATTR(assignElem, "id")) { + location = ATTR(assignElem, "id"); + } else if (HAS_ATTR(assignElem, "location")) { + location = ATTR(assignElem, "location"); + } + + XPathValue key = _xpath.evaluate_expr(location, _doc); + NodeSet nodeSet; + if (doc) { + nodeSet.push_back(doc.getDocumentElement()); + assign(key, nodeSet, assignElem); + } else if (content.length() > 0) { + Text textNode = _doc.createTextNode(Interpreter::spaceNormalize(content)); + nodeSet.push_back(textNode); + assign(key, nodeSet, assignElem); + } else if (HAS_ATTR(assignElem, "expr")) { + XPathValue value = _xpath.evaluate_expr(ATTR(assignElem, "expr"), _doc); + assign(key, value, assignElem); + } else { + LOG(ERROR) << "assign element has no content"; + } + + std::cout << _datamodel << std::endl; +} + +void XPathDataModel::assign(const std::string& location, const Data& data) { + +} + +void XPathDataModel::init(const Arabica::DOM::Element& dataElem, + const Arabica::DOM::Document& doc, + const std::string& content) { + std::string location; + if (HAS_ATTR(dataElem, "id")) { + location = ATTR(dataElem, "id"); + } else if (HAS_ATTR(dataElem, "location")) { + location = ATTR(dataElem, "location"); + } + + Element container = _doc.createElement("data"); + container.setAttribute("id", location); + if (doc) { + Element data = doc.getDocumentElement(); + if (data.hasChildNodes()) { + Node dataClone = _doc.importNode(data, true); + container.appendChild(dataClone); + } + } else if (content.length() > 0) { + Text textNode = _doc.createTextNode(Interpreter::spaceNormalize(content)); + container.appendChild(textNode); + } else if (HAS_ATTR(dataElem, "expr")) { + XPathValue expr = _xpath.evaluate_expr(ATTR(dataElem, "expr"), _doc); + XPathValue key = _xpath.evaluate_expr(location, _doc); + assign(key, expr, dataElem); + for (int i = 0; expr.asNodeSet().size(); i++) + container.appendChild(expr.asNodeSet()[i]); + } else { + LOG(ERROR) << "data element has no content"; + } + _datamodel.appendChild(container); + + // put data element into nodeset and bind to xpath variable + NodeSet nodeSet; + nodeSet.push_back(container); + _varResolver.setVariable(location, nodeSet); + + std::cout << _datamodel << std::endl; +} + +void XPathDataModel::init(const std::string& location, const Data& data) { + +} + +#if 0 void XPathDataModel::assign(const std::string& location, - const Document& doc, - const Arabica::DOM::Element& dataElem) { + const Document& doc, + const Arabica::DOM::Element& dataElem) { XPathValue key = _xpath.evaluate_expr(location, _doc); NodeSet nodeSet; nodeSet.push_back(doc.getDocumentElement()); @@ -203,15 +283,15 @@ void XPathDataModel::assign(const std::string& location, } void XPathDataModel::assign(const std::string& location, - const Data& data, - const Arabica::DOM::Element& dataElem) { + const Data& data, + const Arabica::DOM::Element& dataElem) { // assert(false); // std::cout << location << " = " << data << std::endl; } void XPathDataModel::assign(const std::string& location, - const std::string& expr, - const Arabica::DOM::Element& dataElem) { + const std::string& expr, + const Arabica::DOM::Element& dataElem) { std::string realExpr = (HAS_ATTR(dataElem, "expr") ? ATTR(dataElem, "expr") : expr); XPathValue key = _xpath.evaluate_expr(location, _doc); XPathValue value = _xpath.evaluate_expr(realExpr, _doc); @@ -219,8 +299,8 @@ void XPathDataModel::assign(const std::string& location, } void XPathDataModel::init(const std::string& location, - const Document& doc, - const Arabica::DOM::Element& dataElem) { + const Document& doc, + const Arabica::DOM::Element& dataElem) { Element container = _doc.createElement("data"); container.setAttribute("id", location); Element data = doc.getDocumentElement(); @@ -229,7 +309,7 @@ void XPathDataModel::init(const std::string& location, container.appendChild(dataClone); } _datamodel.appendChild(container); - + // put data element into nodeset and bind to xpath variable NodeSet nodeSet; nodeSet.push_back(container); @@ -237,11 +317,11 @@ void XPathDataModel::init(const std::string& location, } void XPathDataModel::init(const std::string& location, - const std::string& expr, - const Arabica::DOM::Element& dataElem) { + const std::string& expr, + const Arabica::DOM::Element& dataElem) { Element data = _doc.createElement("data"); data.setAttribute("id", location); - + if (expr.length() > 0) { Text textNode = _doc.createTextNode(expr.c_str()); data.appendChild(textNode); @@ -255,182 +335,195 @@ void XPathDataModel::init(const std::string& location, } void XPathDataModel::init(const std::string& location, - const Data& data, - const Arabica::DOM::Element& dataElem) { - assert(false); + const Data& data, + const Arabica::DOM::Element& dataElem) { +// XPathValue key = _xpath.evaluate_expr(location, _doc); + init(location, data.atom, dataElem); } +#endif void XPathDataModel::assign(XPathValue& key, - const XPathValue& value, - const Arabica::DOM::Element& assignElem) { + const XPathValue& value, + const Arabica::DOM::Element& assignElem) { switch (value.type()) { - case STRING: - assign(key, value.asString(), assignElem); - break; - case BOOL: - assign(key, value.asBool(), assignElem); - break; - case NUMBER: - assign(key, value.asNumber(), assignElem); - break; - case NODE_SET: - assign(key, value.asNodeSet(), assignElem); - break; - case ANY: - throw Event("error.execution", Event::PLATFORM); + case STRING: + assign(key, value.asString(), assignElem); + break; + case BOOL: + assign(key, value.asBool(), assignElem); + break; + case NUMBER: + assign(key, value.asNumber(), assignElem); + break; + case NODE_SET: + assign(key, value.asNodeSet(), assignElem); + break; + case ANY: + throw Event("error.execution", Event::PLATFORM); } } void XPathDataModel::assign(XPathValue& key, - const std::string& value, - const Arabica::DOM::Element& assignElem) { + const std::string& value, + const Arabica::DOM::Element& assignElem) { switch (key.type()) { - case NODE_SET: { - if (key.asNodeSet().size() == 0) - return; - Node node = key.asNodeSet()[0]; + case NODE_SET: { + if (key.asNodeSet().size() == 0) + return; + for (int i = 0; i < key.asNodeSet().size(); i++) { + Node node = key.asNodeSet()[i]; switch (node.getNodeType()) { - case Node_base::ATTRIBUTE_NODE: { - Attr attr(node); - attr.setValue(value); - break; - } - case Node_base::TEXT_NODE: { - Text text(node); - text.setNodeValue(value); - break; - } - case Node_base::ELEMENT_NODE: { - Element element(node); - if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "addattribute")) { - // addattribute: Add an attribute with the name specified by 'attr' - // and value specified by 'expr' to the node specified by 'location'. - if (!HAS_ATTR(assignElem, "attr")) - throw Event("error.execution", Event::PLATFORM); - element.setAttribute(ATTR(assignElem, "attr"), value); - } - break; + case Node_base::ATTRIBUTE_NODE: { + Attr attr(node); + attr.setValue(value); + break; + } + case Node_base::TEXT_NODE: { + Text text(node); + text.setNodeValue(value); + break; + } + case Node_base::ELEMENT_NODE: { + Element element(node); + if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "addattribute")) { + // addattribute: Add an attribute with the name specified by 'attr' + // and value specified by 'expr' to the node specified by 'location'. + if (!HAS_ATTR(assignElem, "attr")) + throw Event("error.execution", Event::PLATFORM); + element.setAttribute(ATTR(assignElem, "attr"), value); + } else { + /// test 547 + while(element.hasChildNodes()) + element.removeChild(element.getChildNodes().item(0)); + Text text = _doc.createTextNode(value); + element.appendChild(text); } - default: - throw Event("error.execution", Event::PLATFORM); - break; + break; + } + default: + throw Event("error.execution", Event::PLATFORM); + break; } - break; } - case STRING: - case BOOL: - case NUMBER: - case ANY: - throw Event("error.execution", Event::PLATFORM); - break; - default: - break; + break; + } + case STRING: + case BOOL: + case NUMBER: + case ANY: + throw Event("error.execution", Event::PLATFORM); + break; + default: + break; } } void XPathDataModel::assign(XPathValue& key, - const double value, - const Arabica::DOM::Element& assignElem) { + const double value, + const Arabica::DOM::Element& assignElem) { + assign(key, toStr(value), assignElem); } void XPathDataModel::assign(XPathValue& key, - const bool value, - const Arabica::DOM::Element& assignElem) { + const bool value, + const Arabica::DOM::Element& assignElem) { } void XPathDataModel::assign(XPathValue& key, - const NodeSet& value, - const Arabica::DOM::Element& assignElem) { + const NodeSet& value, + const Arabica::DOM::Element& assignElem) { switch (key.type()) { - case NODE_SET: { - if (key.asNodeSet().size() == 0) - return; - Node node = key.asNodeSet()[0]; + case NODE_SET: { + if (key.asNodeSet().size() == 0) + return; + for (int i = 0; i < key.asNodeSet().size(); i++) { + Node node = key.asNodeSet()[i]; switch (node.getNodeType()) { - case Node_base::ELEMENT_NODE: { - Element element(node); - if (false) { - } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "firstchild")) { - // firstchild: Insert the value specified by 'expr' before all of the children at 'location'. - for (int i = value.size(); i; i--) { - Node importedNode = _doc.importNode(value[i-1], true); - element.insertBefore(importedNode, element.getFirstChild()); - } - } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "lastchild")) { - // lastchild: Insert the value specified by 'expr' after all of the children at 'location'. - for (int i = 0; i < value.size(); i++) { - Node importedNode = _doc.importNode(value[i], true); - element.appendChild(importedNode); - } - } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "previoussibling")) { - // previoussibling: Insert the value specified by 'expr' before the - // node specified by 'location', keeping the same parent. - Node parent = element.getParentNode(); - if (!parent) - throw Event("error.execution", Event::PLATFORM); - for (int i = 0; i < value.size(); i++) { - Node importedNode = _doc.importNode(value[i], true); - parent.insertBefore(importedNode, element); - } - } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "nextsibling")) { - // nextsibling: Insert the value specified by 'expr' after the node - // specified by 'location', keeping the same parent. - Node parent = element.getParentNode(); - if (!parent) - throw Event("error.execution", Event::PLATFORM); - for (int i = value.size(); i; i--) { - Node importedNode = _doc.importNode(value[i-1], true); - Node nextSibling = element.getNextSibling(); - if (nextSibling) { - parent.insertBefore(importedNode, element.getNextSibling()); - } else { - parent.appendChild(importedNode); - } - } - } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "replace")) { - // replace: Replace the node specified by 'location' by the value specified by 'expr'. - Node parent = element.getParentNode(); - if (!parent) - throw Event("error.execution", Event::PLATFORM); - if (value.size() != 1) - throw Event("error.execution", Event::PLATFORM); - Node importedNode = _doc.importNode(value[0], true); - parent.replaceChild(importedNode, element); - } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "delete")) { - // delete: Delete the node specified by 'location'. ('expr' is ignored.). - Node parent = element.getParentNode(); - if (!parent) - throw Event("error.execution", Event::PLATFORM); - parent.removeChild(element); - } else { - // replacechildren: Replace all the children at 'location' with the value specified by 'expr'. - while(element.hasChildNodes()) - element.removeChild(element.getChildNodes().item(0)); - for (int i = 0; i < value.size(); i++) { - Node importedNode = _doc.importNode(value[i], true); - element.appendChild(importedNode); + case Node_base::ELEMENT_NODE: { + Element element(node); + if (false) { + } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "firstchild")) { + // firstchild: Insert the value specified by 'expr' before all of the children at 'location'. + for (int i = value.size(); i; i--) { + Node importedNode = _doc.importNode(value[i-1], true); + element.insertBefore(importedNode, element.getFirstChild()); + } + } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "lastchild")) { + // lastchild: Insert the value specified by 'expr' after all of the children at 'location'. + for (int i = 0; i < value.size(); i++) { + Node importedNode = _doc.importNode(value[i], true); + element.appendChild(importedNode); + } + } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "previoussibling")) { + // previoussibling: Insert the value specified by 'expr' before the + // node specified by 'location', keeping the same parent. + Node parent = element.getParentNode(); + if (!parent) + throw Event("error.execution", Event::PLATFORM); + for (int i = 0; i < value.size(); i++) { + Node importedNode = _doc.importNode(value[i], true); + parent.insertBefore(importedNode, element); + } + } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "nextsibling")) { + // nextsibling: Insert the value specified by 'expr' after the node + // specified by 'location', keeping the same parent. + Node parent = element.getParentNode(); + if (!parent) + throw Event("error.execution", Event::PLATFORM); + for (int i = value.size(); i; i--) { + Node importedNode = _doc.importNode(value[i-1], true); + Node nextSibling = element.getNextSibling(); + if (nextSibling) { + parent.insertBefore(importedNode, element.getNextSibling()); + } else { + parent.appendChild(importedNode); } } - break; + } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "replace")) { + // replace: Replace the node specified by 'location' by the value specified by 'expr'. + Node parent = element.getParentNode(); + if (!parent) + throw Event("error.execution", Event::PLATFORM); + if (value.size() != 1) + throw Event("error.execution", Event::PLATFORM); + Node importedNode = _doc.importNode(value[0], true); + parent.replaceChild(importedNode, element); + } else if (HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "delete")) { + // delete: Delete the node specified by 'location'. ('expr' is ignored.). + Node parent = element.getParentNode(); + if (!parent) + throw Event("error.execution", Event::PLATFORM); + parent.removeChild(element); + } else { + // replacechildren: Replace all the children at 'location' with the value specified by 'expr'. + while(element.hasChildNodes()) + element.removeChild(element.getChildNodes().item(0)); + for (int i = 0; i < value.size(); i++) { + Node importedNode = _doc.importNode(value[i], true); + element.appendChild(importedNode); + } } - default: - throw Event("error.execution", Event::PLATFORM); - break; + break; + } + default: + throw Event("error.execution", Event::PLATFORM); + break; } - break; } - case STRING: - case BOOL: - case NUMBER: - case ANY: - throw Event("error.execution", Event::PLATFORM); - break; + break; + } + case STRING: + case BOOL: + case NUMBER: + case ANY: + throw Event("error.execution", Event::PLATFORM); + break; } } XPathValue - NodeSetVariableResolver::resolveVariable(const std::string& namepaceUri, - const std::string& name) const { +NodeSetVariableResolver::resolveVariable(const std::string& namepaceUri, + const std::string& name) const { std::map >::const_iterator n = _variables.find(name); if(n == _variables.end()) { throw Event("error.execution"); @@ -439,15 +532,15 @@ XPathValue } XPathFunction* - XPathFunctionResolver::resolveFunction(const std::string& namespace_uri, - const std::string& name, - const std::vector >& argExprs) const { +XPathFunctionResolver::resolveFunction(const std::string& namespace_uri, + const std::string& name, + const std::vector >& argExprs) const { if (boost::iequals(name, "in")) { return new XPathFunctionIn(1, -1, argExprs, _interpreter); } return _xpathFuncRes.resolveFunction(namespace_uri, name, argExprs); } - + std::vector > XPathFunctionResolver::validNames() const { std::vector > names = _xpathFuncRes.validNames(); names.push_back(std::make_pair("", "In")); @@ -455,7 +548,7 @@ std::vector > XPathFunctionResolver::validNa } bool XPathFunctionIn::doEvaluate(const Node& context, - const ExecutionContext& executionContext) const { + const ExecutionContext& executionContext) const { for (int i = 0; i < argCount(); i++) { XPathValue stateName = arg(i, context, executionContext); if (stateName.type() == STRING) { diff --git a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h index d028129..5f5952c 100644 --- a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h +++ b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h @@ -18,42 +18,44 @@ namespace uscxml { class XPathFunctionIn : public Arabica::XPath::BooleanXPathFunction { public: XPathFunctionIn(int minArgs, - int maxArgs, - const std::vector >& args, - InterpreterImpl* interpreter) : + int maxArgs, + const std::vector >& args, + InterpreterImpl* interpreter) : BooleanXPathFunction(minArgs, maxArgs, args), _interpreter(interpreter) {} protected: bool doEvaluate(const Arabica::DOM::Node& context, - const Arabica::XPath::ExecutionContext& executionContext) const; + const Arabica::XPath::ExecutionContext& executionContext) const; InterpreterImpl* _interpreter; }; class XPathFunctionResolver : public Arabica::XPath::FunctionResolver { public: virtual ~XPathFunctionResolver() { } - - virtual Arabica::XPath::XPathFunction* - resolveFunction(const std::string& namespace_uri, - const std::string& name, - const std::vector >& argExprs) const; - - virtual std::vector > validNames() const; - void setInterpreter(InterpreterImpl* interpreter) { _interpreter = interpreter; } + + virtual Arabica::XPath::XPathFunction* + resolveFunction(const std::string& namespace_uri, + const std::string& name, + const std::vector >& argExprs) const; + + virtual std::vector > validNames() const; + void setInterpreter(InterpreterImpl* interpreter) { + _interpreter = interpreter; + } protected: Arabica::XPath::StandardXPathFunctionResolver _xpathFuncRes; InterpreterImpl* _interpreter; }; - + class NodeSetVariableResolver : public Arabica::XPath::VariableResolver { public: Arabica::XPath::XPathValue resolveVariable(const std::string& namepaceUri, - const std::string& name) const; + const std::string& name) const; void setVariable(const std::string& name, const Arabica::XPath::NodeSet& value) { _variables[name] = value; } - + private: std::map > _variables; }; @@ -80,25 +82,15 @@ public: virtual void popContext(); virtual void eval(const std::string& expr); - virtual void assign(const std::string& location, - const Arabica::DOM::Document& doc, - const Arabica::DOM::Element& assignElem); - virtual void assign(const std::string& location, - const std::string& expr, - const Arabica::DOM::Element& assignElem); - virtual void assign(const std::string& location, - const Data& data, - const Arabica::DOM::Element& assignElem); - - virtual void init(const std::string& location, - const Arabica::DOM::Document& doc, - const Arabica::DOM::Element& dataElem); - virtual void init(const std::string& location, - const std::string& expr, - const Arabica::DOM::Element& dataElem); - virtual void init(const std::string& location, - const Data& data, - const Arabica::DOM::Element& dataElem); + virtual void assign(const Arabica::DOM::Element& assignElem, + const Arabica::DOM::Document& doc, + const std::string& content); + virtual void assign(const std::string& location, const Data& data); + + virtual void init(const Arabica::DOM::Element& dataElem, + const Arabica::DOM::Document& doc, + const std::string& content); + virtual void init(const std::string& location, const Data& data); virtual Data getStringAsData(const std::string& content); virtual bool isDeclared(const std::string& expr); @@ -114,21 +106,21 @@ protected: Arabica::DOM::Document _doc; void assign(Arabica::XPath::XPathValue& key, - const Arabica::XPath::XPathValue& value, - const Arabica::DOM::Element& assignElem); + const Arabica::XPath::XPathValue& value, + const Arabica::DOM::Element& assignElem); void assign(Arabica::XPath::XPathValue& key, - const std::string& value, - const Arabica::DOM::Element& assignElem); + const std::string& value, + const Arabica::DOM::Element& assignElem); void assign(Arabica::XPath::XPathValue& key, - const double value, - const Arabica::DOM::Element& assignElem); + const double value, + const Arabica::DOM::Element& assignElem); void assign(Arabica::XPath::XPathValue& key, - const bool value, - const Arabica::DOM::Element& assignElem); + const bool value, + const Arabica::DOM::Element& assignElem); void assign(Arabica::XPath::XPathValue& key, - const Arabica::XPath::NodeSet& value, - const Arabica::DOM::Element& assignElem); - + const Arabica::XPath::NodeSet& value, + const Arabica::DOM::Element& assignElem); + NodeSetVariableResolver _varResolver; XPathFunctionResolver _funcResolver; diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp index fc2ac2b..9eafbcf 100644 --- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp +++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp @@ -48,9 +48,9 @@ void USCXMLInvoker::invoke(const InvokeRequest& req) { } else if (req.dom) { _invokedInterpreter = Interpreter::fromDOM(req.dom); } else if (req.content.size() > 0) { - LOG(ERROR) << "Instantiating nested SCXML interpreter by content or expr not supported yet"; + _invokedInterpreter = Interpreter::fromXML(req.content); } else { - LOG(ERROR) << "Cannot invoke nested SCXML interpreter, neither src attribute nor DOM is given"; + LOG(ERROR) << "Cannot invoke nested SCXML interpreter, neither src attribute nor content nor DOM is given"; } if (_invokedInterpreter) { DataModel dataModel(_invokedInterpreter.getImpl()->getDataModel()); diff --git a/test/samples/w3c/ecma/test530.scxml b/test/samples/w3c/ecma/test530.scxml index 9361181..0090907 100644 --- a/test/samples/w3c/ecma/test530.scxml +++ b/test/samples/w3c/ecma/test530.scxml @@ -18,7 +18,9 @@ is evaluated at the right time, we should get invoke.done, otherwise an error - - + + + diff --git a/test/src/test-arabica-xpath.cpp b/test/src/test-arabica-xpath.cpp index 2bcf605..2991dc0 100644 --- a/test/src/test-arabica-xpath.cpp +++ b/test/src/test-arabica-xpath.cpp @@ -9,28 +9,25 @@ typedef string_adaptor SA; -class NodeSetVariableResolver : public Arabica::XPath::VariableResolver -{ - //typedef string_adaptorstring_adaptor; +class NodeSetVariableResolver : public Arabica::XPath::VariableResolver { + //typedef string_adaptorstring_adaptor; public: - virtual Arabica::XPath::XPathValue resolveVariable(const string_type& /* namepace_uri */, - const string_type& name) const - { - using namespace Arabica::XPath; - typename VarMap::const_iterator n = map_.find(name); - if(n == map_.end()) - throw UnboundVariableException(string_adaptor::asStdString(name)); - return XPathValue(new NodeSetValue((*n).second)); - } // resolveVariable - - void setVariable(const string_type& name, const Arabica::XPath::NodeSet& value) - { - map_[name] = value; - } // setVariable - + virtual Arabica::XPath::XPathValue resolveVariable(const string_type& /* namepace_uri */, + const string_type& name) const { + using namespace Arabica::XPath; + typename VarMap::const_iterator n = map_.find(name); + if(n == map_.end()) + throw UnboundVariableException(string_adaptor::asStdString(name)); + return XPathValue(new NodeSetValue((*n).second)); + } // resolveVariable + + void setVariable(const string_type& name, const Arabica::XPath::NodeSet& value) { + map_[name] = value; + } // setVariable + private: - typedef std::map > VarMap; - VarMap map_; + typedef std::map > VarMap; + VarMap map_; }; // class NodeSetVariableResolver Arabica::XPath::XPath parser; @@ -50,49 +47,46 @@ Arabica::DOM::ProcessingInstruction processingInstr Arabica::DOM::Document chapters_; Arabica::DOM::Document numbers_; -class StringVariableResolver : public Arabica::XPath::VariableResolver -{ +class StringVariableResolver : public Arabica::XPath::VariableResolver { public: - virtual Arabica::XPath::XPathValue resolveVariable(const string_type& /* namespace_uri */, - const string_type& name) const - { - using namespace Arabica::XPath; - typename VarMap::const_iterator n = map_.find(name); - if(n == map_.end()) - throw UnboundVariableException(string_adaptor::asStdString(name)); - return XPathValue(new StringValue((*n).second)); - } // resolveVariable - - void setVariable(const string_type& name, const string_type& value) - { - map_[name] = value; - } // setVariable - + virtual Arabica::XPath::XPathValue resolveVariable(const string_type& /* namespace_uri */, + const string_type& name) const { + using namespace Arabica::XPath; + typename VarMap::const_iterator n = map_.find(name); + if(n == map_.end()) + throw UnboundVariableException(string_adaptor::asStdString(name)); + return XPathValue(new StringValue((*n).second)); + } // resolveVariable + + void setVariable(const string_type& name, const string_type& value) { + map_[name] = value; + } // setVariable + private: - typedef std::map VarMap; - VarMap map_; + typedef std::map VarMap; + VarMap map_; }; // StringVariableResolver int main(int argc, char** argv) { - + factory_ = Arabica::SimpleDOM::DOMImplementation::getDOMImplementation(); document_ = factory_.createDocument(SA::construct_from_utf8(""), SA::construct_from_utf8(""), 0); root_ = document_.createElement("root"); document_.appendChild(root_); assert(root_); - + element1_ = document_.createElement(SA::construct_from_utf8("child1")); element2_ = document_.createElement(SA::construct_from_utf8("child2")); element3_ = document_.createElement(SA::construct_from_utf8("child3")); - + element1_.setAttribute(SA::construct_from_utf8("one"), SA::construct_from_utf8("1")); - + element2_.setAttribute(SA::construct_from_utf8("one"), SA::construct_from_utf8("1")); element2_.setAttribute(SA::construct_from_utf8("two"), SA::construct_from_utf8("1")); element2_.setAttribute(SA::construct_from_utf8("three"), SA::construct_from_utf8("1")); element2_.setAttribute(SA::construct_from_utf8("four"), SA::construct_from_utf8("1")); - + text_ = document_.createTextNode(SA::construct_from_utf8("data")); comment_ = document_.createComment(SA::construct_from_utf8("comment")); processingInstruction_ = document_.createProcessingInstruction(SA::construct_from_utf8("target"), SA::construct_from_utf8("data")); @@ -101,13 +95,13 @@ int main(int argc, char** argv) { element2_.appendChild(spinkle_); element2_.appendChild(comment_); element2_.appendChild(processingInstruction_); - + attr_ = element1_.getAttributeNode(SA::construct_from_utf8("one")); - + root_.appendChild(element1_); root_.appendChild(element2_); root_.appendChild(element3_); - + chapters_ = factory_.createDocument(SA::construct_from_utf8(""), SA::construct_from_utf8(""), 0); chapters_.appendChild(chapters_.createElement(SA::construct_from_utf8("document"))); chapters_.getFirstChild().appendChild(chapters_.createElement(SA::construct_from_utf8("chapter"))).appendChild(chapters_.createTextNode(SA::construct_from_utf8("one"))); @@ -115,7 +109,7 @@ int main(int argc, char** argv) { chapters_.getFirstChild().appendChild(chapters_.createElement(SA::construct_from_utf8("chapter"))).appendChild(chapters_.createTextNode(SA::construct_from_utf8("three"))); chapters_.getFirstChild().appendChild(chapters_.createElement(SA::construct_from_utf8("chapter"))).appendChild(chapters_.createTextNode(SA::construct_from_utf8("four"))); chapters_.getFirstChild().appendChild(chapters_.createElement(SA::construct_from_utf8("chapter"))).appendChild(chapters_.createTextNode(SA::construct_from_utf8("five"))); - + numbers_ = factory_.createDocument(SA::construct_from_utf8(""), SA::construct_from_utf8(""), 0); numbers_.appendChild(numbers_.createElement(SA::construct_from_utf8("doc"))); numbers_.getFirstChild().appendChild(numbers_.createElement(SA::construct_from_utf8("number"))).appendChild(numbers_.createTextNode(SA::construct_from_utf8("1"))); @@ -131,68 +125,68 @@ int main(int argc, char** argv) { std::cout << numbers_ << std::endl; std::cout << chapters_ << std::endl; - + if (false) { - using namespace Arabica::XPath; - StringVariableResolver svr; - svr.setVariable(SA::construct_from_utf8("index"), SA::construct_from_utf8("1")); - - parser.setVariableResolver(svr); - XPathValue result = parser.evaluate(SA::construct_from_utf8("/root/*[@two = $index]"), document_); - assert(NODE_SET == result.type()); - assert(element2_ == result.asNodeSet()[0]); - - parser.resetVariableResolver(); - } // test18 + using namespace Arabica::XPath; + StringVariableResolver svr; + svr.setVariable(SA::construct_from_utf8("index"), SA::construct_from_utf8("1")); + + parser.setVariableResolver(svr); + XPathValue result = parser.evaluate(SA::construct_from_utf8("/root/*[@two = $index]"), document_); + assert(NODE_SET == result.type()); + assert(element2_ == result.asNodeSet()[0]); + + parser.resetVariableResolver(); + } // test18 if (false) { - using namespace Arabica::XPath; - XPathExpression xpath = parser.compile(SA::construct_from_utf8("root/*[position() = 2]")); - XPathValue result = xpath.evaluate(document_); - - assert(NODE_SET == result.type()); - assert(1 == result.asNodeSet().size()); - Arabica::DOM::Node n = result.asNodeSet()[0]; - assert(element2_ == n); - } // test19 + using namespace Arabica::XPath; + XPathExpression xpath = parser.compile(SA::construct_from_utf8("root/*[position() = 2]")); + XPathValue result = xpath.evaluate(document_); + + assert(NODE_SET == result.type()); + assert(1 == result.asNodeSet().size()); + Arabica::DOM::Node n = result.asNodeSet()[0]; + assert(element2_ == n); + } // test19 if (false) { - using namespace Arabica::XPath; - Arabica::DOM::DocumentFragment frag = document_.createDocumentFragment(); - frag.appendChild(document_.createElement(SA::construct_from_utf8("foo"))); - - NodeSetVariableResolver svr; - NodeSet ns; - ns.push_back(frag); - svr.setVariable(SA::construct_from_utf8("fruit"), ns); - parser.setVariableResolver(svr); - - XPathValue result = parser.evaluate_expr(SA::construct_from_utf8("$fruit/foo|/root/child3"), document_); - assert(NODE_SET == result.type()); - assert(2 == result.asNodeSet().size()); - assert(element3_ == result.asNodeSet()[0]); - } // testUnion11 + using namespace Arabica::XPath; + Arabica::DOM::DocumentFragment frag = document_.createDocumentFragment(); + frag.appendChild(document_.createElement(SA::construct_from_utf8("foo"))); + + NodeSetVariableResolver svr; + NodeSet ns; + ns.push_back(frag); + svr.setVariable(SA::construct_from_utf8("fruit"), ns); + parser.setVariableResolver(svr); + + XPathValue result = parser.evaluate_expr(SA::construct_from_utf8("$fruit/foo|/root/child3"), document_); + assert(NODE_SET == result.type()); + assert(2 == result.asNodeSet().size()); + assert(element3_ == result.asNodeSet()[0]); + } // testUnion11 if (false) { - using namespace Arabica::XPath; - XPathValue result = parser.evaluate_expr(SA::construct_from_utf8("local-name(/root)"), document_); - assert(STRING == result.type()); - assert(SA::construct_from_utf8("root") == result.asString()); - } // testLocalNameFn1 + using namespace Arabica::XPath; + XPathValue result = parser.evaluate_expr(SA::construct_from_utf8("local-name(/root)"), document_); + assert(STRING == result.type()); + assert(SA::construct_from_utf8("root") == result.asString()); + } // testLocalNameFn1 { - using namespace Arabica::XPath; - Arabica::DOM::DocumentFragment frag = document_.createDocumentFragment(); - frag.appendChild(document_.createElement("foo")); - - NodeSetVariableResolver svr; - NodeSet ns; - ns.push_back(frag); - svr.setVariable("fruit", ns); - parser.setVariableResolver(svr); - - XPathValue result = parser.evaluate(SA::construct_from_utf8("local-name($fruit/foo) = 'foo'"), document_); + using namespace Arabica::XPath; + Arabica::DOM::DocumentFragment frag = document_.createDocumentFragment(); + frag.appendChild(document_.createElement("foo")); + + NodeSetVariableResolver svr; + NodeSet ns; + ns.push_back(frag); + svr.setVariable("fruit", ns); + parser.setVariableResolver(svr); + + XPathValue result = parser.evaluate(SA::construct_from_utf8("local-name($fruit/foo) = 'foo'"), document_); std::cout << result.asBool() << std::endl; - } + } } \ No newline at end of file -- cgit v0.12