diff options
author | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-04-10 20:57:11 (GMT) |
---|---|---|
committer | Stefan Radomski <radomski@tk.informatik.tu-darmstadt.de> | 2013-04-10 20:57:11 (GMT) |
commit | 45ab2909e17f7e0348ccfe4179f23a897a2fd305 (patch) | |
tree | 7a5dfe75657034659e45431469b3909cb69db035 /src/uscxml/plugins/datamodel | |
parent | 1c7064006d4283ffbfa64febea397e68df8e2b54 (diff) | |
download | uscxml-45ab2909e17f7e0348ccfe4179f23a897a2fd305.zip uscxml-45ab2909e17f7e0348ccfe4179f23a897a2fd305.tar.gz uscxml-45ab2909e17f7e0348ccfe4179f23a897a2fd305.tar.bz2 |
New DataModels
Diffstat (limited to 'src/uscxml/plugins/datamodel')
-rw-r--r-- | src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp | 14 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h | 30 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/null/NULLDataModel.cpp | 121 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/null/NULLDataModel.h | 77 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp | 470 | ||||
-rw-r--r-- | src/uscxml/plugins/datamodel/xpath/XPathDataModel.h | 143 |
6 files changed, 848 insertions, 7 deletions
diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp index 0146a31..2491fc4 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.cpp @@ -392,7 +392,9 @@ double V8DataModel::evalAsNumber(const std::string& expr) { return 0; } -void V8DataModel::assign(const std::string& location, const Arabica::DOM::Document<std::string>& doc) { +void V8DataModel::assign(const std::string& location, + const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Element<std::string>& dataElem) { v8::Locker locker; v8::HandleScope handleScope; v8::Context::Scope contextScope(_contexts.front()); @@ -402,17 +404,21 @@ void V8DataModel::assign(const std::string& location, const Arabica::DOM::Docume } -void V8DataModel::assign(const std::string& location, const Data& data) { +void V8DataModel::assign(const std::string& location, + const Data& data, + const Arabica::DOM::Element<std::string>& dataElem) { v8::Locker locker; v8::HandleScope handleScope; v8::Context::Scope contextScope(_contexts.front()); std::stringstream ssJSON; ssJSON << data; - assign(location, ssJSON.str()); + assign(location, ssJSON.str(), dataElem); } -void V8DataModel::assign(const std::string& location, const std::string& expr) { +void V8DataModel::assign(const std::string& location, + const std::string& expr, + const Arabica::DOM::Element<std::string>& dataElem) { v8::Locker locker; v8::HandleScope handleScope; v8::Context::Scope contextScope(_contexts.back()); diff --git a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h index 760b638..7bea50c 100644 --- a/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h +++ b/src/uscxml/plugins/datamodel/ecmascript/v8/V8DataModel.h @@ -39,10 +39,34 @@ public: virtual void pushContext(); virtual void popContext(); + virtual bool supportsJSON() { return true; } + virtual void eval(const std::string& expr); - virtual void assign(const std::string& location, const Arabica::DOM::Document<std::string>& doc); - virtual void assign(const std::string& location, const std::string& expr); - virtual void assign(const std::string& location, const Data& data); + virtual void assign(const std::string& location, + const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Element<std::string>& assignElem); + virtual void assign(const std::string& location, + const std::string& expr, + const Arabica::DOM::Element<std::string>& assignElem); + virtual void assign(const std::string& location, + const Data& data, + const Arabica::DOM::Element<std::string>& assignElem); + + virtual void init(const std::string& location, + const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Element<std::string>& dataElem) { + assign(location, doc, dataElem); + }; + virtual void init(const std::string& location, + const std::string& expr, + const Arabica::DOM::Element<std::string>& dataElem) { + assign(location, expr, dataElem); + } + virtual void init(const std::string& location, + const Data& data, + const Arabica::DOM::Element<std::string>& dataElem) { + assign(location, data, dataElem); + } virtual Data getStringAsData(const std::string& content); virtual Data getValueAsData(const v8::Handle<v8::Value>& value); diff --git a/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp b/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp new file mode 100644 index 0000000..69970dd --- /dev/null +++ b/src/uscxml/plugins/datamodel/null/NULLDataModel.cpp @@ -0,0 +1,121 @@ +#include "uscxml/Common.h" +#include "NULLDataModel.h" + +#include "uscxml/Message.h" +#include <glog/logging.h> + +#ifdef BUILD_AS_PLUGINS +#include <Pluma/Connector.hpp> +#endif + +namespace uscxml { + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool connect(pluma::Host& host) { + host.add( new NULLDataModelProvider() ); + return true; +} +#endif + +NULLDataModel::NULLDataModel() { +} + +boost::shared_ptr<DataModelImpl> NULLDataModel::create(InterpreterImpl* interpreter) { + boost::shared_ptr<NULLDataModel> dm = boost::shared_ptr<NULLDataModel>(new NULLDataModel()); + dm->_interpreter = interpreter; + return dm; +} + +NULLDataModel::~NULLDataModel() { +} + +void NULLDataModel::pushContext() { +} + +void NULLDataModel::popContext() { +} + +void NULLDataModel::initialize() { +} + +void NULLDataModel::setEvent(const Event& event) { +} + +Data NULLDataModel::getStringAsData(const std::string& content) { + Data data; + return data; +} + +bool NULLDataModel::validate(const std::string& location, const std::string& schema) { + return true; +} + +uint32_t NULLDataModel::getLength(const std::string& expr) { + return 0; +} + +void NULLDataModel::eval(const std::string& expr) { +} + +bool NULLDataModel::isDeclared(const std::string& expr) { + return true; +} + +/** + * 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) { + std::string trimmedExpr = 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<std::string> stateExprs; + std::string item; + 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("'"); + size_t end = stateExprs[i].find_last_of("'"); + + std::string stateName; + if (start != std::string::npos && end != std::string::npos && start < end) { + start++; + stateName = stateExprs[i].substr(start, end - start); + } else { + stateName = stateExprs[i]; + } + + if (Interpreter::isMember(_interpreter->getState(stateName), _interpreter->getConfiguration())) { + continue; + } + return false; + } + return true; +} + +std::string NULLDataModel::evalAsString(const std::string& expr) { + return expr; +} + +double NULLDataModel::evalAsNumber(const std::string& expr) { + return 0; +} + +}
\ No newline at end of file diff --git a/src/uscxml/plugins/datamodel/null/NULLDataModel.h b/src/uscxml/plugins/datamodel/null/NULLDataModel.h new file mode 100644 index 0000000..eaa9dbd --- /dev/null +++ b/src/uscxml/plugins/datamodel/null/NULLDataModel.h @@ -0,0 +1,77 @@ +#ifndef NULLDATAMODEL_H_KN8TWG0V +#define NULLDATAMODEL_H_KN8TWG0V + +#include "uscxml/Interpreter.h" +#include <list> + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { +class Event; +class Data; +} + +namespace uscxml { + +class NULLDataModel : public DataModelImpl { +public: + NULLDataModel(); + virtual ~NULLDataModel(); + virtual boost::shared_ptr<DataModelImpl> create(InterpreterImpl* interpreter); + + virtual std::set<std::string> getNames() { + std::set<std::string> names; + names.insert("null"); + return names; + } + + virtual void initialize(); + virtual void setEvent(const Event& event); + + virtual bool validate(const std::string& location, const std::string& schema); + + virtual uint32_t getLength(const std::string& expr); + virtual void pushContext(); + virtual void popContext(); + + virtual void eval(const std::string& expr); + virtual void assign(const std::string& location, + const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Element<std::string>& assignElem) {} + virtual void assign(const std::string& location, + const std::string& expr, + const Arabica::DOM::Element<std::string>& assignElem) {} + virtual void assign(const std::string& location, + const Data& data, + const Arabica::DOM::Element<std::string>& assignElem) {} + + virtual void init(const std::string& location, + const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Element<std::string>& dataElem) {}; + virtual void init(const std::string& location, + const std::string& expr, + const Arabica::DOM::Element<std::string>& dataElem) {}; + virtual void init(const std::string& location, + const Data& data, + const Arabica::DOM::Element<std::string>& dataElem) {}; + + virtual Data getStringAsData(const std::string& content); + virtual bool isDeclared(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); + +protected: + +}; + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(NULLDataModel, DataModelImpl); +#endif + +} + +#endif /* end of include guard: NULLDATAMODEL_H_KN8TWG0V */ diff --git a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp new file mode 100644 index 0000000..f874c86 --- /dev/null +++ b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.cpp @@ -0,0 +1,470 @@ +#include "uscxml/Common.h" +#include "XPathDataModel.h" + +#include "uscxml/Message.h" +#include <glog/logging.h> + +#ifdef BUILD_AS_PLUGINS +#include <Pluma/Connector.hpp> +#endif + +namespace uscxml { + +using namespace Arabica::XPath; +using namespace Arabica::DOM; + +#ifdef BUILD_AS_PLUGINS +PLUMA_CONNECTOR +bool connect(pluma::Host& host) { + host.add( new XPathDataModelProvider() ); + return true; +} +#endif + +XPathDataModel::XPathDataModel() { +} + +boost::shared_ptr<DataModelImpl> XPathDataModel::create(InterpreterImpl* interpreter) { + boost::shared_ptr<XPathDataModel> dm = boost::shared_ptr<XPathDataModel>(new XPathDataModel()); + dm->_interpreter = interpreter; +// dm->_xpath.setVariableResolver(_varResolver); +// dm->_xpath->setVariableCompileTimeResolver(_varCTResolver); +// dm->_xpath->setNamespaceContext(interpreter->getNSContext()); + + dm->_funcResolver.setInterpreter(interpreter); + dm->_xpath.setFunctionResolver(dm->_funcResolver); + dm->_xpath.setVariableResolver(dm->_varResolver); + + dm->_domFactory = Arabica::SimpleDOM::DOMImplementation<std::string>::getDOMImplementation(); + 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<std::string> ioProcElem = dm->_doc.createElement("data"); + ioProcElem.setAttribute("id", "_ioprocessors"); + std::map<std::string, IOProcessor>::const_iterator ioProcIter = interpreter->getIOProcessors().begin(); + while(ioProcIter != interpreter->getIOProcessors().end()) { + Element<std::string> ioProc = dm->_doc.createElement("processor"); + ioProc.setAttribute("name", ioProcIter->first); + + Data ioProcData = ioProcIter->second.getDataModelVariables(); + Element<std::string> ioProcLoc = dm->_doc.createElement("location"); + Text<std::string> ioProcLocText = dm->_doc.createTextNode(ioProcData.compound["location"].atom); + ioProcLoc.appendChild(ioProcLocText); + ioProc.appendChild(ioProcLoc); + ioProcElem.appendChild(ioProc); + + ioProcIter++; + } + dm->_datamodel.appendChild(ioProcElem); + + NodeSet<std::string> ioProcNodeSet; + ioProcNodeSet.push_back(ioProcElem); + dm->_varResolver.setVariable("_ioprocessors", ioProcNodeSet); + + + Element<std::string> sessIdElem = dm->_doc.createElement("data"); + sessIdElem.setAttribute("id", "_sessionid"); + Text<std::string> sessIdText = dm->_doc.createTextNode(interpreter->getSessionId()); + sessIdElem.appendChild(sessIdText); + dm->_datamodel.appendChild(sessIdElem); + + NodeSet<std::string> sessIdNodeSet; + sessIdNodeSet.push_back(sessIdElem); + dm->_varResolver.setVariable("_sessionid", sessIdNodeSet); + + + Element<std::string> nameElem = dm->_doc.createElement("data"); + nameElem.setAttribute("id", "_name"); + Text<std::string> nameText = dm->_doc.createTextNode(interpreter->getName()); + nameElem.appendChild(nameText); + dm->_datamodel.appendChild(nameElem); + + NodeSet<std::string> nameNodeSet; + nameNodeSet.push_back(nameElem); + dm->_varResolver.setVariable("_name", nameNodeSet); + + return dm; +} + +XPathDataModel::~XPathDataModel() { +} + +void XPathDataModel::pushContext() { +} + +void XPathDataModel::popContext() { +} + +void XPathDataModel::initialize() { +} + +void XPathDataModel::setEvent(const Event& event) { + Element<std::string> eventElem = _doc.createElement("data"); + eventElem.setAttribute("id", "_event"); + + Element<std::string> eventDataElem = _doc.createElement("data"); + + NodeSet<std::string> eventNodeSet; + if (event.params.size() > 0) { + std::multimap<std::string, std::string>::const_iterator paramIter = event.params.begin(); + while(paramIter != event.params.end()) { + Element<std::string> eventParamElem = _doc.createElement("data"); + Text<std::string> eventParamText = _doc.createTextNode(paramIter->second); + + eventParamElem.setAttribute("id", paramIter->first); + eventParamElem.appendChild(eventParamText); + eventDataElem.appendChild(eventParamElem); + paramIter++; + } + } + if (event.namelist.size() > 0) { + std::map<std::string, std::string>::const_iterator namelistIter = event.namelist.begin(); + while(namelistIter != event.namelist.end()) { + Element<std::string> eventNamelistElem = _doc.createElement("data"); + Text<std::string> eventNamelistText = _doc.createTextNode(namelistIter->second); + + eventNamelistElem.setAttribute("id", namelistIter->first); + eventNamelistElem.appendChild(eventNamelistText); + eventDataElem.appendChild(eventNamelistElem); + namelistIter++; + } + } + if (event.content.size() > 0) { + eventDataElem.setNodeValue(event.content); + } + + eventElem.appendChild(eventDataElem); + eventNodeSet.push_back(eventElem); + +// std::cout << eventElem << std::endl; + + // do we need to replace an existing event? + Node<std::string> oldEventElem = _datamodel.getFirstChild(); + while(oldEventElem) { + if (oldEventElem.getNodeType() == Node_base::ELEMENT_NODE) { + if (HAS_ATTR(oldEventElem, "id") && boost::iequals(ATTR(oldEventElem, "id"), "_event")) + break; + } + oldEventElem = oldEventElem.getNextSibling(); + } + + if (oldEventElem) { + _datamodel.replaceChild(eventElem, oldEventElem); + } else { + _datamodel.appendChild(eventElem); + } + _varResolver.setVariable("_event", eventNodeSet); +} + +Data XPathDataModel::getStringAsData(const std::string& content) { + Data data; + return data; +} + +bool XPathDataModel::validate(const std::string& location, const std::string& schema) { + return true; +} + +uint32_t XPathDataModel::getLength(const std::string& expr) { + return 0; +} + +void XPathDataModel::eval(const std::string& expr) { + XPathValue<std::string> result = _xpath.evaluate_expr(expr, _doc); +} + +bool XPathDataModel::isDeclared(const std::string& expr) { + return true; +} + +bool XPathDataModel::evalAsBool(const std::string& expr) { + XPathValue<std::string> result = _xpath.evaluate_expr(expr, _doc); + return result.asBool(); +} + +std::string XPathDataModel::evalAsString(const std::string& expr) { + XPathValue<std::string> result = _xpath.evaluate_expr(expr, _doc); + return result.asString(); +} + +double XPathDataModel::evalAsNumber(const std::string& expr) { + XPathValue<std::string> result = _xpath.evaluate_expr(expr, _doc); + return result.asNumber(); +} + +void XPathDataModel::assign(const std::string& location, + const Document<std::string>& doc, + const Arabica::DOM::Element<std::string>& dataElem) { + XPathValue<std::string> key = _xpath.evaluate_expr(location, _doc); + NodeSet<std::string> nodeSet; + nodeSet.push_back(doc.getDocumentElement()); + assign(key, nodeSet, dataElem); +} + +void XPathDataModel::assign(const std::string& location, + const Data& data, + const Arabica::DOM::Element<std::string>& dataElem) { +// assert(false); +// std::cout << location << " = " << data << std::endl; +} + +void XPathDataModel::assign(const std::string& location, + const std::string& expr, + const Arabica::DOM::Element<std::string>& dataElem) { + std::string realExpr = (HAS_ATTR(dataElem, "expr") ? ATTR(dataElem, "expr") : expr); + XPathValue<std::string> key = _xpath.evaluate_expr(location, _doc); + XPathValue<std::string> value = _xpath.evaluate_expr(realExpr, _doc); + assign(key, value, dataElem); +} + +void XPathDataModel::init(const std::string& location, + const Document<std::string>& doc, + const Arabica::DOM::Element<std::string>& dataElem) { + Element<std::string> container = _doc.createElement("data"); + container.setAttribute("id", location); + Element<std::string> data = doc.getDocumentElement(); + if (data.hasChildNodes()) { + Node<std::string> dataClone = _doc.importNode(data, true); + container.appendChild(dataClone); + } + _datamodel.appendChild(container); + + // put data element into nodeset and bind to xpath variable + NodeSet<std::string> nodeSet; + nodeSet.push_back(container); + _varResolver.setVariable(location, nodeSet); +} + +void XPathDataModel::init(const std::string& location, + const std::string& expr, + const Arabica::DOM::Element<std::string>& dataElem) { + Element<std::string> data = _doc.createElement("data"); + data.setAttribute("id", location); + + if (expr.length() > 0) { + Text<std::string> textNode = _doc.createTextNode(expr.c_str()); + data.appendChild(textNode); + _datamodel.appendChild(data); + } + + // put data element into nodeset and bind to xpath variable + NodeSet<std::string> nodeSet; + nodeSet.push_back(data); + _varResolver.setVariable(location, nodeSet); +} + +void XPathDataModel::init(const std::string& location, + const Data& data, + const Arabica::DOM::Element<std::string>& dataElem) { + assert(false); +} + +void XPathDataModel::assign(XPathValue<std::string>& key, + const XPathValue<std::string>& value, + const Arabica::DOM::Element<std::string>& 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); + } +} + +void XPathDataModel::assign(XPathValue<std::string>& key, + const std::string& value, + const Arabica::DOM::Element<std::string>& assignElem) { + switch (key.type()) { + case NODE_SET: { + if (key.asNodeSet().size() == 0) + return; + Node<std::string> node = key.asNodeSet()[0]; + switch (node.getNodeType()) { + case Node_base::ATTRIBUTE_NODE: { + Attr<std::string> attr(node); + attr.setValue(value); + break; + } + case Node_base::TEXT_NODE: { + Text<std::string> text(node); + text.setNodeValue(value); + break; + } + case Node_base::ELEMENT_NODE: { + Element<std::string> 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; + } + 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; + } +} + +void XPathDataModel::assign(XPathValue<std::string>& key, + const double value, + const Arabica::DOM::Element<std::string>& assignElem) { +} + +void XPathDataModel::assign(XPathValue<std::string>& key, + const bool value, + const Arabica::DOM::Element<std::string>& assignElem) { +} + +void XPathDataModel::assign(XPathValue<std::string>& key, + const NodeSet<std::string>& value, + const Arabica::DOM::Element<std::string>& assignElem) { + switch (key.type()) { + case NODE_SET: { + if (key.asNodeSet().size() == 0) + return; + Node<std::string> node = key.asNodeSet()[0]; + switch (node.getNodeType()) { + case Node_base::ELEMENT_NODE: { + Element<std::string> 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<std::string> 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<std::string> 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<std::string> parent = element.getParentNode(); + 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); + 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<std::string> parent = element.getParentNode(); + 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> 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<std::string> parent = element.getParentNode(); + if (!parent) + 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); + 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<std::string> 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<std::string> importedNode = _doc.importNode(value[i], true); + element.appendChild(importedNode); + } + } + 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; + } +} + +XPathValue<std::string> + NodeSetVariableResolver::resolveVariable(const std::string& namepaceUri, + const std::string& name) const { + std::map<std::string, NodeSet<std::string> >::const_iterator n = _variables.find(name); + if(n == _variables.end()) { + throw Event("error.execution"); + } + return XPathValue<std::string>(new NodeSetValue<std::string>(n->second)); +} + +XPathFunction<std::string>* + XPathFunctionResolver::resolveFunction(const std::string& namespace_uri, + const std::string& name, + const std::vector<XPathExpression<std::string> >& argExprs) const { + if (boost::iequals(name, "in")) { + return new XPathFunctionIn(1, -1, argExprs, _interpreter); + } + return _xpathFuncRes.resolveFunction(namespace_uri, name, argExprs); +} + +std::vector<std::pair<std::string, std::string> > XPathFunctionResolver::validNames() const { + std::vector<std::pair<std::string, std::string> > names = _xpathFuncRes.validNames(); + names.push_back(std::make_pair("", "In")); + return names; +} + +bool XPathFunctionIn::doEvaluate(const Node<std::string>& context, + const ExecutionContext<std::string>& executionContext) const { + for (int i = 0; i < argCount(); i++) { + XPathValue<std::string> stateName = arg(i, context, executionContext); + if (stateName.type() == STRING) { + if (!Interpreter::isMember(_interpreter->getState(stateName.asString()), _interpreter->getConfiguration())) { + return false; + } + } + } + return true; +} + +}
\ No newline at end of file diff --git a/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h new file mode 100644 index 0000000..d028129 --- /dev/null +++ b/src/uscxml/plugins/datamodel/xpath/XPathDataModel.h @@ -0,0 +1,143 @@ +#ifndef XPATHDATAMODEL_H_KN8TWG0V +#define XPATHDATAMODEL_H_KN8TWG0V + +#include "uscxml/Interpreter.h" +#include <list> + +#ifdef BUILD_AS_PLUGINS +#include "uscxml/plugins/Plugins.h" +#endif + +namespace uscxml { +class Event; +class Data; +} + +namespace uscxml { + +class XPathFunctionIn : public Arabica::XPath::BooleanXPathFunction<std::string> { +public: + XPathFunctionIn(int minArgs, + int maxArgs, + const std::vector<Arabica::XPath::XPathExpression<std::string> >& args, + InterpreterImpl* interpreter) : + BooleanXPathFunction(minArgs, maxArgs, args), + _interpreter(interpreter) {} + +protected: + bool doEvaluate(const Arabica::DOM::Node<std::string>& context, + const Arabica::XPath::ExecutionContext<std::string>& executionContext) const; + InterpreterImpl* _interpreter; +}; + +class XPathFunctionResolver : public Arabica::XPath::FunctionResolver<std::string> { +public: + virtual ~XPathFunctionResolver() { } + + virtual Arabica::XPath::XPathFunction<std::string>* + resolveFunction(const std::string& namespace_uri, + const std::string& name, + const std::vector<Arabica::XPath::XPathExpression<std::string> >& argExprs) const; + + virtual std::vector<std::pair<std::string, std::string> > validNames() const; + void setInterpreter(InterpreterImpl* interpreter) { _interpreter = interpreter; } +protected: + Arabica::XPath::StandardXPathFunctionResolver<std::string> _xpathFuncRes; + InterpreterImpl* _interpreter; +}; + +class NodeSetVariableResolver : public Arabica::XPath::VariableResolver<std::string> { +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; + } + +private: + std::map<std::string, Arabica::XPath::NodeSet<std::string> > _variables; +}; + +class XPathDataModel : public DataModelImpl { +public: + XPathDataModel(); + virtual ~XPathDataModel(); + virtual boost::shared_ptr<DataModelImpl> create(InterpreterImpl* interpreter); + + virtual std::set<std::string> getNames() { + std::set<std::string> names; + names.insert("xpath"); + return names; + } + + virtual void initialize(); + virtual void setEvent(const Event& event); + + virtual bool validate(const std::string& location, const std::string& schema); + + virtual uint32_t getLength(const std::string& expr); + virtual void pushContext(); + virtual void popContext(); + + virtual void eval(const std::string& expr); + virtual void assign(const std::string& location, + const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Element<std::string>& assignElem); + virtual void assign(const std::string& location, + const std::string& expr, + const Arabica::DOM::Element<std::string>& assignElem); + virtual void assign(const std::string& location, + const Data& data, + const Arabica::DOM::Element<std::string>& assignElem); + + virtual void init(const std::string& location, + const Arabica::DOM::Document<std::string>& doc, + const Arabica::DOM::Element<std::string>& dataElem); + virtual void init(const std::string& location, + const std::string& expr, + const Arabica::DOM::Element<std::string>& dataElem); + virtual void init(const std::string& location, + const Data& data, + const Arabica::DOM::Element<std::string>& dataElem); + + virtual Data getStringAsData(const std::string& content); + virtual bool isDeclared(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); + +protected: + Arabica::XPath::XPath<std::string> _xpath; + Arabica::DOM::DOMImplementation<std::string> _domFactory; + Arabica::DOM::Element<std::string> _datamodel; + Arabica::DOM::Document<std::string> _doc; + + void assign(Arabica::XPath::XPathValue<std::string>& key, + const Arabica::XPath::XPathValue<std::string>& value, + const Arabica::DOM::Element<std::string>& assignElem); + void assign(Arabica::XPath::XPathValue<std::string>& key, + const std::string& value, + const Arabica::DOM::Element<std::string>& assignElem); + void assign(Arabica::XPath::XPathValue<std::string>& key, + const double value, + const Arabica::DOM::Element<std::string>& assignElem); + void assign(Arabica::XPath::XPathValue<std::string>& key, + const bool value, + const Arabica::DOM::Element<std::string>& assignElem); + void assign(Arabica::XPath::XPathValue<std::string>& key, + const Arabica::XPath::NodeSet<std::string>& value, + const Arabica::DOM::Element<std::string>& assignElem); + + NodeSetVariableResolver _varResolver; + XPathFunctionResolver _funcResolver; + +}; + +#ifdef BUILD_AS_PLUGINS +PLUMA_INHERIT_PROVIDER(XPathDataModel, DataModelImpl); +#endif + +} + +#endif /* end of include guard: XPATHDATAMODEL_H_KN8TWG0V */ |