#ifndef ARABICA_XSLT_FUNCTIONS_HPP #define ARABICA_XSLT_FUNCTIONS_HPP #include #include namespace Arabica { namespace XSLT { // node-set document(object, node-set?) class DocumentFunction : public Arabica::XPath::NodeSetXPathFunction { typedef Arabica::XPath::NodeSetXPathFunction baseT; public: DocumentFunction(const std::string& currentBase, const std::vector >& args) : Arabica::XPath::NodeSetXPathFunction(1, 2, args), baseURI_(currentBase) { } protected: virtual Arabica::XPath::NodeSet doEvaluate(const DOM::Node& context, const Arabica::XPath::ExecutionContext& executionContext) const { Arabica::XPath::NodeSet nodes; Arabica::XPath::XPathValue a0 = arg(0, context, executionContext); if(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 std::string& location, Arabica::XPath::NodeSet& nodes) const { SAX2DOM::Parser domParser; SAX::CatchErrorHandler eh; domParser.setErrorHandler(eh); Arabica::io::URI base(baseURI_); Arabica::io::URI absolute(base, location); SAX::InputSource is(absolute.as_string()); domParser.parse(is); if(!eh.errorsReported()) nodes.push_back(domParser.getDocument()); else std::cerr << eh.errors() << std::endl; } // load_document std::string baseURI_; }; // DocumentFunction // node-set key(string, object) class KeyFunction : public Arabica::XPath::NodeSetXPathFunction { typedef Arabica::XPath::NodeSetXPathFunction baseT; public: KeyFunction(const DeclaredKeys& keys, const std::map& inscopeNamespaces, const std::vector >& args) : Arabica::XPath::NodeSetXPathFunction(2, 2, args), keys_(keys), namespaces_(inscopeNamespaces) { } // KeyFunction protected: virtual Arabica::XPath::NodeSet doEvaluate(const DOM::Node& context, const Arabica::XPath::ExecutionContext& executionContext) const { std::string keyname = argAsString(0, context, executionContext); std::string keyClarkName = XML::QualifiedName::parseQName(keyname, true, UriMapper(namespaces_)).clarkName(); Arabica::XPath::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 Arabica::XPath::NodeSet nodeSetUnion(const std::string& keyClarkName, const Arabica::XPath::NodeSet nodes, const Arabica::XPath::ExecutionContext& executionContext) const { Arabica::XPath::NodeSet results; for(Arabica::XPath::NodeSet::const_iterator n = nodes.begin(), ne = nodes.end(); n != ne; ++n) { std::string 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 UriMapper { public: UriMapper(const std::map& namespaces) : namespaces_(namespaces) { } UriMapper(const UriMapper& rhs) : namespaces_(rhs.namespaces_) { } std::string operator()(const std::string& prefix) const { std::map::const_iterator ns = namespaces_.find(prefix); if(ns == namespaces_.end()) return ""; return ns->second; } //operator() private: const std::map& namespaces_; bool operator==(const UriMapper&) const; UriMapper& operator=(const UriMapper&); }; // class UriMapper }; // class KeyFunction // string format-number(number, string, string?) // node-set current() class CurrentFunction : public Arabica::XPath::NodeSetXPathFunction { typedef Arabica::XPath::NodeSetXPathFunction baseT; public: CurrentFunction(const std::vector >& args) : Arabica::XPath::NodeSetXPathFunction(0, 0, args) { } protected: virtual Arabica::XPath::NodeSet doEvaluate(const DOM::Node& context, const Arabica::XPath::ExecutionContext& executionContext) const { Arabica::XPath::NodeSet set; set.push_back(executionContext.currentNode()); return set; } // doEvaluate }; // CurrentFunction // string unparsed-entity-uri(string) class UnparsedEntityUriFunction : public Arabica::XPath::StringXPathFunction { public: UnparsedEntityUriFunction(const std::vector >& args) : Arabica::XPath::StringXPathFunction(1, 1, args) { } protected: virtual std::string doEvaluate(const DOM::Node& context, const Arabica::XPath::ExecutionContext& executionContext) const { // This is a minimal, but I think conformant, implementation return ""; } // evaluate }; // UnparsedEntityUri // string generate-id(node-set?) class GenerateIdFunction : public Arabica::XPath::StringXPathFunction { typedef Arabica::XPath::StringXPathFunction baseT; public: GenerateIdFunction(const std::vector >& args) : Arabica::XPath::StringXPathFunction(0, 1, args) { } protected: virtual std::string doEvaluate(const DOM::Node& context, const Arabica::XPath::ExecutionContext& executionContext) const { DOM::Node node; if(baseT::argCount() == 0) node = context; else { Arabica::XPath::NodeSet ns = baseT::argAsNodeSet(0, context, executionContext); if(ns.size() == 0) return ""; node = ns.top(); } // if ... std::ostringstream os; os << node.underlying_impl(); return os.str(); } // doEvaluate }; // class GenerateIdFunction // object system-property(string) class SystemPropertyFunction : public Arabica::XPath::StringXPathFunction { typedef Arabica::XPath::StringXPathFunction baseT; public: SystemPropertyFunction (const std::vector >& args) : Arabica::XPath::StringXPathFunction(1, 1, args) { } protected: virtual std::string doEvaluate(const DOM::Node& context, const Arabica::XPath::ExecutionContext& executionContext) const { std::string property = baseT::argAsString(0, context, executionContext); std::string result; if(property == "xsl:version") return "1.0"; if(property == "xsl:vendor") return "Jez Higgins, Jez UK Ltd"; else if(property == "xsl:vendor-url") return "http://www.jezuk.co.uk/arabica"; return ""; } // evaluate }; // SystemPropertyFunction // boolean element-available(string) // boolean function-available(string) } // namespace XSLT } // namespace Arabica #endif // ARABICA_XSLT_FUNCTIONS_HPP