2007-07-19 19:01:42 +02:00
|
|
|
#ifndef ARABICA_XSLT_FUNCTIONS_HPP
|
|
|
|
#define ARABICA_XSLT_FUNCTIONS_HPP
|
2007-08-22 14:22:57 +02:00
|
|
|
|
2007-09-05 00:55:47 +02:00
|
|
|
#include <DOM/SAX2DOM/SAX2DOM.hpp>
|
|
|
|
#include <SAX/helpers/CatchErrorHandler.hpp>
|
2007-08-22 14:22:57 +02:00
|
|
|
|
|
|
|
namespace Arabica
|
|
|
|
{
|
|
|
|
namespace XSLT
|
|
|
|
{
|
|
|
|
|
|
|
|
// node-set document(object, node-set?)
|
2009-07-13 10:24:26 +02:00
|
|
|
class DocumentFunction : public Arabica::XPath::NodeSetXPathFunction<std::string>
|
2007-08-22 14:22:57 +02:00
|
|
|
{
|
2009-07-13 10:24:26 +02:00
|
|
|
typedef Arabica::XPath::NodeSetXPathFunction<std::string> baseT;
|
2007-08-22 14:22:57 +02:00
|
|
|
|
|
|
|
public:
|
2007-08-23 15:55:06 +02:00
|
|
|
DocumentFunction(const std::string& currentBase,
|
2007-10-25 22:42:00 +02:00
|
|
|
const std::vector<Arabica::XPath::XPathExpression<std::string> >& args) :
|
2009-07-13 10:24:26 +02:00
|
|
|
Arabica::XPath::NodeSetXPathFunction<std::string>(1, 2, args),
|
2007-08-23 15:55:06 +02:00
|
|
|
baseURI_(currentBase)
|
2007-08-22 14:22:57 +02:00
|
|
|
{ }
|
|
|
|
|
2009-07-13 10:24:26 +02:00
|
|
|
protected:
|
|
|
|
virtual Arabica::XPath::NodeSet<std::string> doEvaluate(const DOM::Node<std::string>& context,
|
|
|
|
const Arabica::XPath::ExecutionContext<std::string>& executionContext) const
|
2007-08-22 14:22:57 +02:00
|
|
|
{
|
2007-08-25 13:51:29 +02:00
|
|
|
Arabica::XPath::NodeSet<std::string> nodes;
|
|
|
|
|
2009-02-18 09:37:00 +01:00
|
|
|
Arabica::XPath::XPathValue<std::string> a0 = arg(0, context, executionContext);
|
2009-03-27 09:30:28 +01:00
|
|
|
if(argCount() != 1)
|
|
|
|
throw Arabica::XPath::UnsupportedException("two arg version of document()");
|
|
|
|
if(a0.type() != Arabica::XPath::STRING)
|
2007-08-25 13:51:29 +02:00
|
|
|
throw Arabica::XPath::UnsupportedException("node-set arg version of document()");
|
2009-03-27 09:30:28 +01:00
|
|
|
|
|
|
|
load_document(a0.asString(), nodes);
|
2009-07-13 10:24:26 +02:00
|
|
|
return nodes;
|
|
|
|
} // doEvaluate
|
2007-08-22 14:22:57 +02:00
|
|
|
|
|
|
|
private:
|
2007-08-25 13:51:29 +02:00
|
|
|
void load_document(const std::string& location,
|
|
|
|
Arabica::XPath::NodeSet<std::string>& nodes) const
|
2007-08-22 14:22:57 +02:00
|
|
|
{
|
|
|
|
SAX2DOM::Parser<std::string> domParser;
|
|
|
|
SAX::CatchErrorHandler<std::string> eh;
|
|
|
|
domParser.setErrorHandler(eh);
|
|
|
|
|
2007-10-22 16:10:49 +02:00
|
|
|
Arabica::io::URI base(baseURI_);
|
2007-09-28 10:30:16 +02:00
|
|
|
Arabica::io::URI absolute(base, location);
|
2007-08-23 15:55:06 +02:00
|
|
|
|
2007-09-05 14:57:07 +02:00
|
|
|
SAX::InputSource<std::string> is(absolute.as_string());
|
2007-08-22 14:22:57 +02:00
|
|
|
domParser.parse(is);
|
|
|
|
|
|
|
|
if(!eh.errorsReported())
|
2007-08-25 13:51:29 +02:00
|
|
|
nodes.push_back(domParser.getDocument());
|
2007-08-22 14:22:57 +02:00
|
|
|
else
|
|
|
|
std::cerr << eh.errors() << std::endl;
|
|
|
|
} // load_document
|
2007-08-23 15:55:06 +02:00
|
|
|
|
|
|
|
std::string baseURI_;
|
2007-08-22 14:22:57 +02:00
|
|
|
}; // DocumentFunction
|
|
|
|
|
2007-12-25 22:56:28 +01:00
|
|
|
// node-set key(string, object)
|
2009-07-13 10:24:26 +02:00
|
|
|
class KeyFunction : public Arabica::XPath::NodeSetXPathFunction<std::string>
|
2009-02-18 09:37:00 +01:00
|
|
|
{
|
2009-07-13 10:24:26 +02:00
|
|
|
typedef Arabica::XPath::NodeSetXPathFunction<std::string> baseT;
|
2009-02-18 09:37:00 +01:00
|
|
|
public:
|
2009-02-18 10:36:41 +01:00
|
|
|
KeyFunction(const DeclaredKeys& keys,
|
2009-02-26 10:32:55 +01:00
|
|
|
const std::map<std::string, std::string>& inscopeNamespaces,
|
2009-02-18 09:37:00 +01:00
|
|
|
const std::vector<Arabica::XPath::XPathExpression<std::string> >& args) :
|
2009-07-13 10:24:26 +02:00
|
|
|
Arabica::XPath::NodeSetXPathFunction<std::string>(2, 2, args),
|
2009-02-26 10:32:55 +01:00
|
|
|
keys_(keys),
|
|
|
|
namespaces_(inscopeNamespaces)
|
2009-02-18 10:36:41 +01:00
|
|
|
{
|
|
|
|
} // KeyFunction
|
2009-02-18 09:37:00 +01:00
|
|
|
|
2009-07-13 10:24:26 +02:00
|
|
|
protected:
|
|
|
|
virtual Arabica::XPath::NodeSet<std::string> doEvaluate(const DOM::Node<std::string>& context,
|
|
|
|
const Arabica::XPath::ExecutionContext<std::string>& executionContext) const
|
2009-02-18 09:37:00 +01:00
|
|
|
{
|
2009-03-03 08:58:29 +01:00
|
|
|
std::string keyname = argAsString(0, context, executionContext);
|
2010-02-21 00:25:36 +01:00
|
|
|
std::string keyClarkName = XML::QualifiedName<std::string>::parseQName(keyname, true, namespaces_).clarkName();
|
2009-03-03 08:58:29 +01:00
|
|
|
|
2009-02-18 09:37:00 +01:00
|
|
|
Arabica::XPath::XPathValue<std::string> a1 = baseT::arg(1, context, executionContext);
|
|
|
|
if(a1.type() == Arabica::XPath::NODE_SET)
|
2009-03-03 08:58:29 +01:00
|
|
|
return nodeSetUnion(keyClarkName, a1.asNodeSet(), executionContext);
|
2009-02-26 10:32:55 +01:00
|
|
|
|
2009-07-13 10:24:26 +02:00
|
|
|
return keys_.lookup(keyClarkName, a1.asString(), executionContext);
|
|
|
|
} // doEvaluate
|
2009-02-18 09:37:00 +01:00
|
|
|
|
2009-07-13 10:24:26 +02:00
|
|
|
Arabica::XPath::NodeSet<std::string> nodeSetUnion(const std::string& keyClarkName,
|
2009-03-03 08:58:29 +01:00
|
|
|
const Arabica::XPath::NodeSet<std::string> nodes,
|
|
|
|
const Arabica::XPath::ExecutionContext<std::string>& executionContext) const
|
|
|
|
{
|
|
|
|
Arabica::XPath::NodeSet<std::string> results;
|
|
|
|
for(Arabica::XPath::NodeSet<std::string>::const_iterator n = nodes.begin(), ne = nodes.end(); n != ne; ++n)
|
|
|
|
{
|
|
|
|
std::string id = Arabica::XPath::impl::nodeStringValue<std::string, Arabica::default_string_adaptor<std::string> >(*n);
|
|
|
|
results.push_back(keys_.lookup(keyClarkName, id, executionContext));
|
|
|
|
} // for ...
|
|
|
|
results.to_document_order();
|
2009-07-13 10:24:26 +02:00
|
|
|
return results;
|
2009-03-03 08:58:29 +01:00
|
|
|
} // nodeSetUnion
|
|
|
|
|
2009-02-18 10:36:41 +01:00
|
|
|
private:
|
|
|
|
const DeclaredKeys& keys_;
|
2009-02-26 10:32:55 +01:00
|
|
|
std::map<std::string, std::string> namespaces_;
|
|
|
|
|
2009-02-18 09:37:00 +01:00
|
|
|
}; // class KeyFunction
|
|
|
|
|
2007-12-25 22:56:28 +01:00
|
|
|
// string format-number(number, string, string?)
|
|
|
|
|
|
|
|
// node-set current()
|
2009-07-13 10:24:26 +02:00
|
|
|
class CurrentFunction : public Arabica::XPath::NodeSetXPathFunction<std::string>
|
2007-12-25 22:56:28 +01:00
|
|
|
{
|
2009-07-13 10:24:26 +02:00
|
|
|
typedef Arabica::XPath::NodeSetXPathFunction<std::string> baseT;
|
2007-12-25 22:56:28 +01:00
|
|
|
public:
|
|
|
|
CurrentFunction(const std::vector<Arabica::XPath::XPathExpression<std::string> >& args) :
|
2009-07-13 10:24:26 +02:00
|
|
|
Arabica::XPath::NodeSetXPathFunction<std::string>(0, 0, args) { }
|
2007-12-25 22:56:28 +01:00
|
|
|
|
2009-07-13 10:24:26 +02:00
|
|
|
protected:
|
2010-01-10 23:02:43 +01:00
|
|
|
virtual Arabica::XPath::NodeSet<std::string> doEvaluate(const DOM::Node<std::string>& /* context */,
|
|
|
|
const Arabica::XPath::ExecutionContext<std::string>& executionContext) const
|
2007-12-25 22:56:28 +01:00
|
|
|
{
|
|
|
|
Arabica::XPath::NodeSet<std::string> set;
|
|
|
|
set.push_back(executionContext.currentNode());
|
2009-07-13 10:24:26 +02:00
|
|
|
return set;
|
|
|
|
} // doEvaluate
|
2007-12-25 22:56:28 +01:00
|
|
|
}; // CurrentFunction
|
|
|
|
|
|
|
|
// string unparsed-entity-uri(string)
|
2009-07-13 10:13:50 +02:00
|
|
|
class UnparsedEntityUriFunction : public Arabica::XPath::StringXPathFunction<std::string>
|
2008-10-27 23:20:49 +01:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
UnparsedEntityUriFunction(const std::vector<Arabica::XPath::XPathExpression<std::string> >& args) :
|
2009-07-13 10:13:50 +02:00
|
|
|
Arabica::XPath::StringXPathFunction<std::string>(1, 1, args) { }
|
2008-10-27 23:20:49 +01:00
|
|
|
|
2009-07-13 10:13:50 +02:00
|
|
|
protected:
|
2010-01-10 23:02:43 +01:00
|
|
|
virtual std::string doEvaluate(const DOM::Node<std::string>& /* context */,
|
|
|
|
const Arabica::XPath::ExecutionContext<std::string>& /* executionContext */) const
|
2008-10-27 23:20:49 +01:00
|
|
|
{
|
|
|
|
// This is a minimal, but I think conformant, implementation
|
2009-07-13 10:13:50 +02:00
|
|
|
return "";
|
2008-10-27 23:20:49 +01:00
|
|
|
} // evaluate
|
|
|
|
}; // UnparsedEntityUri
|
|
|
|
|
2007-12-25 22:56:28 +01:00
|
|
|
// string generate-id(node-set?)
|
2009-07-13 10:13:50 +02:00
|
|
|
class GenerateIdFunction : public Arabica::XPath::StringXPathFunction<std::string>
|
2008-10-27 20:13:47 +01:00
|
|
|
{
|
2009-07-13 10:13:50 +02:00
|
|
|
typedef Arabica::XPath::StringXPathFunction<std::string> baseT;
|
2008-10-27 20:13:47 +01:00
|
|
|
public:
|
|
|
|
GenerateIdFunction(const std::vector<Arabica::XPath::XPathExpression<std::string> >& args) :
|
2009-07-13 10:13:50 +02:00
|
|
|
Arabica::XPath::StringXPathFunction<std::string>(0, 1, args) { }
|
2008-10-27 20:13:47 +01:00
|
|
|
|
2009-07-13 10:13:50 +02:00
|
|
|
protected:
|
|
|
|
virtual std::string doEvaluate(const DOM::Node<std::string>& context,
|
|
|
|
const Arabica::XPath::ExecutionContext<std::string>& executionContext) const
|
2008-10-27 20:13:47 +01:00
|
|
|
{
|
|
|
|
DOM::Node<std::string> node;
|
|
|
|
if(baseT::argCount() == 0)
|
|
|
|
node = context;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Arabica::XPath::NodeSet<std::string> ns = baseT::argAsNodeSet(0, context, executionContext);
|
|
|
|
if(ns.size() == 0)
|
2009-07-13 10:13:50 +02:00
|
|
|
return "";
|
2008-10-27 20:13:47 +01:00
|
|
|
node = ns.top();
|
|
|
|
} // if ...
|
|
|
|
|
|
|
|
std::ostringstream os;
|
|
|
|
os << node.underlying_impl();
|
2009-07-13 10:13:50 +02:00
|
|
|
return os.str();
|
|
|
|
} // doEvaluate
|
2008-10-27 20:13:47 +01:00
|
|
|
}; // class GenerateIdFunction
|
2007-12-25 22:56:28 +01:00
|
|
|
|
2007-08-22 14:22:57 +02:00
|
|
|
// object system-property(string)
|
2009-07-13 10:13:50 +02:00
|
|
|
class SystemPropertyFunction : public Arabica::XPath::StringXPathFunction<std::string>
|
2007-08-22 14:22:57 +02:00
|
|
|
{
|
2009-07-13 10:13:50 +02:00
|
|
|
typedef Arabica::XPath::StringXPathFunction<std::string> baseT;
|
2007-08-22 14:22:57 +02:00
|
|
|
public:
|
2007-10-25 22:42:00 +02:00
|
|
|
SystemPropertyFunction (const std::vector<Arabica::XPath::XPathExpression<std::string> >& args) :
|
2009-07-13 10:13:50 +02:00
|
|
|
Arabica::XPath::StringXPathFunction<std::string>(1, 1, args) { }
|
2007-12-19 00:03:16 +01:00
|
|
|
|
2009-07-13 10:13:50 +02:00
|
|
|
protected:
|
|
|
|
virtual std::string doEvaluate(const DOM::Node<std::string>& context,
|
|
|
|
const Arabica::XPath::ExecutionContext<std::string>& executionContext) const
|
2007-08-22 14:22:57 +02:00
|
|
|
{
|
|
|
|
std::string property = baseT::argAsString(0, context, executionContext);
|
|
|
|
std::string result;
|
|
|
|
if(property == "xsl:version")
|
2009-07-13 10:13:50 +02:00
|
|
|
return "1.0";
|
|
|
|
if(property == "xsl:vendor")
|
|
|
|
return "Jez Higgins, Jez UK Ltd";
|
2007-08-22 14:22:57 +02:00
|
|
|
else if(property == "xsl:vendor-url")
|
2009-07-13 10:13:50 +02:00
|
|
|
return "http://www.jezuk.co.uk/arabica";
|
|
|
|
return "";
|
2007-08-22 14:22:57 +02:00
|
|
|
} // evaluate
|
|
|
|
}; // SystemPropertyFunction
|
|
|
|
|
2007-12-25 22:56:28 +01:00
|
|
|
// boolean element-available(string)
|
2010-02-21 19:35:58 +01:00
|
|
|
class ElementAvailableFunction : public Arabica::XPath::BooleanXPathFunction<std::string>
|
|
|
|
{
|
|
|
|
typedef Arabica::XPath::BooleanXPathFunction<std::string> baseT;
|
|
|
|
public:
|
|
|
|
ElementAvailableFunction(const std::vector<std::pair<std::string, std::string> >& names,
|
|
|
|
const std::map<std::string, std::string>& inscopeNamespaces,
|
|
|
|
const std::vector<Arabica::XPath::XPathExpression<std::string> >& args) :
|
|
|
|
Arabica::XPath::BooleanXPathFunction<std::string>(1, 1, args),
|
|
|
|
namespaces_(inscopeNamespaces),
|
|
|
|
elementNames_(names)
|
|
|
|
{
|
|
|
|
} // ElementAvailableFunction
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual bool doEvaluate(const DOM::Node<std::string>& context,
|
|
|
|
const Arabica::XPath::ExecutionContext<std::string>& executionContext) const
|
|
|
|
{
|
2010-02-21 23:14:04 +01:00
|
|
|
const std::string functionName = baseT::argAsString(0, context, executionContext);
|
|
|
|
const XML::QualifiedName<std::string> expandedName = XML::QualifiedName<std::string>::parseQName(functionName, true, namespaces_);
|
|
|
|
|
2011-01-01 23:58:29 +01:00
|
|
|
if((expandedName.namespaceUri() != StylesheetConstant::NamespaceURI()) &&
|
|
|
|
(!expandedName.namespaceUri().empty()))
|
2010-02-21 23:14:04 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
static const char* XSLTNames[] = { "apply-imports", "apply-templates", "attributes",
|
|
|
|
"call-template", "choose", "comment", "copy",
|
|
|
|
"copy-of", "element", "fallback", "for-each",
|
|
|
|
"if", "message", "number", "processing-instruction",
|
|
|
|
"text", "value-of", "variable", 0 };
|
|
|
|
|
|
|
|
for(int i = 0; XSLTNames[i] != 0; ++i)
|
|
|
|
if(expandedName.localName() == XSLTNames[i])
|
|
|
|
return true;
|
|
|
|
|
2010-02-21 19:35:58 +01:00
|
|
|
return false;
|
|
|
|
} // doEvaluate
|
|
|
|
|
|
|
|
private:
|
|
|
|
const std::map<std::string, std::string> namespaces_;
|
2010-02-21 23:29:06 +01:00
|
|
|
std::vector<std::pair<std::string, std::string> > elementNames_;
|
2010-02-21 19:35:58 +01:00
|
|
|
}; // class ElementAvailableFunction
|
|
|
|
|
2007-12-25 22:56:28 +01:00
|
|
|
// boolean function-available(string)
|
2010-02-20 00:21:30 +01:00
|
|
|
class FunctionAvailableFunction : public Arabica::XPath::BooleanXPathFunction<std::string>
|
|
|
|
{
|
|
|
|
typedef Arabica::XPath::BooleanXPathFunction<std::string> baseT;
|
|
|
|
public:
|
2010-02-20 22:56:47 +01:00
|
|
|
FunctionAvailableFunction(const std::vector<std::pair<std::string, std::string> >& names,
|
|
|
|
const std::map<std::string, std::string>& inscopeNamespaces,
|
|
|
|
const std::vector<Arabica::XPath::XPathExpression<std::string> >& args) :
|
2010-02-20 00:21:30 +01:00
|
|
|
Arabica::XPath::BooleanXPathFunction<std::string>(1, 1, args),
|
2010-02-21 19:35:58 +01:00
|
|
|
namespaces_(inscopeNamespaces),
|
|
|
|
functionNames_(names)
|
2010-02-20 00:21:30 +01:00
|
|
|
{
|
2010-02-21 00:25:36 +01:00
|
|
|
Arabica::XPath::StandardXPathFunctionResolver<std::string> standardResolver;
|
|
|
|
const std::vector<std::pair<std::string, std::string> > standardNames = standardResolver.validNames();
|
|
|
|
functionNames_.insert(functionNames_.begin(), standardNames.begin(), standardNames.end());
|
2010-02-20 00:21:30 +01:00
|
|
|
} // FunctionAvailableFunction
|
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual bool doEvaluate(const DOM::Node<std::string>& context,
|
|
|
|
const Arabica::XPath::ExecutionContext<std::string>& executionContext) const
|
|
|
|
{
|
|
|
|
const std::string functionName = baseT::argAsString(0, context, executionContext);
|
2010-02-21 00:25:36 +01:00
|
|
|
const XML::QualifiedName<std::string> expandedName = XML::QualifiedName<std::string>::parseQName(functionName, true, namespaces_);
|
|
|
|
|
|
|
|
const std::pair<std::string, std::string> name_to_check = std::make_pair(expandedName.namespaceUri(), expandedName.localName());
|
2010-02-20 00:21:30 +01:00
|
|
|
|
2010-02-21 00:25:36 +01:00
|
|
|
return (std::find(functionNames_.begin(), functionNames_.end(), name_to_check) != functionNames_.end());
|
2010-02-20 00:21:30 +01:00
|
|
|
} // doEvaluate
|
|
|
|
|
|
|
|
private:
|
2010-02-20 22:56:47 +01:00
|
|
|
const std::map<std::string, std::string> namespaces_;
|
2010-02-21 23:29:06 +01:00
|
|
|
std::vector<std::pair<std::string, std::string> > functionNames_;
|
2010-02-20 00:21:30 +01:00
|
|
|
}; // class FunctionAvailableFunction
|
2007-07-19 19:01:42 +02:00
|
|
|
|
2010-02-21 00:25:36 +01:00
|
|
|
class UndefinedFunction : public Arabica::XPath::BooleanXPathFunction<std::string>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
UndefinedFunction(const std::string namespace_uri,
|
|
|
|
const std::string name,
|
|
|
|
const std::vector<Arabica::XPath::XPathExpression<std::string> >& args) :
|
|
|
|
Arabica::XPath::BooleanXPathFunction<std::string>(-1, -1, args)
|
|
|
|
{
|
|
|
|
if(!namespace_uri.empty())
|
|
|
|
{
|
|
|
|
error_ += "{";
|
|
|
|
error_ += namespace_uri;
|
|
|
|
error_ += "}";
|
|
|
|
} // if ..
|
|
|
|
|
|
|
|
error_ += name;
|
|
|
|
} // UndefinedFunction
|
|
|
|
|
|
|
|
protected:
|
2010-02-21 00:39:38 +01:00
|
|
|
virtual bool doEvaluate(const DOM::Node<std::string>&,
|
|
|
|
const Arabica::XPath::ExecutionContext<std::string>&) const
|
2010-02-21 00:25:36 +01:00
|
|
|
{
|
|
|
|
throw Arabica::XPath::UndefinedFunctionException(error_);
|
|
|
|
} // doEvaluate
|
|
|
|
|
|
|
|
std::string error_;
|
|
|
|
}; // class UndefinedFunction
|
|
|
|
|
2007-07-19 19:01:42 +02:00
|
|
|
} // namespace XSLT
|
|
|
|
} // namespace Arabica
|
|
|
|
|
|
|
|
#endif // ARABICA_XSLT_FUNCTIONS_HPP
|
|
|
|
|
2007-08-22 14:22:57 +02:00
|
|
|
|