1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
import os
from webob import Response
from zope.component import queryUtility
from zope.component import getSiteManager
from zope.deprecation import deprecated
from zope.interface import classProvides
from zope.interface import implements
from repoze.bfg.path import caller_path
from repoze.bfg.interfaces import INodeTemplateRenderer
from repoze.bfg.interfaces import IResponseFactory
from repoze.bfg.interfaces import ITemplateRendererFactory
def get_transform(path, node):
""" Return a callable transform object. When called, the
transform will return a string. The ``path`` argument should be a
package-relative path (also may be absolute) to an XSLT file.
When called, the transform will use the kwargs in ``*kw`` as top
level names and the lxml node at ``node``."""
# Render using XSLT
path = caller_path(path)
renderer = queryUtility(INodeTemplateRenderer, path)
if renderer is None:
if not os.path.exists(path):
raise ValueError('Missing template file: %s' % path)
renderer = XSLTemplateRenderer(path)
sm = getSiteManager()
sm.registerUtility(renderer, INodeTemplateRenderer, name=path)
return renderer
def render_transform(path, node, **kw):
""" Render a XSL template at the package-relative path (may also
be absolute) using the kwargs in ``*kw`` as top-level names and
the lxml node at ``node`` and return a string."""
path = caller_path(path)
template = get_transform(path, node)
return template(node, **kw)
def render_transform_to_response(path, node, **kw):
""" Render a XSL template at the package-relative path (may also
be absolute) using the kwargs in ``*kw`` as top-level names and
the lxml node at ``node`` and return a Response object."""
path = caller_path(path)
result = render_transform(path, node, **kw)
response_factory = queryUtility(IResponseFactory, default=Response)
return response_factory(result)
class XSLTemplateRenderer(object):
classProvides(ITemplateRendererFactory)
implements(INodeTemplateRenderer)
def __init__(self, path, auto_reload=False):
self.path = path
self.auto_reload = auto_reload
def __call__(self, node, **kw):
processor = get_processor(self.path, self.auto_reload)
result = str(processor(node, **kw))
return result
XSLTemplateFactory = XSLTemplateRenderer
deprecated('ZPTTemplateFactory',
('repoze.bfg.xslt.XSLTemplateFactory should now be '
'imported as repoze.bfg.xslt.XSLTTemplateRenderer'))
# Manage XSLT processors on a per-thread basis
import threading
from lxml import etree
xslt_pool = threading.local()
def get_processor(xslt_fn, auto_reload=False):
if not auto_reload:
try:
return xslt_pool.processors[xslt_fn]
except AttributeError:
xslt_pool.processors = {}
except KeyError:
pass
# Make a processor and add it to the pool
source = etree.ElementTree(file=xslt_fn)
proc = etree.XSLT(source)
xslt_pool.processors[xslt_fn] = proc
return proc
|