mirror of
https://github.com/jezhiggins/arabica
synced 2024-12-29 22:23:27 +01:00
271 lines
10 KiB
C++
271 lines
10 KiB
C++
#ifndef ARABICA_XSLT_STYLESHEETCONSTANT_HPP
|
|
#define ARABICA_XSLT_STYLESHEETCONSTANT_HPP
|
|
|
|
#include <XML/XMLCharacterClasses.hpp>
|
|
#include <XPath/impl/xpath_namespace_context.hpp>
|
|
#include <memory>
|
|
|
|
#include "xslt_stylesheet_parser.hpp"
|
|
#include "xslt_compiled_stylesheet.hpp"
|
|
#include "xslt_compilation_context.hpp"
|
|
#include "handler/xslt_value_validation.hpp"
|
|
#include "handler/xslt_template_handler.hpp"
|
|
#include "handler/xslt_include_handler.hpp"
|
|
#include "handler/xslt_output_handler.hpp"
|
|
#include "handler/xslt_namespace_alias_handler.hpp"
|
|
#include "handler/xslt_key_handler.hpp"
|
|
#include "handler/xslt_foreign_element_handler.hpp"
|
|
|
|
namespace Arabica
|
|
{
|
|
namespace XSLT
|
|
{
|
|
|
|
template<class string_type, class string_adaptor>
|
|
class StylesheetHandler : public SAX::DefaultHandler<string_type, string_adaptor>
|
|
{
|
|
typedef StylesheetConstant<string_type, string_adaptor> SC;
|
|
typedef AttributeValidators<string_type, string_adaptor> AV;
|
|
public:
|
|
typedef string_type stringT;
|
|
typedef string_adaptor string_adaptorT;
|
|
typedef SAX::Attributes<string_type, string_adaptor> AttributesT;
|
|
typedef SAX::DefaultHandler<string_type, string_adaptor> DefaultHandlerT;
|
|
typedef CompilationContext<string_type, string_adaptor> CompilationContextT;
|
|
|
|
StylesheetHandler(CompilationContextT& context) :
|
|
context_(context),
|
|
top_(false)
|
|
{
|
|
context_.root(*this);
|
|
includer_.context(context_, this);
|
|
} // StylesheetHandler
|
|
|
|
virtual void startDocument()
|
|
{
|
|
top_ = true;
|
|
} // startDocument
|
|
|
|
virtual void startElement(const string_type& namespaceURI,
|
|
const string_type& localName,
|
|
const string_type& qName,
|
|
const AttributesT& atts)
|
|
{
|
|
if(top_)
|
|
{
|
|
top_ = false;
|
|
if(namespaceURI == SC::NamespaceURI)
|
|
startStylesheet(namespaceURI, localName, qName, atts);
|
|
else
|
|
startLREAsStylesheet(namespaceURI, localName, qName, atts);
|
|
return;
|
|
} // if(top_)
|
|
|
|
if(namespaceURI == SC::NamespaceURI)
|
|
startXSLTElement(namespaceURI, localName, qName, atts);
|
|
else if(!string_adaptor::empty(namespaceURI))
|
|
startForeignElement(namespaceURI, localName, qName, atts);
|
|
else
|
|
oops(qName);
|
|
} // startElement
|
|
|
|
virtual void endElement(const string_type& /* namespaceURI */,
|
|
const string_type& /* localName */,
|
|
const string_type& /* qName */)
|
|
{
|
|
} // endElement
|
|
|
|
virtual void characters(const string_type& ch)
|
|
{
|
|
verifyNoCharacterData<string_type, string_adaptor>(ch, SC::stylesheet);
|
|
} // characters
|
|
|
|
virtual void endDocument()
|
|
{
|
|
includer_.unwind_imports();
|
|
context_.stylesheet().prepare();
|
|
} // endDocument
|
|
|
|
private:
|
|
void startStylesheet(const string_type& /* namespaceURI */,
|
|
const string_type& localName,
|
|
const string_type& qName,
|
|
const AttributesT& atts)
|
|
{
|
|
if(localName != SC::stylesheet && localName != SC::transform)
|
|
throw SAX::SAXException("Top-level element must be 'stylesheet' or 'transform'.");
|
|
|
|
static const AV rules = AV::rule(SC::version, true)
|
|
.rule(SC::extension_element_prefixes, false)
|
|
.rule(SC::exclude_result_prefixes, false)
|
|
.rule(SC::id, false);
|
|
|
|
std::map<string_type, string_type> attributes = rules.gather(qName, atts);
|
|
if(attributes[SC::version] != SC::Version)
|
|
throw SAX::SAXException("I'm only a poor version 1.0 XSLT Transformer.");
|
|
if(!string_adaptor::empty(attributes[SC::extension_element_prefixes]))
|
|
throw SAX::SAXException("Haven't implemented extension-element-prefixes yet");
|
|
} // startStylesheet
|
|
|
|
void startLREAsStylesheet(const string_type& namespaceURI,
|
|
const string_type& localName,
|
|
const string_type& qName,
|
|
const AttributesT& atts)
|
|
{
|
|
string_type version;
|
|
for(int a = 0; a != atts.getLength(); ++a)
|
|
if((SC::NamespaceURI == atts.getURI(a)) &&
|
|
(SC::version == atts.getLocalName(a)))
|
|
{
|
|
version = atts.getValue(a);
|
|
break;
|
|
}
|
|
|
|
if(string_adaptor::empty(version))
|
|
throw SAX::SAXException("The source file does not look like a stylesheet.");
|
|
if(version != SC::Version)
|
|
throw SAX::SAXException("I'm only a poor version 1.0 XSLT Transformer.");
|
|
|
|
Template<string_type, string_adaptor>* lreStylesheet =
|
|
new Template<string_type, string_adaptor>(context_.xpath_match(SC::root_xpath),
|
|
string_adaptor::empty_string(),
|
|
string_adaptor::empty_string(),
|
|
string_adaptor::empty_string(),
|
|
context_.precedence());
|
|
context_.push(lreStylesheet,
|
|
new LREStylesheetHandler<string_type, string_adaptor>(context_, lreStylesheet),
|
|
namespaceURI,
|
|
localName,
|
|
qName,
|
|
atts);
|
|
} // startLREAsStylesheet
|
|
|
|
void startXSLTElement(const string_type& namespaceURI,
|
|
const string_type& localName,
|
|
const string_type& qName,
|
|
const AttributesT& atts)
|
|
{
|
|
if((localName == SC::import) || (localName == SC::include))
|
|
{
|
|
include_stylesheet(namespaceURI, localName, qName, atts);
|
|
return;
|
|
} // if ...
|
|
|
|
SAX::DefaultHandler<string_type, string_adaptor>* child = allowedChildren().create(localName, context_);
|
|
|
|
if(child != 0)
|
|
context_.push(0, child, namespaceURI, localName, qName, atts);
|
|
else
|
|
oops(qName);
|
|
} // startXSLTElement
|
|
|
|
void startForeignElement(const string_type& namespaceURI,
|
|
const string_type& localName,
|
|
const string_type& qName,
|
|
const AttributesT& atts)
|
|
{
|
|
context_.push(0,
|
|
new ForeignElementHandler<string_type, string_adaptor>(context_),
|
|
namespaceURI,
|
|
localName,
|
|
qName,
|
|
atts);
|
|
} // startForeignElement
|
|
|
|
void include_stylesheet(const string_type& namespaceURI,
|
|
const string_type& localName,
|
|
const string_type& qName,
|
|
const AttributesT& atts)
|
|
{
|
|
includer_.start_include(namespaceURI, localName, qName, atts);
|
|
} // include_stylesheet
|
|
|
|
void oops(const string_type& qName) const
|
|
{
|
|
throw SAX::SAXException("xsl:stylesheet does not allow " + string_adaptor::asStdString(qName) + " here.");
|
|
} // oops
|
|
|
|
ChildElements<string_type, string_adaptor>& allowedChildren()
|
|
{
|
|
static ChildElements<string_type, string_adaptor> allowed =
|
|
ChildElements<string_type, string_adaptor>::add(SC::template_, CreateHandler<TemplateHandler<string_type, string_adaptor> > )
|
|
.add(SC::param, CreateHandler<TopLevelVariableHandler<Param<string_type, string_adaptor> > >)
|
|
.add(SC::variable, CreateHandler<TopLevelVariableHandler<Variable<string_type, string_adaptor> > > )
|
|
.add(SC::output, CreateHandler<OutputHandler<string_type, string_adaptor> >)
|
|
.add(SC::attribute_set, CreateHandler<NotImplementedYetHandler<string_type, string_adaptor> >)
|
|
.add(SC::decimal_format, CreateHandler<NotImplementedYetHandler<string_type, string_adaptor> >)
|
|
//"import"
|
|
//"include"
|
|
.add(SC::key, CreateHandler<KeyHandler<string_type, string_adaptor> >)
|
|
.add(SC::namespace_alias, CreateHandler<NamespaceAliasHandler<string_type, string_adaptor> >)
|
|
.add(SC::preserve_space, CreateHandler<NotImplementedYetHandler<string_type, string_adaptor> >)
|
|
.add(SC::strip_space, CreateHandler<NotImplementedYetHandler<string_type, string_adaptor> >);
|
|
|
|
return allowed;
|
|
} // allowedChildren
|
|
|
|
|
|
CompilationContextT& context_;
|
|
DefaultHandlerT* child_;
|
|
IncludeHandler<string_type, string_adaptor> includer_;
|
|
bool top_;
|
|
}; // class StylesheetHandler
|
|
|
|
template<class string_type, class string_adaptor = Arabica::default_string_adaptor<string_type> >
|
|
class StylesheetCompiler
|
|
{
|
|
public:
|
|
typedef string_type string_typeT;
|
|
typedef string_adaptor string_adaptorT;
|
|
typedef SAX::InputSource<string_type, string_adaptor> InputSourceT;
|
|
|
|
StylesheetCompiler()
|
|
{
|
|
} // StylesheetCompiler
|
|
|
|
~StylesheetCompiler()
|
|
{
|
|
} // ~StylesheetCompiler
|
|
|
|
std::auto_ptr<Stylesheet<string_type, string_adaptor> > compile(InputSourceT& source)
|
|
{
|
|
error_ = "";
|
|
|
|
std::auto_ptr<CompiledStylesheet<string_type, string_adaptor> > stylesheet(new CompiledStylesheet<string_type, string_adaptor>());
|
|
|
|
StylesheetParser<string_type, string_adaptor> parser;
|
|
CompilationContext<string_type, string_adaptor> context(parser, *stylesheet.get());
|
|
|
|
StylesheetHandler<string_type, string_adaptor> stylesheetHandler(context);
|
|
parser.setContentHandler(stylesheetHandler);
|
|
//parser.setErrorHandler(*this);
|
|
|
|
//if(entityResolver_)
|
|
// parser.setEntityResolver(*entityResolver_);
|
|
try {
|
|
parser.parse(source);
|
|
} // try
|
|
catch(std::exception& ex)
|
|
{
|
|
error_ = ex.what();
|
|
//std::cerr << "Compilation Failed : " << ex.what() << std::endl;
|
|
stylesheet.reset();
|
|
} // catch
|
|
|
|
return std::auto_ptr<Stylesheet<string_type, string_adaptor> >(stylesheet.release());
|
|
} // compile
|
|
|
|
const std::string& error() const
|
|
{
|
|
return error_;
|
|
} // error
|
|
|
|
private:
|
|
std::string error_;
|
|
}; // class StylesheetCompiler
|
|
|
|
} // namespace XSLT
|
|
} // namespace Arabica
|
|
|
|
#endif // ARABICA_XSLT_STYLESHEETCOMPILER_HPP
|
|
|