/** * @file * @author 2012-2013 Stefan Radomski (stefan.radomski@cs.tu-darmstadt.de) * @author 2013 Enrico Papi (enrico.papi@ajile.it) * @copyright Simplified BSD * * @cond * This program is free software: you can redistribute it and/or modify * it under the terms of the FreeBSD license as published by the FreeBSD * project. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * You should have received a copy of the FreeBSD license along with this * program. If not, see . * @endcond */ #include "uscxml/Common.h" #include "XPathDataModel.h" #include "uscxml/Message.h" #include "uscxml/DOMUtils.h" #include #include #ifdef BUILD_AS_PLUGINS #include #endif namespace uscxml { using namespace Arabica::XPath; using namespace Arabica::DOM; #ifdef BUILD_AS_PLUGINS PLUMA_CONNECTOR bool pluginConnect(pluma::Host& host) { host.add( new XPathDataModelProvider() ); return true; } #endif XPathDataModel::XPathDataModel() { } boost::shared_ptr XPathDataModel::create(InterpreterImpl* interpreter) { boost::shared_ptr dm = boost::shared_ptr(new XPathDataModel()); dm->_interpreter = interpreter; // dm->_xpath->setVariableCompileTimeResolver(_varCTResolver); // dm->_xpath->setNamespaceContext(interpreter->getNSContext()); dm->_funcResolver.setInterpreter(interpreter); dm->_xpath.setNamespaceContext(*interpreter->getNameSpaceInfo().getNSContext()); dm->_xpath.setFunctionResolver(dm->_funcResolver); dm->_xpath.setVariableResolver(dm->_varResolver); dm->_domFactory = Arabica::SimpleDOM::DOMImplementation::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 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); 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()); sessIdElem.appendChild(sessIdText); dm->_datamodel.appendChild(sessIdElem); NodeSet sessIdNodeSet; sessIdNodeSet.push_back(sessIdText); 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(nameText); 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 eventElem = _doc.createElement("data"); eventElem.setAttribute("id", "_event"); Element eventDataElem = _doc.createElement("data"); NodeSet eventNodeSet; { // -- name Element eventNameElem = _doc.createElement("name"); Text eventName = _doc.createTextNode(event.name.c_str()); eventNameElem.appendChild(eventName); eventElem.appendChild(eventNameElem); } { // -- origin Element eventOriginElem = _doc.createElement("origin"); Text eventOrigin = _doc.createTextNode(event.origin.c_str()); eventOriginElem.appendChild(eventOrigin); eventElem.appendChild(eventOriginElem); } { // -- type Element eventTypeElem = _doc.createElement("type"); Text eventType; switch (event.eventType) { 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::const_iterator paramIter = event.params.begin(); while(paramIter != event.params.end()) { Element eventParamElem = _doc.createElement("data"); // this is simplified - Data might be more elaborate than a simple string atom Text eventParamText = _doc.createTextNode(paramIter->second.atom); eventParamElem.setAttribute("id", paramIter->first); eventParamElem.appendChild(eventParamText); eventDataElem.appendChild(eventParamElem); paramIter++; } } if (event.namelist.size() > 0) { std::map::const_iterator namelistIter = event.namelist.begin(); while(namelistIter != event.namelist.end()) { Element eventNamelistElem = _doc.createElement("data"); // this is simplified - Data might be more elaborate than a simple string atom Text eventNamelistText = _doc.createTextNode(namelistIter->second.atom); eventNamelistElem.setAttribute("id", namelistIter->first); eventNamelistElem.appendChild(eventNamelistText); eventDataElem.appendChild(eventNamelistElem); namelistIter++; } } if (event.raw.size() > 0) { Element eventRawElem = _doc.createElement("raw"); Text textNode = _doc.createTextNode(event.raw.c_str()); eventRawElem.appendChild(textNode); eventElem.appendChild(eventRawElem); } if (event.content.size() > 0) { Text textNode = _doc.createTextNode(InterpreterImpl::spaceNormalize(event.content).c_str()); eventDataElem.appendChild(textNode); } if (event.dom) { Node importedNode = _doc.importNode(event.dom, true); eventDataElem.appendChild(importedNode); } if (event.data.array.size() == 1) { Text textNode = _doc.createTextNode(event.data.array.front().atom.c_str()); eventDataElem.appendChild(textNode); } else if (event.data.array.size() > 1) { std::list::const_iterator ptr; unsigned int i; for( i = 0 , ptr = event.data.array.begin() ; ((i < event.data.array.size()) && (ptr != event.data.array.end())); i++ , ptr++ ) { Element eventMESElem = _doc.createElement("data"); Text textNode = _doc.createTextNode(ptr->atom.c_str()); std::stringstream ss; ss << i; eventMESElem.setAttribute("id", ss.str()); eventMESElem.appendChild(textNode); eventDataElem.appendChild(eventMESElem); } } eventElem.appendChild(eventDataElem); eventNodeSet.push_back(eventElem); // do we need to replace an existing event? Node oldEventElem = _datamodel.getFirstChild(); while(oldEventElem) { if (oldEventElem.getNodeType() == Node_base::ELEMENT_NODE) { if (HAS_ATTR_CAST(oldEventElem, "id") && iequals(ATTR_CAST(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; XPathValue result = _xpath.evaluate_expr(content, _doc); std::stringstream ss; switch (result.type()) { case ANY: break; case Arabica::XPath::BOOL: ss << result.asBool(); break; case NUMBER: ss << result.asNumber(); break; case STRING: ss << result.asString(); break; case NODE_SET: NodeSet ns = result.asNodeSet(); for (int i = 0; i < ns.size(); i++) { ss.str(""); ss << i; std::string idx = ss.str(); ss.str(""); ss << ns[i]; data.compound[idx] = Data(ss.str(), Data::INTERPRETED); } data.type = Data::INTERPRETED; return data; break; } data.atom = ss.str(); data.type = Data::VERBATIM; return data; } bool XPathDataModel::validate(const std::string& location, const std::string& schema) { return true; } bool XPathDataModel::isLocation(const std::string& expr) { return true; } uint32_t XPathDataModel::getLength(const std::string& expr) { // std::cout << _datamodel << std::endl; XPathValue result = _xpath.evaluate_expr(expr, _doc); switch(result.type()) { case NUMBER: return result.asNumber(); break; case NODE_SET: return result.asNodeSet().size(); break; default: ERROR_EXECUTION_THROW("'" + expr + "' does not evaluate to an array."); } return 0; } void XPathDataModel::setForeach(const std::string& item, const std::string& array, const std::string& index, uint32_t iteration) { XPathValue arrayResult = _xpath.evaluate_expr(array, _doc); assert(arrayResult.type() == NODE_SET); #if 0 std::cout << "Array Size: " << arrayResult.asNodeSet().size() << std::endl; for (int i = 0; i < arrayResult.asNodeSet().size(); i++) { std::cout << arrayResult.asNodeSet()[i] << std::endl; } #endif assert(arrayResult.asNodeSet().size() >= iteration); NodeSet arrayNodeSet; arrayNodeSet.push_back(arrayResult.asNodeSet()[iteration]); if (!isDeclared(item)) { if (!isValidIdentifier(item)) ERROR_EXECUTION_THROW("Expression '" + item + "' not a valid identifier."); Element container = _doc.createElement("data"); container.setAttribute("id", item); container.appendChild(arrayResult.asNodeSet()[iteration].cloneNode(true)); _datamodel.appendChild(container); _varResolver.setVariable(item, arrayNodeSet); } XPathValue itemResult = _varResolver.resolveVariable("", item); assign(itemResult, arrayNodeSet, Element()); if (index.length() > 0) { NodeSet indexNodeSet; Text indexElem = _doc.createTextNode(toStr(iteration)); indexNodeSet.push_back(indexElem); if (!isDeclared(index)) { Element container = _doc.createElement("data"); container.setAttribute("id", index); container.appendChild(indexElem); _datamodel.appendChild(container); NodeSet indexVarNodeSet; indexVarNodeSet.push_back(container); _varResolver.setVariable(index, indexVarNodeSet); } XPathValue indexResult = _varResolver.resolveVariable("", index); assign(indexResult, indexNodeSet, Element()); } #if 0 std::cout << _datamodel << std::endl << std::endl; std::cout << "Index: " << indexResult.asNodeSet().size() << std::endl; for (int i = 0; i < indexResult.asNodeSet().size(); i++) { std::cout << indexResult.asNodeSet()[i] << std::endl; } std::cout << std::endl; #endif } bool XPathDataModel::isValidIdentifier(const std::string& identifier) { if(boost::starts_with(identifier, ".")) return false; return true; } void XPathDataModel::eval(const Arabica::DOM::Element& scriptElem, const std::string& expr) { XPathValue result = _xpath.evaluate_expr(expr, _doc); } bool XPathDataModel::isDeclared(const std::string& expr) { return true; try { return _varResolver.isDeclared(expr) || evalAsBool(expr); } catch(...) { return false; } } bool XPathDataModel::evalAsBool(const std::string& expr) { return evalAsBool(Arabica::DOM::Element(), expr); } bool XPathDataModel::evalAsBool(const Arabica::DOM::Element& node, const std::string& expr) { // std::cout << std::endl << evalAsString(expr); XPathValue result; try { result = _xpath.evaluate_expr(expr, _doc); } catch(SyntaxException e) { ERROR_EXECUTION_THROW(e.what()); } catch(std::runtime_error e) { ERROR_EXECUTION_THROW(e.what()); } return result.asBool(); } std::string XPathDataModel::evalAsString(const std::string& expr) { XPathValue result; try { result = _xpath.evaluate_expr(expr, _doc); } catch(SyntaxException e) { ERROR_EXECUTION_THROW(e.what()); } catch(std::runtime_error e) { ERROR_EXECUTION_THROW(e.what()); } switch (result.type()) { case STRING: return result.asString(); break; case Arabica::XPath::BOOL: // MSVC croaks with ambiguous symbol without qualified name return (result.asBool() ? "true" : "false"); break; case NUMBER: return toStr(result.asNumber()); break; case NODE_SET: { NodeSet nodeSet = result.asNodeSet(); std::stringstream ss; for (int i = 0; i < nodeSet.size(); i++) { ss << nodeSet[i]; if (nodeSet[i].getNodeType() != Node_base::TEXT_NODE) { ss << std::endl; } } return ss.str(); break; } case ANY: ERROR_EXECUTION_THROW("Type ANY not supported to evaluate as string"); break; } return "undefined"; } double XPathDataModel::evalAsNumber(const std::string& expr) { XPathValue result = _xpath.evaluate_expr(expr, _doc); return result.asNumber(); } void XPathDataModel::assign(const Element& assignElem, const Node& node, 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"); } // test 326ff XPathValue key = _xpath.evaluate_expr(location, _doc); #ifdef VERBOSE LOG(INFO) << "Key XPath : " << key.asString(); #endif #if 0 if (key.type() == NODE_SET) { try { for (int i = 0; i < key.asNodeSet().size(); i++) { Node node = key.asNodeSet()[i]; if (node == _varResolver.resolveVariable("", "_ioprocessors").asNodeSet()[0]) ERROR_EXECUTION_THROW("Cannot assign _ioProcessors"); if (node == _varResolver.resolveVariable("", "_sessionid").asNodeSet()[0]) ERROR_EXECUTION_THROW("Cannot assign _sessionid"); if (node == _varResolver.resolveVariable("", "_name").asNodeSet()[0]) ERROR_EXECUTION_THROW("Cannot assign _name"); if (node == _varResolver.resolveVariable("", "_event").asNodeSet()[0]) ERROR_EXECUTION_THROW("Cannot assign _event"); } } catch (Event e) {} } #endif NodeSet nodeSet; if (node) { Node data = node; while (data) { // do not add empty text as a node if (data.getNodeType() == Node_base::TEXT_NODE) { std::string trimmed = data.getNodeValue(); boost::trim(trimmed); if (trimmed.length() == 0) { data = data.getNextSibling(); continue; } } nodeSet.push_back(data); data = data.getNextSibling(); } assign(key, nodeSet, assignElem); } else if (content.length() > 0) { Text textNode = _doc.createTextNode(InterpreterImpl::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); #ifdef VERBOSE LOG(INFO) << "Value XPath : " << value.asString(); #endif 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) { XPathValue locationResult = _xpath.evaluate_expr(location, _doc); NodeSet dataNodeSet = dataToNodeSet(data); assign(locationResult, dataNodeSet, Element()); // std::cout << _datamodel << std::endl; } NodeSet XPathDataModel::dataToNodeSet(const Data& data) { NodeSet dataNodeSet; if (data.atom.length() > 0) { dataNodeSet.push_back(_doc.createTextNode(data.atom)); } return dataNodeSet; } void XPathDataModel::init(const Element& dataElem, const Node& node, 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"); } NodeSet nodeSet; if (node || (content.length() > 0)) { _datamodel.appendChild(_doc.importNode(dataElem, true)); nodeSet.push_back(dataElem); } else if (HAS_ATTR(dataElem, "expr")) { try { Element container = _doc.createElement("data"); container.setAttribute("id", location); XPathValue expr = _xpath.evaluate_expr(ATTR(dataElem, "expr"), _doc); switch (expr.type()) { case NODE_SET: { for (int i = 0; i < expr.asNodeSet().size(); i++) { container.appendChild(expr.asNodeSet()[i].cloneNode(true)); nodeSet.push_back(expr.asNodeSet()[i].cloneNode(true)); } break; } case STRING: container.appendChild(_doc.createTextNode(expr.asString())); nodeSet.push_back(_doc.createTextNode(expr.asString())); break; case NUMBER: { container.appendChild(_doc.createTextNode(toStr(expr.asNumber()))); nodeSet.push_back(_doc.createTextNode(toStr(expr.asNumber()))); break; } case Arabica::XPath::BOOL: case ANY: ERROR_EXECUTION_THROW("expr evaluates to type ANY"); } _datamodel.appendChild(container); } catch (SyntaxException e) { ERROR_EXECUTION_THROW(e.what()); } } else { LOG(ERROR) << "data element has no content"; } _varResolver.setVariable(location, nodeSet); } void XPathDataModel::init(const std::string& location, const Data& data) { NodeSet nodeSet; _varResolver.setVariable(location, nodeSet); } void XPathDataModel::assign(const XPathValue& key, const XPathValue& value, const Element& assignElem) { switch (key.type()) { case NODE_SET: if (key.asNodeSet().size() == 0) { ERROR_EXECUTION_THROW("key for assign is empty nodeset"); } switch (value.type()) { case STRING: assign(key.asNodeSet(), value.asString(), assignElem); break; case Arabica::XPath::BOOL: assign(key.asNodeSet(), value.asBool(), assignElem); break; case NUMBER: assign(key.asNodeSet(), value.asNumber(), assignElem); break; case NODE_SET: assign(key.asNodeSet(), value.asNodeSet(), assignElem); break; case ANY: ERROR_EXECUTION_THROW("Type ANY as key for assign not supported"); } break; case STRING: case Arabica::XPath::BOOL: case NUMBER: case ANY: ERROR_EXECUTION_THROW("Type ANY as key for assign not supported") break; } } void XPathDataModel::assign(const XPathValue& key, const NodeSet& value, const Element& assignElem) { if (value.size() == 0 || !value[0]) return; switch (key.type()) { case NODE_SET: { assign(key.asNodeSet(), value, assignElem); break; } case STRING: case Arabica::XPath::BOOL: case NUMBER: case ANY: ERROR_EXECUTION_THROW("Type ANY as key for assign not supported") } } void XPathDataModel::assign(const NodeSet& key, const std::string& value, const Element& assignElem) { if (key.size() == 0) return; for (int i = 0; i < key.size(); i++) { Node node = key[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") && 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")) ERROR_EXECUTION_THROW("Assign element is missing 'attr'"); 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); } break; } default: ERROR_EXECUTION_THROW("Unsupported node type with assign"); break; } } } void XPathDataModel::assign(const NodeSet& key, const double value, const Element& assignElem) { assign(key, toStr(value), assignElem); } void XPathDataModel::assign(const NodeSet& key, const bool value, const Element& assignElem) { } void XPathDataModel::assign(const NodeSet& key, const NodeSet& value, const Element& 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()) case Node_base::ELEMENT_NODE: { assign(Element(key[i]), value, assignElem); break; default: // std::cout << key[i].getNodeType() << std::endl; ERROR_EXECUTION_THROW("Unsupported node type for assign"); break; } } } void XPathDataModel::assign(const Element& key, const NodeSet& value, const Element& assignElem) { Element element(key); if (value.size() == 0 || !value[0]) return; if (false) { } else if (assignElem && HAS_ATTR(assignElem, "type") && 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 = (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") && 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 = (value[i].getOwnerDocument() == _doc ? value[i].cloneNode(true) : _doc.importNode(value[i], true)); element.appendChild(importedNode); } } else if (assignElem && HAS_ATTR(assignElem, "type") && 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) ERROR_EXECUTION_THROW("Node has no parent"); for (int i = 0; i < value.size(); i++) { Node 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") && 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) ERROR_EXECUTION_THROW("Node has no parent"); for (int i = value.size(); i; i--) { Node importedNode = (value[i-1].getOwnerDocument() == _doc ? value[i-1].cloneNode(true) : _doc.importNode(value[i-1], true)); Node nextSibling = element.getNextSibling(); if (nextSibling) { parent.insertBefore(importedNode, element.getNextSibling()); } else { parent.appendChild(importedNode); } } } else if (assignElem && HAS_ATTR(assignElem, "type") && iequals(ATTR(assignElem, "type"), "replace")) { // replace: Replace the node specified by 'location' by the value specified by 'expr'. Node parent = element.getParentNode(); if (!parent) ERROR_EXECUTION_THROW("Node has no parent"); if (value.size() != 1) ERROR_EXECUTION_THROW("Value not singular"); Node 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") && iequals(ATTR(assignElem, "type"), "delete")) { // delete: Delete the node specified by 'location'. ('expr' is ignored.). Node parent = element.getParentNode(); if (!parent) ERROR_EXECUTION_THROW("Node has no parent"); 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 = element.getOwnerDocument().importNode(value[i], true); element.appendChild(importedNode); } } } XPathValue NodeSetVariableResolver::resolveVariable(const std::string& namepaceUri, const std::string& name) const { std::map >::const_iterator n = _variables.find(name); if(n == _variables.end()) { ERROR_EXECUTION_THROW("No variable named '" + name + "'"); } #if VERBOSE 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; } std::cout << std::endl; #endif return XPathValue(new NodeSetValue(n->second)); } void NodeSetVariableResolver::setVariable(const std::string& name, const NodeSet& value) { #if VERBOSE 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; #if 0 std::map >::iterator varIter = _variables.begin(); while (varIter != _variables.end()) { std::cout << varIter->first << ":" << std::endl; for (int i = 0; i < varIter->second.size(); i++) { std::cout << varIter->second[i].getNodeType() << " | " << varIter->second[i] << std::endl; } varIter++; } #endif } bool NodeSetVariableResolver::isDeclared(const std::string& name) { #if 0 std::map >::iterator varIter = _variables.begin(); while (varIter != _variables.end()) { std::cout << varIter->first << std::endl; varIter++; } #endif return _variables.find(name) != _variables.end(); } XPathFunction* XPathFunctionResolver::resolveFunction(const std::string& namespace_uri, const std::string& name, const std::vector >& argExprs) const { if (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")); return names; } bool XPathFunctionIn::doEvaluate(const Node& context, const ExecutionContext& executionContext) const { for (int i = 0; i < argCount(); i++) { XPathValue stateName = arg(i, context, executionContext); if (stateName.type() == STRING) { if (_interpreter->isInState(stateName.asString())) { continue; } } return false; } return true; } }