arabica/include/XSLT/impl/xslt_stylesheet_compiler.hpp

237 lines
6.9 KiB
C++
Raw Normal View History

2007-07-19 19:01:42 +02:00
#ifndef ARABICA_XSLT_STYLESHEETCONSTANT_HPP
#define ARABICA_XSLT_STYLESHEETCONSTANT_HPP
2007-09-05 00:55:47 +02:00
#include <XML/XMLCharacterClasses.hpp>
2007-08-23 15:55:06 +02:00
#include <XPath/impl/xpath_namespace_context.hpp>
2007-07-19 19:01:42 +02:00
#include <memory>
#include "xslt_stylesheet_parser.hpp"
2007-07-19 19:01:42 +02:00
#include "xslt_stylesheet.hpp"
#include "xslt_compilation_context.hpp"
#include "xslt_functions.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"
namespace Arabica
{
namespace XSLT
{
class StylesheetHandler : public SAX::DefaultHandler
{
public:
StylesheetHandler(CompilationContext& context) :
context_(context),
2007-08-23 15:55:06 +02:00
top_(true),
foreign_(0)
2007-07-19 19:01:42 +02:00
{
context_.root(*this);
includer_.context(context_, this);
} // StylesheetHandler
virtual void startElement(const std::string& namespaceURI,
const std::string& localName,
const std::string& qName,
const SAX::Attributes& atts)
{
if(top_)
{
if(namespaceURI != StylesheetConstant::NamespaceURI())
throw SAX::SAXException("The source file does not look like a stylesheet.");
if(localName != "stylesheet" && localName != "transform")
throw SAX::SAXException("Top-level element must be 'stylesheet' or 'transform'.");
if(atts.getValue("version") == "")
throw SAX::SAXException("stylesheet element must have a version attribute.");
if(atts.getValue("version") != StylesheetConstant::Version())
throw SAX::SAXException("I'm only a poor version 1.0 XSLT Transformer.");
top_ = false;
return;
} // if(stylesheet_ == 0)
2007-08-23 15:55:06 +02:00
if(namespaceURI != StylesheetConstant::NamespaceURI())
2007-07-19 19:01:42 +02:00
{
2007-08-23 15:55:06 +02:00
++foreign_;
return;
} //
2007-07-19 19:01:42 +02:00
2007-08-23 15:55:06 +02:00
if((localName == "import") || (localName == "include"))
{
include_stylesheet(namespaceURI, localName, qName, atts);
return;
2007-07-19 19:01:42 +02:00
} // if ...
2007-08-23 15:55:06 +02:00
for(const ChildElement* c = allowedChildren; c->name != 0; ++c)
if(c->name == localName)
{
context_.push(0,
c->createHandler(context_),
namespaceURI,
qName,
localName,
atts);
return;
} // if ...
2007-07-19 19:01:42 +02:00
} // startElement
virtual void endElement(const std::string& namespaceURI,
const std::string& localName,
const std::string& qName)
{
2007-08-23 15:55:06 +02:00
if(namespaceURI != StylesheetConstant::NamespaceURI())
--foreign_;
2007-07-19 19:01:42 +02:00
} // endElement
virtual void characters(const std::string& ch)
{
2007-08-23 15:55:06 +02:00
if(foreign_)
return;
2007-07-19 19:01:42 +02:00
for(std::string::const_iterator s = ch.begin(), e = ch.end(); s != e; ++s)
if(!Arabica::XML::is_space(*s))
2007-08-23 15:55:06 +02:00
throw SAX::SAXException("stylesheet element can not contain character data :'" + ch +"'");
2007-07-19 19:01:42 +02:00
} // characters
virtual void endDocument()
{
includer_.unwind_imports();
context_.stylesheet().prepare();
} // endDocument
private:
void include_stylesheet(const std::string& namespaceURI,
const std::string& localName,
const std::string& qName,
const SAX::Attributes& atts)
{
includer_.start_include(namespaceURI, localName, qName, atts);
} // include_stylesheet
CompilationContext& context_;
SAX::DefaultHandler* child_;
IncludeHandler includer_;
bool top_;
2007-08-23 15:55:06 +02:00
unsigned int foreign_;
2007-07-19 19:01:42 +02:00
static const ChildElement allowedChildren[];
}; // class StylesheetHandler
const ChildElement StylesheetHandler::allowedChildren[] =
{
{ "attribute-set", CreateHandler<NotImplementedYetHandler>},
{ "decimal-format", CreateHandler<NotImplementedYetHandler>},
//"import"
//"include"
{ "key", CreateHandler<NotImplementedYetHandler>},
{ "namespace-alias", CreateHandler<NamespaceAliasHandler>},
{ "output", CreateHandler<OutputHandler>},
{ "param", CreateHandler<TopLevelVariableHandler<Param> >},
{ "preserve-space", CreateHandler<NotImplementedYetHandler>},
{ "strip-space", CreateHandler<NotImplementedYetHandler>},
{ "template", CreateHandler<TemplateHandler> },
{ "variable", CreateHandler<TopLevelVariableHandler<Variable> > },
{ 0, 0 }
}; // StylesheetHandler::allowedChildren
2007-08-23 15:55:06 +02:00
class StylesheetCompiler :
private Arabica::XPath::FunctionResolver<std::string>,
private Arabica::XPath::NamespaceContext<std::string, Arabica::default_string_adaptor<std::string> >
2007-07-19 19:01:42 +02:00
{
public:
2007-08-23 15:55:06 +02:00
StylesheetCompiler()
2007-07-19 19:01:42 +02:00
{
} // StylesheetCompiler
~StylesheetCompiler()
{
} // ~StylesheetCompiler
std::auto_ptr<Stylesheet> compile(SAX::InputSource& source)
{
error_ = "";
Arabica::XPath::XPath<std::string> xpathCompiler;
2007-08-23 15:55:06 +02:00
xpathCompiler.setNamespaceContext(*this);
xpathCompiler.setFunctionResolver(*this);
2007-07-19 19:01:42 +02:00
2007-08-23 15:55:06 +02:00
std::auto_ptr<Stylesheet> stylesheet(new Stylesheet());
CompilationContext context(parser_,
2007-07-19 19:01:42 +02:00
xpathCompiler,
2007-08-23 15:55:06 +02:00
*stylesheet.get());
2007-07-19 19:01:42 +02:00
StylesheetHandler stylesheetHandler(context);
2007-08-23 15:55:06 +02:00
parser_.setContentHandler(stylesheetHandler);
//parser_.setErrorHandler(*this);
2007-07-19 19:01:42 +02:00
//if(entityResolver_)
2007-08-23 15:55:06 +02:00
// parser_.setEntityResolver(*entityResolver_);
2007-07-19 19:01:42 +02:00
try {
2007-08-23 15:55:06 +02:00
parser_.parse(source);
2007-07-19 19:01:42 +02:00
} // try
catch(std::exception& ex)
{
error_ = ex.what();
//std::cerr << "Compilation Failed : " << ex.what() << std::endl;
2007-08-23 15:55:06 +02:00
stylesheet.reset();
2007-07-19 19:01:42 +02:00
} // catch
2007-08-23 15:55:06 +02:00
return stylesheet;
2007-07-19 19:01:42 +02:00
} // compile
const std::string& error() const
{
return error_;
} // error
private:
virtual void fatalError(const SAX::SAXException& exception)
{
std::cerr << "Error: " << exception.what() << std::endl;
stylesheet_.reset();
} // fatalError
2007-08-23 15:55:06 +02:00
// FunctionResolver
virtual Arabica::XPath::XPathFunction<std::string>* resolveFunction(
const std::string& namespace_uri,
const std::string& name,
const std::vector<Arabica::XPath::XPathExpressionPtr<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")
return new CurrentFunction(argExprs);
// unparsed-entity-uri
// generate-id
if(name == "system-property")
return new SystemPropertyFunction(argExprs);
return 0;
} // resolveFunction
// NamespaceContext
virtual std::string namespaceURI(const std::string& prefix) const
{
return parser_.namespaceURI(prefix);
} // namespaceURI
StylesheetParser parser_;
2007-07-19 19:01:42 +02:00
std::auto_ptr<Stylesheet> stylesheet_;
std::string error_;
}; // class StylesheetCompiler
} // namespace XSLT
} // namespace Arabica
#endif // ARABICA_XSLT_STYLESHEETCOMPILER_HPP