arabica/include/XSLT/impl/xslt_stylesheet_compiler.hpp

272 lines
9.8 KiB
C++
Raw Normal View History

#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"
2010-05-19 21:22:22 +02:00
#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>
{
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;
2012-11-09 20:17:13 +01:00
if(namespaceURI == StylesheetConstant<string_type, string_adaptor>::NamespaceURI())
startStylesheet(namespaceURI, localName, qName, atts);
else
startLREAsStylesheet(namespaceURI, localName, qName, atts);
return;
} // if(top_)
2012-11-09 20:17:13 +01:00
if(namespaceURI == StylesheetConstant<string_type, string_adaptor>::NamespaceURI())
startXSLTElement(namespaceURI, localName, qName, atts);
else if(!namespaceURI.empty())
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)
{
2012-11-09 20:17:13 +01:00
verifyNoCharacterData<string_type>(ch, "xsl:stylesheet/xsl:transform");
} // 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 != "stylesheet" && localName != "transform")
throw SAX::SAXException("Top-level element must be 'stylesheet' or 'transform'.");
static const ValueRule rules[] = { { "version", true, 0, 0 },
{ "extension-element-prefixes", false, 0, 0 },
{ "exclude-result-prefixes", false, 0, 0 },
{ "id", false, 0, 0 },
{ 0, false, 0, 0 } };
std::map<string_type, string_type> attributes = gatherAttributes(qName, atts, rules);
2012-11-09 20:17:13 +01:00
if(attributes["version"] != StylesheetConstant<string_type, string_adaptor>::Version())
throw SAX::SAXException("I'm only a poor version 1.0 XSLT Transformer.");
if(!attributes["extension-element-prefixes"].empty())
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)
2012-11-09 20:17:13 +01:00
if((StylesheetConstant<string_type, string_adaptor>::NamespaceURI() == atts.getURI(a)) &&
("version" == atts.getLocalName(a)))
{
version = atts.getValue(a);
break;
}
if(version.empty())
throw SAX::SAXException("The source file does not look like a stylesheet.");
2012-11-09 20:17:13 +01:00
if(version != StylesheetConstant<string_type, string_adaptor>::Version())
throw SAX::SAXException("I'm only a poor version 1.0 XSLT Transformer.");
2012-11-06 08:50:57 +01:00
Template<string_type, string_adaptor>* lreStylesheet = new Template<string_type, string_adaptor>(context_.xpath_match("/"), "", "", "", context_.precedence());
context_.push(lreStylesheet,
2012-11-04 18:22:47 +01:00
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 == "import") || (localName == "include"))
{
include_stylesheet(namespaceURI, localName, qName, atts);
return;
} // if ...
2012-11-04 23:34:40 +01:00
for(const ChildElement<string_type, string_adaptor>* c = allowedChildren; c->name != 0; ++c)
if(c->name == localName)
{
context_.push(0,
c->createHandler(context_),
namespaceURI,
localName,
qName,
atts);
return;
} // if ...
oops(qName);
} // startXSLTElement
void startForeignElement(const string_type& namespaceURI,
const string_type& localName,
const string_type& qName,
const AttributesT& atts)
{
context_.push(0,
2012-11-09 20:17:13 +01:00
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 " + qName + " here.");
} // oops
CompilationContextT& context_;
DefaultHandlerT* child_;
IncludeHandler includer_;
bool top_;
2012-11-04 23:34:40 +01:00
static const ChildElement<string_type, string_adaptor> allowedChildren[];
}; // class StylesheetHandler
template<class string_type, class string_adaptor>
2012-11-04 23:34:40 +01:00
const ChildElement<string_type, string_adaptor> StylesheetHandler<string_type, string_adaptor>::allowedChildren[] =
{
2012-11-04 23:34:40 +01:00
{ "attribute-set", CreateHandler<NotImplementedYetHandler<string_type, string_adaptor> >},
{ "decimal-format", CreateHandler<NotImplementedYetHandler<string_type, string_adaptor> >},
//"import"
//"include"
2012-11-06 20:02:31 +01:00
{ "key", CreateHandler<KeyHandler<string_type, string_adaptor> >},
2012-11-06 20:05:52 +01:00
{ "namespace-alias", CreateHandler<NamespaceAliasHandler<string_type, string_adaptor> >},
2012-11-06 20:09:20 +01:00
{ "output", CreateHandler<OutputHandler<string_type, string_adaptor> >},
2012-11-06 09:29:42 +01:00
{ "param", CreateHandler<TopLevelVariableHandler<Param<string_type, string_adaptor> > >},
2012-11-04 23:34:40 +01:00
{ "preserve-space", CreateHandler<NotImplementedYetHandler<string_type, string_adaptor> >},
{ "strip-space", CreateHandler<NotImplementedYetHandler<string_type, string_adaptor> >},
2012-11-06 08:50:57 +01:00
{ "template", CreateHandler<TemplateHandler<string_type, string_adaptor> > },
2012-11-04 23:34:40 +01:00
{ "variable", CreateHandler<TopLevelVariableHandler<Variable<string_type, string_adaptor> > > },
{ 0, 0 }
}; // StylesheetHandler::allowedChildren
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
2012-11-06 21:03:15 +01:00
std::auto_ptr<Stylesheet<string_type, string_adaptor> > compile(InputSourceT& source)
{
error_ = "";
2012-11-06 21:03:15 +01:00
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
2012-11-06 21:03:15 +01:00
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