2007-07-19 19:01:42 +02:00
|
|
|
#ifndef ARABICA_XSLT_VARIABLE_STACK_HPP
|
|
|
|
#define ARABICA_XSLT_VARIABLE_STACK_HPP
|
|
|
|
|
|
|
|
#include <XPath/XPath.hpp>
|
|
|
|
#include <map>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace Arabica
|
|
|
|
{
|
|
|
|
namespace XSLT
|
|
|
|
{
|
|
|
|
|
|
|
|
class Variable_instance;
|
|
|
|
typedef boost::shared_ptr<const Variable_instance> Variable_instance_ptr;
|
|
|
|
typedef std::map<std::string, Variable_instance_ptr> Scope;
|
|
|
|
|
|
|
|
class Variable_instance
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
Variable_instance() { }
|
|
|
|
virtual ~Variable_instance() { }
|
|
|
|
|
|
|
|
virtual const std::string& namespace_uri() const = 0;
|
|
|
|
virtual const std::string& name() const = 0;
|
2007-10-22 19:42:50 +02:00
|
|
|
virtual Arabica::XPath::XPathValue<std::string> value() const = 0;
|
2007-07-19 19:01:42 +02:00
|
|
|
|
|
|
|
virtual void injectGlobalScope(const Scope& scope) const = 0;
|
|
|
|
|
|
|
|
private:
|
|
|
|
Variable_instance(const Variable_instance&);
|
|
|
|
Variable_instance& operator=(const Variable_instance&);
|
|
|
|
bool operator==(const Variable_instance&) const;
|
|
|
|
}; // Variable_instance
|
|
|
|
|
|
|
|
class VariableStack : public Arabica::XPath::VariableResolver<std::string>
|
|
|
|
{
|
|
|
|
public:
|
2008-08-02 23:41:44 +02:00
|
|
|
VariableStack()
|
|
|
|
{
|
2007-07-19 19:01:42 +02:00
|
|
|
stack_.push_back(Scope());
|
2008-08-02 23:41:44 +02:00
|
|
|
|
2007-07-19 19:01:42 +02:00
|
|
|
params_.push_back(Scope());
|
|
|
|
params_.push_back(Scope());
|
2008-08-02 23:41:44 +02:00
|
|
|
} // VariableStack
|
|
|
|
|
2007-07-19 19:01:42 +02:00
|
|
|
VariableStack(const VariableStack& rhs) :
|
|
|
|
stack_(rhs.stack_),
|
|
|
|
params_(rhs.params_)
|
|
|
|
{
|
|
|
|
} // VariableStack
|
|
|
|
|
|
|
|
void pushScope()
|
2008-08-02 23:41:44 +02:00
|
|
|
{
|
|
|
|
stack_.push_back(Scope());
|
2007-07-19 19:01:42 +02:00
|
|
|
params_.push_back(Scope());
|
2008-08-02 23:41:44 +02:00
|
|
|
} // pushScope
|
2007-07-19 19:01:42 +02:00
|
|
|
|
2007-11-01 23:28:20 +01:00
|
|
|
void chainScope()
|
|
|
|
{
|
|
|
|
stack_.push_back(Scope(stack_.back()));
|
|
|
|
params_.push_back(Scope(params_.back()));
|
|
|
|
} // chainsScope
|
|
|
|
|
2008-08-02 23:41:44 +02:00
|
|
|
void popScope()
|
|
|
|
{
|
2007-07-19 19:01:42 +02:00
|
|
|
params_.pop_back();
|
2008-08-02 23:41:44 +02:00
|
|
|
stack_.pop_back();
|
|
|
|
} // popScope
|
|
|
|
|
2007-07-19 19:01:42 +02:00
|
|
|
void topLevelParam(Variable_instance_ptr param)
|
|
|
|
{
|
|
|
|
params_.front()[clarkName(param)] = param;
|
|
|
|
} // topLevelParam
|
|
|
|
|
2007-10-27 01:21:21 +02:00
|
|
|
std::string passParam(Variable_instance_ptr param)
|
2007-07-19 19:01:42 +02:00
|
|
|
{
|
2007-10-27 01:21:21 +02:00
|
|
|
std::string clark_name = clarkName(param);
|
2007-11-21 23:35:04 +01:00
|
|
|
Scope& params = params_.back();
|
|
|
|
|
|
|
|
if(params.find(clark_name) != params.end())
|
|
|
|
throw std::runtime_error("Duplicate parameter name in xsl:with-param - " + clark_name);
|
|
|
|
params[clark_name] = param;
|
2007-10-27 01:21:21 +02:00
|
|
|
return clark_name;
|
2007-07-19 19:01:42 +02:00
|
|
|
} // passParam
|
|
|
|
|
2007-10-27 01:21:21 +02:00
|
|
|
void unpassParam(const std::string& name)
|
|
|
|
{
|
|
|
|
params_.back().erase(name);
|
|
|
|
} // unpassParam
|
|
|
|
|
2007-07-19 19:01:42 +02:00
|
|
|
void declareParam(Variable_instance_ptr param)
|
|
|
|
{
|
|
|
|
ScopeStack::reverse_iterator p = params_.rbegin()+1;
|
2008-08-02 23:41:44 +02:00
|
|
|
Scope::iterator i = p->find(clarkName(param));
|
|
|
|
if(i == p->end())
|
2007-07-19 19:01:42 +02:00
|
|
|
declareVariable(param);
|
|
|
|
else
|
|
|
|
declareVariable(i->second);
|
|
|
|
} // declareParam
|
|
|
|
|
2008-08-02 23:41:44 +02:00
|
|
|
void declareVariable(Variable_instance_ptr var)
|
|
|
|
{
|
2007-11-21 23:35:04 +01:00
|
|
|
std::string name = clarkName(var);
|
|
|
|
Scope& stack = stack_.back();
|
2008-08-02 23:41:44 +02:00
|
|
|
|
2007-11-21 23:35:04 +01:00
|
|
|
if(stack.find(name) != stack.end())
|
|
|
|
throw std::runtime_error("Duplicate variable name : " + name);
|
2008-08-02 23:41:44 +02:00
|
|
|
stack[clarkName(var)] = var;
|
|
|
|
} // declareVariable
|
|
|
|
|
2007-07-19 19:01:42 +02:00
|
|
|
void freezeTopLevel()
|
|
|
|
{
|
|
|
|
const Scope& top = stack_.front();
|
|
|
|
for(Scope::const_iterator v = top.begin(), ve = top.end(); v != ve; ++v)
|
|
|
|
v->second->injectGlobalScope(top);
|
|
|
|
} // freezeTopLevel
|
2008-08-02 23:41:44 +02:00
|
|
|
|
2007-07-19 19:01:42 +02:00
|
|
|
void injectGlobalScope(const Scope& scope)
|
|
|
|
{
|
|
|
|
stack_.front() = scope;
|
|
|
|
} // injectGlobalScope
|
2008-08-02 23:41:44 +02:00
|
|
|
|
2007-10-22 19:42:50 +02:00
|
|
|
virtual Arabica::XPath::XPathValue<std::string> resolveVariable(const std::string& namespace_uri,
|
|
|
|
const std::string& name) const
|
2007-07-19 19:01:42 +02:00
|
|
|
{
|
|
|
|
std::string clarkName = "{" + namespace_uri + "}" + name;
|
2008-08-02 23:41:44 +02:00
|
|
|
if(std::find(resolutionStack_.begin(), resolutionStack_.end(), clarkName) != resolutionStack_.end())
|
|
|
|
throw std::runtime_error("Circular dependency: " + clarkName + " refers to itself directly or indirectly.");
|
|
|
|
|
|
|
|
resolutionStack_.push_back(clarkName);
|
|
|
|
Arabica::XPath::XPathValue<std::string> val = lookup(stack_.back(), clarkName);
|
|
|
|
resolutionStack_.pop_back();
|
|
|
|
|
|
|
|
if(val != 0)
|
|
|
|
return val;
|
|
|
|
|
|
|
|
val = lookup(stack_.front(), clarkName); // try our "global" scope
|
|
|
|
if(val == 0)
|
|
|
|
throw Arabica::XPath::UnboundVariableException(clarkName);
|
|
|
|
|
|
|
|
return val;
|
2007-07-19 19:01:42 +02:00
|
|
|
} // resolveVariable
|
2008-08-02 23:41:44 +02:00
|
|
|
|
2007-07-19 19:01:42 +02:00
|
|
|
private:
|
2008-08-02 23:41:44 +02:00
|
|
|
typedef std::vector<Scope> ScopeStack;
|
|
|
|
|
2007-07-19 19:01:42 +02:00
|
|
|
std::string clarkName(Variable_instance_ptr var)
|
|
|
|
{
|
|
|
|
return "{" + var->namespace_uri() + "}" + var->name();
|
|
|
|
} // clarkName
|
2008-08-02 23:41:44 +02:00
|
|
|
|
|
|
|
Arabica::XPath::XPathValue<std::string> lookup(const Scope& scope, const std::string& name) const
|
|
|
|
{
|
|
|
|
Scope::const_iterator i = scope.find(name);
|
|
|
|
if(i == scope.end())
|
|
|
|
return Arabica::XPath::XPathValue<std::string>(0);
|
|
|
|
|
|
|
|
return i->second->value();
|
|
|
|
} // lookup
|
|
|
|
|
|
|
|
ScopeStack stack_;
|
2007-07-19 19:01:42 +02:00
|
|
|
ScopeStack params_;
|
2008-08-02 23:41:44 +02:00
|
|
|
mutable std::vector<std::string> resolutionStack_;
|
2007-07-19 19:01:42 +02:00
|
|
|
}; // class VariableStack
|
|
|
|
|
|
|
|
} // namespace XSLT
|
|
|
|
} // namespace Arabica
|
|
|
|
#endif // ARABICA_XSLT_VARIABLE_STACK_HPP
|
|
|
|
|