mirror of
https://github.com/jezhiggins/arabica
synced 2024-12-30 22:23:40 +01:00
f610d739fe
Templates are now constructed with their precedence. Variables are too, with a tweak to allow for the immediate evaluation of non-topl-level params and vars. The execution context now no longer needs to track variable precedence, which is good because it will be getting it wrong anyway. Corresponding simplifications follow to compliation context.
222 lines
6.7 KiB
C++
Executable file
222 lines
6.7 KiB
C++
Executable file
#ifndef ARABICA_XSLT_COMPILATION_CONTEXT
|
|
#define ARABICA_XSLT_COMPILATION_CONTEXT
|
|
|
|
#include <SAX/XMLReader.hpp>
|
|
#include <SAX/helpers/DefaultHandler.hpp>
|
|
#include <XML/strings.hpp>
|
|
#include <XPath/XPath.hpp>
|
|
#include <stack>
|
|
|
|
#include "xslt_stylesheet_parser.hpp"
|
|
#include "xslt_functions.hpp"
|
|
|
|
namespace Arabica
|
|
{
|
|
namespace XSLT
|
|
{
|
|
class CompiledStylesheet;
|
|
class ItemContainer;
|
|
|
|
class CompilationContext :
|
|
private Arabica::XPath::FunctionResolver<std::string>,
|
|
private Arabica::XPath::NamespaceContext<std::string, Arabica::default_string_adaptor<std::string> >
|
|
{
|
|
public:
|
|
CompilationContext(StylesheetParser& parser,
|
|
CompiledStylesheet& stylesheet) :
|
|
parser_(parser),
|
|
stylesheet_(stylesheet),
|
|
autoNs_(1),
|
|
current_allowed_(false)
|
|
{
|
|
xpath_.setNamespaceContext(*this);
|
|
xpath_.setFunctionResolver(*this);
|
|
} // CompilationContext
|
|
|
|
~CompilationContext()
|
|
{
|
|
// delete any left over - will only be the case if unwinding
|
|
while(handlerStack_.size() > 1)
|
|
{
|
|
delete handlerStack_.top();
|
|
handlerStack_.pop();
|
|
} // while ...
|
|
} // ~CompilationContext
|
|
|
|
void root(SAX::DefaultHandler<std::string>& root)
|
|
{
|
|
handlerStack_.push(&root);
|
|
} // root
|
|
|
|
StylesheetParser& parser() const { return parser_; }
|
|
Arabica::XPath::XPathExpressionPtr<std::string> xpath_expression(const std::string& expr) const { return xpath_.compile_expr(expr); }
|
|
std::vector<Arabica::XPath::MatchExpr<std::string> > xpath_match(const std::string& match) const
|
|
{
|
|
DisallowCurrent guard(current_allowed_);
|
|
return xpath_.compile_match(match);
|
|
} // xpath_match
|
|
Arabica::XPath::XPathExpressionPtr<std::string> xpath_attribute_value_template(const std::string& expr) const { return xpath_.compile_attribute_value_template(expr); }
|
|
CompiledStylesheet& stylesheet() const { return stylesheet_; }
|
|
|
|
std::pair<std::string, std::string> processInternalQName(const std::string& qName) const
|
|
{
|
|
if(!Arabica::XML::is_qname(qName))
|
|
throw SAX::SAXException("Bad name : " + qName);
|
|
// 2.4 The default namespace is not used for unprefixed names.
|
|
if(qName.find(':') == std::string::npos)
|
|
return std::make_pair("", qName);
|
|
return parser_.processQName(qName);
|
|
} // processInternalQName
|
|
|
|
std::string makeAbsolute(const std::string& href) const
|
|
{
|
|
return parser_.makeAbsolute(href);
|
|
} // makeAbsolute
|
|
|
|
std::string setBase(const std::string& href) const
|
|
{
|
|
return parser_.setBase(href);
|
|
} // setBase
|
|
|
|
void push(ItemContainer* parent,
|
|
SAX::DefaultHandler<std::string>* newHandler,
|
|
const std::string& namespaceURI,
|
|
const std::string& localName,
|
|
const std::string& qName,
|
|
const SAX::Attributes<std::string>& atts)
|
|
{
|
|
parentStack_.push(parent);
|
|
handlerStack_.push(newHandler);
|
|
parser_.setContentHandler(*newHandler);
|
|
newHandler->startElement(namespaceURI, qName, localName, atts);
|
|
} // push
|
|
|
|
void pop()
|
|
{
|
|
parentStack_.pop();
|
|
delete handlerStack_.top();
|
|
handlerStack_.pop();
|
|
parser_.setContentHandler(*handlerStack_.top());
|
|
} // pop
|
|
|
|
ItemContainer& parentContainer() const
|
|
{
|
|
return *parentStack_.top();
|
|
} // parentContainer
|
|
|
|
SAX::ContentHandler<std::string>& parentHandler() const
|
|
{
|
|
parser_.setContentHandler(*handlerStack_.top());
|
|
return parser_.contentHandler();
|
|
} // parentHandler
|
|
|
|
std::map<std::string, std::string> inScopeNamespaces() const
|
|
{
|
|
return parser_.inScopeNamespaces();
|
|
} // inScopeNamespaces
|
|
|
|
void addNamespaceAlias(const std::string& stylesheet_namespace,
|
|
const std::string& result_prefix,
|
|
const std::string& result_namespace)
|
|
{
|
|
namespaceRemap_[stylesheet_namespace] = std::make_pair(result_prefix, result_namespace);
|
|
} // addNamespaceAlias
|
|
|
|
bool isRemapped(const std::string& namespaceURI) const
|
|
{
|
|
return namespaceRemap_.find(namespaceURI) != namespaceRemap_.end();
|
|
} // isRemapped
|
|
|
|
const std::pair<std::string, std::string>& remappedNamespace(const std::string& namespaceURI)
|
|
{
|
|
return namespaceRemap_[namespaceURI];
|
|
} // remappedNamespace
|
|
|
|
std::string autoNamespacePrefix() const
|
|
{
|
|
std::ostringstream ss;
|
|
ss << "auto-ns" << autoNs_++;
|
|
return ss.str();
|
|
} // autoNamespacePrefix
|
|
|
|
void push_import_precedence()
|
|
{
|
|
precedenceStack_.push();
|
|
stylesheet_.push_import_precedence();
|
|
} // push_import_precedence
|
|
|
|
void pop_import_precedence()
|
|
{
|
|
} // pop_import_precedence
|
|
|
|
const Precedence& precedence() const
|
|
{
|
|
return precedenceStack_.top();
|
|
} // precedence
|
|
|
|
private:
|
|
// FunctionResolver
|
|
virtual Arabica::XPath::XPathFunction<std::string>* resolveFunction(
|
|
const std::string& namespace_uri,
|
|
const std::string& name,
|
|
const std::vector<Arabica::XPath::XPathExpression<std::string> >& argExprs) const
|
|
{
|
|
if(!namespace_uri.empty())
|
|
return 0;
|
|
|
|
// document
|
|
if(name == "document")
|
|
return new DocumentFunction(parser_.currentBase(), argExprs);
|
|
// key
|
|
// format-number
|
|
if((name == "current") && (current_allowed_))
|
|
return new CurrentFunction(argExprs);
|
|
// unparsed-entity-uri
|
|
//if(name == "unparsed-entity-uri")
|
|
// return new UnparsedEntityUriFunction(argExprs);
|
|
// generate-id
|
|
if(name == "generate-id")
|
|
return new GenerateIdFunction(argExprs);
|
|
if(name == "system-property")
|
|
return new SystemPropertyFunction(argExprs);
|
|
// element-available
|
|
// function-available
|
|
|
|
return 0;
|
|
} // resolveFunction
|
|
|
|
// NamespaceContext
|
|
virtual std::string namespaceURI(const std::string& prefix) const
|
|
{
|
|
return parser_.namespaceURI(prefix);
|
|
} // namespaceURI
|
|
|
|
typedef std::pair<std::string, std::string> Namespace;
|
|
|
|
StylesheetParser& parser_;
|
|
Arabica::XPath::XPath<std::string> xpath_;
|
|
CompiledStylesheet& stylesheet_;
|
|
std::stack<SAX::DefaultHandler<std::string>*> handlerStack_;
|
|
std::stack<ItemContainer*> parentStack_;
|
|
std::map<std::string, Namespace> namespaceRemap_;
|
|
PrecedenceStack precedenceStack_;
|
|
|
|
CompilationContext(const CompilationContext&);
|
|
mutable int autoNs_;
|
|
mutable bool current_allowed_;
|
|
|
|
class DisallowCurrent
|
|
{
|
|
public:
|
|
DisallowCurrent(bool& allow) : allow_(allow) { allow_ = false; }
|
|
~DisallowCurrent() { allow_ = true; }
|
|
private:
|
|
bool& allow_;
|
|
}; // DisallowCurrent
|
|
}; // class CompilationContext
|
|
|
|
} // namespace XSLT
|
|
} // namespace Arabica
|
|
|
|
#endif // ARABICA_XSLT_COMPILATION_CONTEXT
|
|
|