diff options
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | src/uscxml/Interpreter.cpp | 17 | ||||
-rw-r--r-- | src/uscxml/Message.cpp | 24 | ||||
-rw-r--r-- | src/uscxml/Message.h | 2 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp | 151 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/xpath/XPathDataModel.h | 11 | ||||
-rw-r--r-- | src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp | 4 | ||||
-rw-r--r-- | test/samples/w3c/xpath/test539.txt | 4 | ||||
-rw-r--r-- | test/samples/w3c/xpath/test540.txt | 3 | ||||
-rw-r--r-- | test/samples/w3c/xpath/test552.txt | 1 | ||||
-rw-r--r-- | test/samples/w3c/xpath/test557.txt | 4 | ||||
-rw-r--r-- | test/samples/w3c/xpath/test558.txt | 3 |
12 files changed, 190 insertions, 36 deletions
@@ -12,7 +12,7 @@ the respective build-process and did not precompile required libraries. * Full ECMAScript datamodel using Google's v8 and JavaScriptCore (JSC is incomplete) * Full NULL datamodel with required <tt>In</tt> predicate * Early Prolog datamodel using SWI prolog - * Rudimentary support for XPath datamodel (Draft and tests are in conflict imho) + * Rudimentary support for XPath datamodel (W3C tests not yet implementable) * <b>Invokers</b> * <tt>scxml</tt>: Invoke a nested scxml interpreter * <tt>dirmon</tt>: Watches a directory for changes to files diff --git a/src/uscxml/Interpreter.cpp b/src/uscxml/Interpreter.cpp index 21f64cb..dea7299 100644 --- a/src/uscxml/Interpreter.cpp +++ b/src/uscxml/Interpreter.cpp @@ -382,12 +382,12 @@ void InterpreterImpl::normalize(Arabica::DOM::Element<std::string>& scxml) { } void InterpreterImpl::receiveInternal(const Event& event) { -// std::cout << _name << " 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 << _name << " receive: " << event.name << std::endl; + std::cout << _name << " receive: " << event.name << std::endl; if (toFront) { _externalQueue.push_front(event); } else { @@ -475,6 +475,12 @@ void InterpreterImpl::processDOMorText(const Arabica::DOM::Node<std::string>& no inputSource.setByteStream(ssPtr); if (parser.parse(inputSource) && parser.getDocument()) { dom = parser.getDocument(); + Node<std::string> content = dom.getDocumentElement(); + assert(content.getNodeType() == Node_base::ELEMENT_NODE); + Node<std::string> container = dom.createElement("container"); + dom.replaceChild(container, content); + container.appendChild(content); + std::cout << dom << std::endl; return; } else { text = srcContent.str(); @@ -890,7 +896,7 @@ bool InterpreterImpl::nameMatch(const std::string& transitionEvent, const std::s return false; // naive case of single descriptor and exact match - if (boost::equals(transitionEvent, event)) + if (boost::iequals(transitionEvent, event)) return true; boost::char_separator<char> sep(" "); @@ -911,7 +917,7 @@ bool InterpreterImpl::nameMatch(const std::string& transitionEvent, const std::s return true; // are they already equal? - if (boost::equals(eventDesc, event)) + if (boost::iequals(eventDesc, event)) return true; // eventDesc has to be a real prefix of event now and therefore shorter @@ -919,7 +925,8 @@ bool InterpreterImpl::nameMatch(const std::string& transitionEvent, const std::s continue; // it is a prefix of the event name and event continues with .something - if (eventDesc.compare(event.substr(0, eventDesc.size())) == 0) + if (boost::istarts_with(event, eventDesc)) +// if (eventDesc.compare(event.substr(0, eventDesc.size())) == 0) if (event.find(".", eventDesc.size()) == eventDesc.size()) return true; } diff --git a/src/uscxml/Message.cpp b/src/uscxml/Message.cpp index c3f4281..27e01e2 100644 --- a/src/uscxml/Message.cpp +++ b/src/uscxml/Message.cpp @@ -110,6 +110,30 @@ Arabica::DOM::Document<std::string> Data::toDocument() { return document; } +Arabica::DOM::Node<std::string> Event::getFirstDOMElement() const { + Arabica::DOM::Node<std::string> data = dom.getDocumentElement().getFirstChild(); + while (data) { + if (data.getNodeType() == Arabica::DOM::Node_base::TEXT_NODE) { + std::string trimmed = boost::trim_copy(data.getNodeValue()); + if (trimmed.length() == 0) { + data = data.getNextSibling(); + continue; + } + } + break; + } + return data; +} + +Arabica::DOM::Document<std::string> Event::getStrippedDOM() const { + Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); + Arabica::DOM::Document<std::string> document = domFactory.createDocument("", "", 0); + if (dom) { + document.getDocumentElement().appendChild(document.importNode(getFirstDOMElement(), true)); + } + return document; +} + Arabica::DOM::Document<std::string> Event::toDocument() { Arabica::DOM::DOMImplementation<std::string> domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); Arabica::DOM::Document<std::string> document = data.toDocument(); diff --git a/src/uscxml/Message.h b/src/uscxml/Message.h index 27bd071..ea1e8ab 100644 --- a/src/uscxml/Message.h +++ b/src/uscxml/Message.h @@ -139,6 +139,8 @@ public: void setDOM(const Arabica::DOM::Document<std::string>& dom) { this->dom = dom; } + Arabica::DOM::Node<std::string> getFirstDOMElement() const; + Arabica::DOM::Document<std::string> getStrippedDOM() const; std::string getRaw() { return raw; diff --git a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp index 39616f8..6377af2 100644 --- a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp +++ b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp @@ -59,11 +59,7 @@ boost::shared_ptr<DataModelImpl> XPathDataModel::create(InterpreterImpl* interpr dm->_datamodel.appendChild(ioProcElem); NodeSet<std::string> ioProcNodeSet; - Node<std::string> node = ioProcElem.getFirstChild(); - while(node) { - ioProcNodeSet.push_back(node); - node = node.getNextSibling(); - } + ioProcNodeSet.push_back(ioProcElem); dm->_varResolver.setVariable("_ioprocessors", ioProcNodeSet); Element<std::string> sessIdElem = dm->_doc.createElement("data"); @@ -107,8 +103,41 @@ void XPathDataModel::setEvent(const Event& event) { eventElem.setAttribute("id", "_event"); Element<std::string> eventDataElem = _doc.createElement("data"); - NodeSet<std::string> eventNodeSet; + + { + // -- name + Element<std::string> eventNameElem = _doc.createElement("name"); + Text<std::string> eventName = _doc.createTextNode(event.name.c_str()); + eventNameElem.appendChild(eventName); + eventElem.appendChild(eventNameElem); + } + { + // -- origin + Element<std::string> eventOriginElem = _doc.createElement("origin"); + Text<std::string> eventOrigin = _doc.createTextNode(event.origin.c_str()); + eventOriginElem.appendChild(eventOrigin); + eventElem.appendChild(eventOriginElem); + } + { + // -- type + Element<std::string> eventTypeElem = _doc.createElement("type"); + Text<std::string> eventType; + switch (event.type) { + case Event::INTERNAL: + eventType = _doc.createTextNode("internal"); + break; + case Event::EXTERNAL: + eventType = _doc.createTextNode("external"); + break; + case Event::PLATFORM: + eventType = _doc.createTextNode("platform"); + break; + } + eventTypeElem.appendChild(eventType); + eventElem.appendChild(eventTypeElem); + } + if (event.params.size() > 0) { std::multimap<std::string, std::string>::const_iterator paramIter = event.params.begin(); while(paramIter != event.params.end()) { @@ -137,7 +166,7 @@ void XPathDataModel::setEvent(const Event& event) { Element<std::string> eventRawElem = _doc.createElement("raw"); Text<std::string> textNode = _doc.createTextNode(event.raw.c_str()); eventRawElem.appendChild(textNode); - eventDataElem.appendChild(eventRawElem); + eventElem.appendChild(eventRawElem); } if (event.content.size() > 0) { @@ -145,12 +174,12 @@ void XPathDataModel::setEvent(const Event& event) { eventDataElem.appendChild(textNode); } if (event.dom) { - Node<std::string> importedNode = _doc.importNode(event.dom.getFirstChild(), true); + Node<std::string> importedNode = _doc.importNode(event.getFirstDOMElement(), true); eventDataElem.appendChild(importedNode); } eventElem.appendChild(eventDataElem); - eventNodeSet.push_back(eventDataElem); + eventNodeSet.push_back(eventElem); // do we need to replace an existing event? Node<std::string> oldEventElem = _datamodel.getFirstChild(); @@ -283,12 +312,28 @@ bool XPathDataModel::isDeclared(const std::string& expr) { } bool XPathDataModel::evalAsBool(const std::string& expr) { - XPathValue<std::string> result = _xpath.evaluate_expr(expr, _doc); +// std::cout << std::endl << evalAsString(expr); + XPathValue<std::string> result; + try { + result = _xpath.evaluate_expr(expr, _doc); + } catch(SyntaxException e) { + throw Event("error.execution", Event::PLATFORM); + } catch(std::runtime_error e) { + throw Event("error.execution", Event::PLATFORM); + } return result.asBool(); } std::string XPathDataModel::evalAsString(const std::string& expr) { - XPathValue<std::string> result = _xpath.evaluate_expr(expr, _doc); + + XPathValue<std::string> result; + try { + result = _xpath.evaluate_expr(expr, _doc); + } catch(SyntaxException e) { + throw Event("error.execution", Event::PLATFORM); + } catch(std::runtime_error e) { + throw Event("error.execution", Event::PLATFORM); + } switch (result.type()) { case STRING: return result.asString(); @@ -303,7 +348,10 @@ std::string XPathDataModel::evalAsString(const std::string& expr) { NodeSet<std::string> nodeSet = result.asNodeSet(); std::stringstream ss; for (int i = 0; i < nodeSet.size(); i++) { - ss << nodeSet[i] << std::endl; + ss << nodeSet[i]; + if (nodeSet[i].getNodeType() != Node_base::TEXT_NODE) { + ss << std::endl; + } } return ss.str(); break; @@ -330,7 +378,21 @@ void XPathDataModel::assign(const Element<std::string>& assignElem, location = ATTR(assignElem, "location"); } + // test 326ff XPathValue<std::string> key = _xpath.evaluate_expr(location, _doc); + if (key.type() == NODE_SET) { + for (int i = 0; i < key.asNodeSet().size(); i++) { + Node<std::string> node = key.asNodeSet()[i]; + if (node == _varResolver.resolveVariable("", "_ioprocessors").asNodeSet()[0]) + throw Event("error.execution", Event::PLATFORM); + if (node == _varResolver.resolveVariable("", "_sessionid").asNodeSet()[0]) + throw Event("error.execution", Event::PLATFORM); + if (node == _varResolver.resolveVariable("", "_name").asNodeSet()[0]) + throw Event("error.execution", Event::PLATFORM); + if (node == _varResolver.resolveVariable("", "_event").asNodeSet()[0]) + throw Event("error.execution", Event::PLATFORM); + } + } NodeSet<std::string> nodeSet; if (doc) { if (doc.getDocumentElement()) { @@ -365,7 +427,18 @@ void XPathDataModel::assign(const Element<std::string>& assignElem, } void XPathDataModel::assign(const std::string& location, const Data& data) { + XPathValue<std::string> locationResult = _xpath.evaluate_expr(location, _doc); + NodeSet<std::string> dataNodeSet = dataToNodeSet(data); + assign(locationResult, dataNodeSet, Element<std::string>()); +// std::cout << _datamodel << std::endl; +} +NodeSet<std::string> XPathDataModel::dataToNodeSet(const Data& data) { + NodeSet<std::string> dataNodeSet; + if (data.atom.length() > 0) { + dataNodeSet.push_back(_doc.createTextNode(data.atom)); + } + return dataNodeSet; } void XPathDataModel::init(const Element<std::string>& dataElem, @@ -396,10 +469,12 @@ void XPathDataModel::init(const Element<std::string>& dataElem, try { XPathValue<std::string> expr = _xpath.evaluate_expr(ATTR(dataElem, "expr"), _doc); switch (expr.type()) { - case NODE_SET: - for (int i = 0; expr.asNodeSet().size(); i++) - container.appendChild(expr.asNodeSet()[i]); + case NODE_SET: { + for (int i = 0; i < expr.asNodeSet().size(); i++) { + container.appendChild(expr.asNodeSet()[i].cloneNode(true)); + } break; + } case STRING: container.appendChild(_doc.createTextNode(expr.asString())); break; @@ -420,7 +495,15 @@ void XPathDataModel::init(const Element<std::string>& dataElem, // put data element into nodeset and bind to xpath variable NodeSet<std::string> nodeSet; +#if 1 nodeSet.push_back(container); +#else + Node<std::string> node = container.getFirstChild(); + while(node) { + nodeSet.push_back(node); + node = node.getNextSibling(); + } +#endif _varResolver.setVariable(location, nodeSet); // std::cout << _datamodel << std::endl; @@ -469,6 +552,8 @@ void XPathDataModel::assign(const XPathValue<std::string>& key, void XPathDataModel::assign(const XPathValue<std::string>& key, const NodeSet<std::string>& value, const Element<std::string>& assignElem) { + if (value.size() == 0 || !value[0]) + return; switch (key.type()) { case NODE_SET: { assign(key.asNodeSet(), value, assignElem); @@ -540,6 +625,8 @@ void XPathDataModel::assign(const NodeSet<std::string>& key, const Element<std::string>& assignElem) { if (key.size() == 0) return; + if (value.size() == 0 || !value[0]) + return; for (int i = 0; i < key.size(); i++) { switch (key[i].getNodeType()) { @@ -559,17 +646,20 @@ void XPathDataModel::assign(const Element<std::string>& key, const NodeSet<std::string>& value, const Element<std::string>& assignElem) { Element<std::string> element(key); + if (value.size() == 0 || !value[0]) + return; + if (false) { } else if (assignElem && 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<std::string> importedNode = _doc.importNode(value[i-1], true); + Node<std::string> importedNode = (value[i-1].getOwnerDocument() == _doc ? value[i-1].cloneNode(true) : _doc.importNode(value[i-1], true)); element.insertBefore(importedNode, element.getFirstChild()); } } else if (assignElem && 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<std::string> importedNode = _doc.importNode(value[i], true); + Node<std::string> importedNode = (value[i].getOwnerDocument() == _doc ? value[i].cloneNode(true) : _doc.importNode(value[i], true)); element.appendChild(importedNode); } } else if (assignElem && HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "previoussibling")) { @@ -579,7 +669,7 @@ void XPathDataModel::assign(const Element<std::string>& key, if (!parent) throw Event("error.execution", Event::PLATFORM); for (int i = 0; i < value.size(); i++) { - Node<std::string> importedNode = _doc.importNode(value[i], true); + Node<std::string> importedNode = (value[i].getOwnerDocument() == _doc ? value[i].cloneNode(true) : _doc.importNode(value[i], true)); parent.insertBefore(importedNode, element); } } else if (assignElem && HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "nextsibling")) { @@ -589,7 +679,7 @@ void XPathDataModel::assign(const Element<std::string>& key, if (!parent) throw Event("error.execution", Event::PLATFORM); for (int i = value.size(); i; i--) { - Node<std::string> importedNode = _doc.importNode(value[i-1], true); + Node<std::string> importedNode = (value[i-1].getOwnerDocument() == _doc ? value[i-1].cloneNode(true) : _doc.importNode(value[i-1], true)); Node<std::string> nextSibling = element.getNextSibling(); if (nextSibling) { parent.insertBefore(importedNode, element.getNextSibling()); @@ -604,7 +694,7 @@ void XPathDataModel::assign(const Element<std::string>& key, throw Event("error.execution", Event::PLATFORM); if (value.size() != 1) throw Event("error.execution", Event::PLATFORM); - Node<std::string> importedNode = _doc.importNode(value[0], true); + Node<std::string> importedNode = (value[0].getOwnerDocument() == _doc ? value[0].cloneNode(true) : _doc.importNode(value[0], true)); parent.replaceChild(importedNode, element); } else if (assignElem && HAS_ATTR(assignElem, "type") && boost::iequals(ATTR(assignElem, "type"), "delete")) { // delete: Delete the node specified by 'location'. ('expr' is ignored.). @@ -617,7 +707,7 @@ void XPathDataModel::assign(const Element<std::string>& key, while(element.hasChildNodes()) element.removeChild(element.getChildNodes().item(0)); for (int i = 0; i < value.size(); i++) { - Node<std::string> importedNode = _doc.importNode(value[i], true); + Node<std::string> importedNode = (value[i].getOwnerDocument() == _doc ? value[i].cloneNode(true) : _doc.importNode(value[i], true)); element.appendChild(importedNode); } } @@ -630,8 +720,8 @@ NodeSetVariableResolver::resolveVariable(const std::string& namepaceUri, if(n == _variables.end()) { throw Event("error.execution"); } -#if 0 - std::cout << std::endl << name << ":" << std::endl; +#if 1 + std::cout << std::endl << "Getting " << name << ":" << std::endl; for (int i = 0; i < n->second.size(); i++) { std::cout << n->second[i].getNodeType() << " | " << n->second[i] << std::endl; } @@ -640,6 +730,21 @@ NodeSetVariableResolver::resolveVariable(const std::string& namepaceUri, return XPathValue<std::string>(new NodeSetValue<std::string>(n->second)); } +void NodeSetVariableResolver::setVariable(const std::string& name, const NodeSet<std::string>& value) { +#if 1 + std::cout << std::endl << "Setting " << name << ":" << std::endl; + for (int i = 0; i < value.size(); i++) { + std::cout << value[i].getNodeType() << " | " << value[i] << std::endl; + } + std::cout << std::endl; +#endif + _variables[name] = value; +} + +bool NodeSetVariableResolver::isDeclared(const std::string& name) { + return _variables.find(name) != _variables.end(); +} + XPathFunction<std::string>* XPathFunctionResolver::resolveFunction(const std::string& namespace_uri, const std::string& name, diff --git a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h index 7140b2f..104d100 100644 --- a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h +++ b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h @@ -52,12 +52,8 @@ class NodeSetVariableResolver : public Arabica::XPath::VariableResolver<std::str public: Arabica::XPath::XPathValue<std::string> resolveVariable(const std::string& namepaceUri, const std::string& name) const; - void setVariable(const std::string& name, const Arabica::XPath::NodeSet<std::string>& value) { - _variables[name] = value; - } - bool isDeclared(const std::string& name) { - return _variables.find(name) != _variables.end(); - } + void setVariable(const std::string& name, const Arabica::XPath::NodeSet<std::string>& value); + bool isDeclared(const std::string& name); private: std::map<std::string, Arabica::XPath::NodeSet<std::string> > _variables; @@ -115,6 +111,7 @@ protected: Arabica::DOM::Document<std::string> _doc; bool isValidIdentifier(const std::string& identifier); + Arabica::XPath::NodeSet<std::string> dataToNodeSet(const Data& data); // resolve value to its type void assign(const Arabica::XPath::XPathValue<std::string>& key, @@ -148,7 +145,7 @@ protected: void assign(const Arabica::DOM::Text<std::string>& key, const Arabica::XPath::NodeSet<std::string>& value, const Arabica::DOM::Element<std::string>& assignElem); - + NodeSetVariableResolver _varResolver; XPathFunctionResolver _funcResolver; diff --git a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp index 1d6394e..c8d86fa 100644 --- a/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp +++ b/src/uscxml/plugins/ioprocessor/basichttp/BasicHTTPIOProcessor.cpp @@ -86,7 +86,11 @@ void BasicHTTPIOProcessor::httpRecvRequest(const HTTPServer::Request& req) { reqEvent.name = value; } else { reqEvent.data.compound[key] = value; + reqEvent.params.insert(std::make_pair(key, value)); } + } else { + // this is most likely wrong + reqEvent.content = evhttp_decode_uri(term.c_str()); } } } else { diff --git a/test/samples/w3c/xpath/test539.txt b/test/samples/w3c/xpath/test539.txt new file mode 100644 index 0000000..de1b0a1 --- /dev/null +++ b/test/samples/w3c/xpath/test539.txt @@ -0,0 +1,4 @@ + <books xmlns=""> + <book title="title1"/> + <book title="title2"/> + </books>
\ No newline at end of file diff --git a/test/samples/w3c/xpath/test540.txt b/test/samples/w3c/xpath/test540.txt new file mode 100644 index 0000000..2191239 --- /dev/null +++ b/test/samples/w3c/xpath/test540.txt @@ -0,0 +1,3 @@ +123 +4 5 +
\ No newline at end of file diff --git a/test/samples/w3c/xpath/test552.txt b/test/samples/w3c/xpath/test552.txt new file mode 100644 index 0000000..d8263ee --- /dev/null +++ b/test/samples/w3c/xpath/test552.txt @@ -0,0 +1 @@ +2
\ No newline at end of file diff --git a/test/samples/w3c/xpath/test557.txt b/test/samples/w3c/xpath/test557.txt new file mode 100644 index 0000000..a8e51da --- /dev/null +++ b/test/samples/w3c/xpath/test557.txt @@ -0,0 +1,4 @@ +<books xmlns=""> + <book title="title1"/> + <book title="title2"/> + </books>
\ No newline at end of file diff --git a/test/samples/w3c/xpath/test558.txt b/test/samples/w3c/xpath/test558.txt new file mode 100644 index 0000000..bb2bcc7 --- /dev/null +++ b/test/samples/w3c/xpath/test558.txt @@ -0,0 +1,3 @@ + +this is +a string
\ No newline at end of file |