#ifndef ARABICA_XSLT_FUNCTIONS_HPP #define ARABICA_XSLT_FUNCTIONS_HPP #include #include namespace Arabica { namespace XSLT { // node-set document(object, node-set?) template class DocumentFunction : public Arabica::XPath::NodeSetXPathFunction { typedef Arabica::XPath::NodeSetXPathFunction baseT; typedef Arabica::XPath::XPathExpression XPathExpression; typedef std::vector ArgList; typedef Arabica::XPath::XPathValue XPathValue; typedef Arabica::XPath::NodeSet NodeSet; typedef Arabica::XPath::ExecutionContext XPathExecutionContext; typedef DOM::Node DOMNode; public: static const string_type& name() { static const string_type n = string_adaptor::construct_from_utf8("document"); return n; } // name DocumentFunction(const string_type& currentBase, const ArgList& args) : baseT(1, 2, args), baseURI_(currentBase) { } protected: virtual NodeSet doEvaluate(const DOMNode& context, const XPathExecutionContext& executionContext) const { NodeSet nodes; XPathValue a0 = arg(0, context, executionContext); if(baseT::argCount() != 1) throw Arabica::XPath::UnsupportedException("two arg version of document()"); if(a0.type() != Arabica::XPath::STRING) throw Arabica::XPath::UnsupportedException("node-set arg version of document()"); load_document(a0.asString(), nodes); return nodes; } // doEvaluate private: void load_document(const string_type& location, NodeSet& nodes) const { SAX2DOM::Parser domParser; SAX::CatchErrorHandler eh; domParser.setErrorHandler(eh); Arabica::io::URI base(string_adaptor::asStdString(baseURI_)); Arabica::io::URI absolute(base, string_adaptor::asStdString(location)); SAX::InputSource is(string_adaptor::construct_from_utf8(absolute.as_string().c_str())); domParser.parse(is); if(!eh.errorsReported()) nodes.push_back(domParser.getDocument()); else std::cerr << eh.errors() << std::endl; } // load_document string_type baseURI_; }; // DocumentFunction // node-set key(string, object) template class KeyFunction : public Arabica::XPath::NodeSetXPathFunction { typedef Arabica::XPath::NodeSetXPathFunction baseT; typedef Arabica::XPath::XPathExpression XPathExpression; typedef std::vector ArgList; typedef Arabica::XPath::XPathValue XPathValue; typedef Arabica::XPath::NodeSet NodeSet; typedef Arabica::XPath::ExecutionContext XPathExecutionContext; typedef DOM::Node DOMNode; typedef XML::QualifiedName QualifiedName; public: static const string_type& name() { static const string_type n = string_adaptor::construct_from_utf8("key"); return n; } // name KeyFunction(const DeclaredKeys& keys, const std::map& inscopeNamespaces, const ArgList& args) : baseT(2, 2, args), keys_(keys), namespaces_(inscopeNamespaces) { } // KeyFunction protected: virtual NodeSet doEvaluate(const DOMNode& context, const XPathExecutionContext& executionContext) const { string_type keyname = argAsString(0, context, executionContext); string_type keyClarkName = QualifiedName::parseQName(keyname, true, namespaces_).clarkName(); XPathValue a1 = baseT::arg(1, context, executionContext); if(a1.type() == Arabica::XPath::NODE_SET) return nodeSetUnion(keyClarkName, a1.asNodeSet(), executionContext); return keys_.lookup(keyClarkName, a1.asString(), executionContext); } // doEvaluate NodeSet nodeSetUnion(const string_type& keyClarkName, const NodeSet nodes, const XPathExecutionContext& executionContext) const { NodeSet results; for(typename NodeSet::const_iterator n = nodes.begin(), ne = nodes.end(); n != ne; ++n) { string_type id = Arabica::XPath::impl::nodeStringValue(*n); results.push_back(keys_.lookup(keyClarkName, id, executionContext)); } // for ... results.to_document_order(); return results; } // nodeSetUnion private: const DeclaredKeys& keys_; std::map namespaces_; }; // class KeyFunction // string format-number(number, string, string?) // node-set current() template class CurrentFunction : public Arabica::XPath::NodeSetXPathFunction { typedef Arabica::XPath::NodeSetXPathFunction baseT; typedef Arabica::XPath::XPathExpression XPathExpression; typedef std::vector ArgList; typedef Arabica::XPath::NodeSet NodeSet; typedef Arabica::XPath::ExecutionContext XPathExecutionContext; typedef DOM::Node DOMNode; public: static const string_type& name() { static const string_type n = string_adaptor::construct_from_utf8("current"); return n; } // name CurrentFunction(const ArgList& args) : baseT(0, 0, args) { } protected: virtual NodeSet doEvaluate(const DOMNode& /* context */, const XPathExecutionContext& executionContext) const { NodeSet set; set.push_back(executionContext.currentNode()); return set; } // doEvaluate }; // CurrentFunction // string unparsed-entity-uri(string) template class UnparsedEntityUriFunction : public Arabica::XPath::StringXPathFunction { typedef Arabica::XPath::StringXPathFunction baseT; typedef Arabica::XPath::XPathExpression XPathExpression; typedef std::vector ArgList; typedef Arabica::XPath::ExecutionContext XPathExecutionContext; typedef DOM::Node DOMNode; public: static const string_type& name() { static const string_type n = string_adaptor::construct_from_utf8("unparsed-entity-uri"); return n; } // name UnparsedEntityUriFunction(const ArgList& args) : baseT(1, 1, args) { } protected: virtual string_type doEvaluate(const DOMNode& /* context */, const XPathExecutionContext& /* executionContext */) const { // This is a minimal, but I think conformant, implementation return string_adaptor::empty_string(); } // evaluate }; // UnparsedEntityUri // string generate-id(node-set?) template class GenerateIdFunction : public Arabica::XPath::StringXPathFunction { typedef Arabica::XPath::StringXPathFunction baseT; typedef Arabica::XPath::XPathExpression XPathExpression; typedef std::vector ArgList; typedef Arabica::XPath::NodeSet NodeSet; typedef Arabica::XPath::ExecutionContext XPathExecutionContext; typedef DOM::Node DOMNode; public: static const string_type& name() { static const string_type n = string_adaptor::construct_from_utf8("generate-id"); return n; } // name GenerateIdFunction(const ArgList& args) : baseT(0, 1, args) { } protected: virtual string_type doEvaluate(const DOMNode& context, const XPathExecutionContext& executionContext) const { DOMNode node; if(baseT::argCount() == 0) node = context; else { NodeSet ns = baseT::argAsNodeSet(0, context, executionContext); if(ns.size() == 0) return string_adaptor::empty_string(); node = ns.top(); } // if ... std::basic_ostringstream os; os << node.underlying_impl(); return os.str(); } // doEvaluate }; // class GenerateIdFunction // object system-property(string) template class SystemPropertyFunction : public Arabica::XPath::StringXPathFunction { typedef Arabica::XPath::StringXPathFunction baseT; typedef Arabica::XPath::XPathExpression XPathExpression; typedef std::vector ArgList; typedef Arabica::XPath::ExecutionContext XPathExecutionContext; typedef DOM::Node DOMNode; public: static const string_type& name() { static const string_type n = string_adaptor::construct_from_utf8("system-property"); return n; } // name SystemPropertyFunction (const ArgList& args) : baseT(1, 1, args) { } protected: virtual string_type doEvaluate(const DOMNode& context, const XPathExecutionContext& executionContext) const { typedef StylesheetConstant SC; string_type property = baseT::argAsString(0, context, executionContext); string_type result; if(property == SC::version_property) return SC::Version; if(property == SC::vendor_property) return SC::Vendor; else if(property == SC::vendor_url_property) return SC::VendorUrl; return string_adaptor::empty_string(); } // evaluate }; // SystemPropertyFunction // boolean element-available(string) template class ElementAvailableFunction : public Arabica::XPath::BooleanXPathFunction { typedef Arabica::XPath::BooleanXPathFunction baseT; typedef Arabica::XPath::XPathExpression XPathExpression; typedef std::vector ArgList; typedef Arabica::XPath::ExecutionContext XPathExecutionContext; typedef DOM::Node DOMNode; typedef XML::QualifiedName QualifiedName; public: static const string_type& name() { static const string_type n = string_adaptor::construct_from_utf8("element_available"); return n; } // name ElementAvailableFunction(const std::vector >& names, const std::map& inscopeNamespaces, const ArgList& args) : baseT(1, 1, args), namespaces_(inscopeNamespaces), elementNames_(names) { } // ElementAvailableFunction protected: virtual bool doEvaluate(const DOMNode& context, const XPathExecutionContext& executionContext) const { typedef StylesheetConstant SC; const string_type functionName = baseT::argAsString(0, context, executionContext); const QualifiedName expandedName = QualifiedName::parseQName(functionName, true, namespaces_); if((expandedName.namespaceUri() != StylesheetConstant::NamespaceURI) && (!expandedName.namespaceUri().empty())) return false; static string_type XSLTNames[] = { SC::apply_imports, SC::apply_templates, SC::attribute, SC::call_template, SC::choose, SC::comment, SC::copy, SC::copy_of, SC::element, SC::fallback, SC::for_each, SC::if_, SC::message, SC::number, SC::processing_instruction, SC::text, SC::value_of, SC::variable, string_adaptor::empty_string() }; for(int i = 0; XSLTNames[i] != string_adaptor::empty_string(); ++i) if(expandedName.localName() == XSLTNames[i]) return true; return false; } // doEvaluate private: const std::map namespaces_; std::vector > elementNames_; }; // class ElementAvailableFunction // boolean function-available(string) template class FunctionAvailableFunction : public Arabica::XPath::BooleanXPathFunction { typedef Arabica::XPath::BooleanXPathFunction baseT; typedef Arabica::XPath::XPathExpression XPathExpression; typedef std::vector ArgList; typedef Arabica::XPath::ExecutionContext XPathExecutionContext; typedef DOM::Node DOMNode; typedef XML::QualifiedName QualifiedName; public: static const string_type& name() { static const string_type n = string_adaptor::construct_from_utf8("function-available"); return n; } // name FunctionAvailableFunction(const std::vector >& names, const std::map& inscopeNamespaces, const ArgList& args) : baseT(1, 1, args), namespaces_(inscopeNamespaces), functionNames_(names) { Arabica::XPath::StandardXPathFunctionResolver standardResolver; const std::vector > standardNames = standardResolver.validNames(); functionNames_.insert(functionNames_.begin(), standardNames.begin(), standardNames.end()); } // FunctionAvailableFunction protected: virtual bool doEvaluate(const DOMNode& context, const XPathExecutionContext& executionContext) const { const string_type functionName = baseT::argAsString(0, context, executionContext); const QualifiedName expandedName = QualifiedName::parseQName(functionName, true, namespaces_); const std::pair name_to_check = std::make_pair(expandedName.namespaceUri(), expandedName.localName()); return (std::find(functionNames_.begin(), functionNames_.end(), name_to_check) != functionNames_.end()); } // doEvaluate private: const std::map namespaces_; std::vector > functionNames_; }; // class FunctionAvailableFunction template class UndefinedFunction : public Arabica::XPath::BooleanXPathFunction { typedef Arabica::XPath::BooleanXPathFunction baseT; typedef Arabica::XPath::XPathExpression XPathExpression; typedef std::vector ArgList; typedef Arabica::XPath::ExecutionContext XPathExecutionContext; typedef DOM::Node DOMNode; public: UndefinedFunction(const string_type namespace_uri, const string_type name, const ArgList& args) : baseT(-1, -1, args) { typedef Arabica::text::Unicode UnicodeT; if(!namespace_uri.empty()) { error_ += UnicodeT::LEFT_SQUARE_BRACKET; error_ += namespace_uri; error_ += UnicodeT::RIGHT_SQUARE_BRACKET; } // if .. error_ += name; } // UndefinedFunction protected: virtual bool doEvaluate(const DOMNode&, const XPathExecutionContext&) const { throw Arabica::XPath::UndefinedFunctionException(string_adaptor::asStdString(error_)); } // doEvaluate string_type error_; }; // class UndefinedFunction } // namespace XSLT } // namespace Arabica #endif // ARABICA_XSLT_FUNCTIONS_HPP