XSLTemplate is a simple XSLT based templating system that was created in order to use XSLT for WSGI web applications. The goal is to have a simple means of using XSLT for templating as well as provide an obvious and simple way of extending template via traditional XSLT extension functions and elements.
As it is based on 4Suite, all the 4Suite documentation can be used as a basis for creating extensions. Also, XSLTemplates comes with some basic extensions specific to web applications.
Basic Usage
To use XSLTemplates insert the middleware into your WSGI stack.
from xsltemplates import TemplateMiddlware
app_conf = {'template_directory', 'templates'}
app = YourApplication()
app = TemplateMiddleware(app_conf, app)
Then from within your application you can specify the template you want to use. The result from the output is the source of the transform.
from xsltempltes import set_template
class MyApp(object):
def __call__(self, environ, start_response):
# sets the template in the environ dict with the key 'xsltemplate.template'
set_template(environ, 'index.xslt')
xml = """<?xml version="1.0"?>
<page><content>hello world</content></page>"""
start_response('200 OK', [('content-type', 'text/html')])
return [xml]
The result of the transformation will be the output.
Parameters
You can send parameters to the stylesheet as well by adding them to the 'xsltemplate.params' dict in the environment or using the 'set_params' function. For example,
from xsltemplates import set_params, set_template
def some_wsgi_app(environ, start_response):
set_template(environ 'index.xslt')
params = {'message' : 'Hello World!'}
set_params(environ, params)
xml = """<?xml version="1.0"?>
<page><content>hello world</content></page>"""
start_response('200 OK', [('content-type', 'text/html')])
return [xml]
To use the "message" parameter in the stylesheet use the xsltemplates namespace.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:p="http://ionrock.org/ns/xsltemplate"
xmlns="http://www.w3.org/1999/xhtml">
<xsl:param name="p:message />
<xsl:template match="/">
<html><head><title>Hi</title></head>
<body>
<h1><xsl:value-of select="$p:message" /></h1>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
You can also pass in node-sets via a list of Domlette objects (Ft.Xml.Domlette). XSLTemplates provides a very simple node_set function for making this tranformation, although it is very minimal.
from Ft.Xml import Parse
def node_set(xml):
return Parse(xml)For more information please visit the 4Suite documentation on possible issues.
Extension Functions/Elements
XSLT supports extension elements and functions which allow you to extend the functionality of the processor as needed. The best example is that of the Exslt (http://exslt.org) libraries which define essential functions such as exslt:node-set() and exslt:func. 4Suite has excellent support of the Exslt libraries as well a good number of its own libraries.
To add your own extensions simply create a module and include a list of tuples as a keyed parameter in the TemplateMiddleware constructor.
# sample module
from Ft.Xml.XPath import Conversions
def say_hello(context, name):
name = Conversions.StringValue(name)
return "Hello %s" % name
# tuple (namespace, function/extension name, function/calleable)
extensions = [
(u'http://ionrock.org/ns/xsltemplate', u'say-hello', say_hello),
]
# in constructor
from my.sample.module import extensions
app = TemplateMiddleware(app_conf, app, extensions=extensions)
Then in the stylesheet you can use the function/element.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:p="http://ionrock.org/ns/xsltemplate"
xmlns="http://www.w3.org/1999/xhtml">
<xsl:template match="/">
<html><head><title>Hi</title></head>
<body>
<h1>
<xsl:value-of select="p:say-hello('Eric')" />
</h1>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Importing and Including
XSLTemplates has a custom resolver that it used when it loads an XSLT. The custom resolver simply looks for a "local:" prefix, which gets expanded to the template directory. This way you can include and import other stylesheets from your template directory.
To use the resolver, just prefix the relative path with "local:" in your xsl:include or xsl:import elements:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:p="http://ionrock.org/ns/xsltemplate"
xmlns="http://www.w3.org/1999/xhtml">
<xsl:include href="local:utils/form_templates.xslt" />
<xsl:template match="/">
<html><head><title>Hi</title></head>
<body>
<h1>Email Us!</h1>
<form action="." method="post">
<!-- this call-template is in "utils/form_templates.xslt" -->
<xsl:call-template name="utils-email-form">
<xsl:with-param name="default-email">Enter Email Address</xsl:with-param>
<xsl:with-param name="default-content">Your message</xsl:with-param>
</xsl:call-template>
</form>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
The in the template directory a file "utils/form_templates.xslt" might look like this:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:p="http://ionrock.org/ns/xsltemplate"
xmlns="http://www.w3.org/1999/xhtml">
<xsl:template name="utils-email-form">
<xsl:param name="default-email" />
<xsl:param name="default-content"><xsl:text> </xsl:text></xsl:param>
<label for="email-address">Email</label>
<input type="text" name="email-address" value="$default-email" />
<label for="email-content">Message</label>
<textarea rows="10" cols="40" name="email-content">
<xsl:value-of select="$default-content" />
</textarea>
</xsl:template>
</xsl:stylesheet>The custom resolver will revert to the normal 4Suite resolution if the "local:" is not used.
Using Python Eggs
XSLTemplates can use python eggs for specifying the source of the template, source file or for inclusion/importing in templates. Here is an example using stylesheet contained in an egg.
from xsltemplates import set_template
def hello(environ, start_response):
set_template(environ, 'pkg://myegg.somemodule#path/to/the/file.xslt')
start_response('200 OK', [('content-type', 'text/html')])
return ['<?xml version="1.0"?><page />']
And including a file from an egg is very similar.
<xsl:include href="pkg://myegg.somemodule#path/to/file.xslt" />
Default Index File
Sometimes you primarily want a stylesheet to simply be a template that receives values to be fill in. For these cases, XSLTemplates lets you provide a simple default bit of XML.
from xsltemplates import TemplateMiddleware
conf = {'use_index_xml': '<?xml version="1.0"?><page />'}
app = MyWSGIApp()
app = TemplateMiddleware(conf, app)
If there is an empty response, it will fill it in with '<?xml version="1.0"?><page />'. Likewise there is also IndexXMLMiddleware that allows the same functionality.
from xsltemplates import TemplateMiddleware, IndexXMLMiddleware
conf = {'index_xml': '/path/to/index.xml'}
app = MyWSGIApp()
app = IndexXMLMiddleware(conf, app}
app = TemplateMiddleware(conf, app)
This allows you to configure the use of an actual file or string.
Template Constants
Often times you will want to have a consistent set of values available as parameters in the stylesheet. XSLTemplates provides a TemplateConstants middleware that adds these to the parameters passed to the stylesheet.
from xsltemplate import TemplateMiddleware, TemplateConstants
app = MyWSGIApp()
app = TemplateConstants({'base-url': 'http://example.com/blog/'}, app)
app = TemplateMiddleware({}, app)
By default, the TemplateConstants middleware will include the environ dictionary as parameters. To turn this off, set the use_environ keyword parameter to False.
app = TemplateConstants(constants, app, use_environ=False)
Output Content Type
There are two ways for setting the Content-Type in the response. One way is to set the Content-Type header explicitly in the application:
def my_app(environ, start_response):
f = open('about.xml', 'r')
set_template(environ, 'homepage.xslt')
headers = [('Content-Type', 'text/html')]
start_response('200 OK', headers)
return f
The other way to set the media type is by using the media-type attribute on the xsl:output element:
<xsl:output type="html" indent="yes" media-type="text/html" />
This latter method is somewhat preferred depending on your usage.