source: products/quintagroup.transmogrifier/trunk/quintagroup/transmogrifier/xslt.py @ 277

Last change on this file since 277 was 277, checked in by mylan, 18 years ago

Fix publishing bug

File size: 4.5 KB
Line 
1try:
2    import libxml2
3    import libxslt
4except ImportError:
5    HAS_LIBS = False
6else:
7    HAS_LIBS = True
8
9from zope.interface import classProvides, implements, Interface
10from zope.configuration.fields import Path
11from zope.schema import TextLine
12
13from collective.transmogrifier.interfaces import ISectionBlueprint
14from collective.transmogrifier.interfaces import ISection
15from collective.transmogrifier.utils import defaultMatcher
16
17class StylesheetRegistry(object):
18    def __init__(self):
19        self.clear()
20
21    def clear(self):
22        self._stylesheet_info = {}
23
24    def registerStylesheet(self, source, from_, to, file):
25        name = "%s:%s" % (from_, to)
26        if source in self._stylesheet_info:
27            if name in self._stylesheet_info[source]:
28                raise KeyError('Duplicate stylesheet registration: %s %s %s' % 
29                    (source, from_, to))
30        source = self._stylesheet_info.setdefault(source, {})
31        source[name] = {
32            'from_': from_,
33            'to': to,
34            'file': file
35        }
36
37    def getStylesheet(self, source, from_, to):
38        name = "%s:%s" % (from_, to)
39        try:
40            return self._stylesheet_info[source][name]
41        except KeyError:
42            return None
43
44    def listStylesheetNames(self):
45        names = []
46        for k, v in self._stylesheet_info.items():
47            for name in v.keys():
48                names.append("%s:%s" % (k, name))
49        return tuple(names)
50
51stylesheet_registry = StylesheetRegistry()
52
53# Test cleanup support
54from zope.testing.cleanup import addCleanUp
55addCleanUp(stylesheet_registry.clear)
56del addCleanUp
57
58class IStylesheetDirective(Interface):
59    """ Register XSLT file with the global registry.
60    """
61
62    source = TextLine(
63        title=u"Source",
64        description=u"The source of XML data.",
65        required=True
66        )
67
68    from_ = TextLine(
69        title=u"From",
70        description=u"Value which describes XML data before transformation.",
71        required=True
72        )
73
74    to = TextLine(
75        title=u"To",
76        description=u"Value which describes XML data after transformation.",
77        required=True
78        )
79
80    file = Path(
81        title=u"XSLT file",
82        description=u"The XSLT file to register.",
83        required=True
84        )
85
86
87def stylesheet(_context, source, from_, to, file):
88    """Add a new stylesheet to the registry"""
89
90    _context.action(
91        discriminator=('stylesheet', source, from_, to),
92        callable=stylesheet_registry.registerStylesheet,
93        args=(source, from_, to, file))
94
95
96class XSLTSection(object):
97    classProvides(ISectionBlueprint)
98    implements(ISection)
99
100    def __init__(self, transmogrifier, name, options, previous):
101        self.fileskey = defaultMatcher(options, 'files-key', name, 'files')
102        self.source = options.get('source', 'marshall').strip()
103        self.fromkey = defaultMatcher(options, 'from-key', name, 'from')
104        self.tokey = defaultMatcher(options, 'to-key', name, 'to')
105
106        self.previous = previous
107
108    def __iter__(self):
109        source = self.source
110        for item in self.previous:
111            fileskey = self.fileskey(*item.keys())[0]
112            fromkey = self.fromkey(*item.keys())[0]
113            tokey = self.tokey(*item.keys())[0]
114
115            if not (fileskey and fromkey and tokey):
116                yield item; continue
117
118            if not (source in item[fileskey] and item[fileskey][source]):
119                yield item; continue
120
121            from_ = item[fromkey]
122            to = item[tokey]
123            stylesheet_info = stylesheet_registry.getStylesheet(source, from_, to)
124
125            if stylesheet_info is None:
126                yield item; continue
127
128            fp = open(stylesheet_info['file'], 'r')
129            stylesheet = fp.read()
130            fp.close()
131
132            source_dict = item[fileskey][source]
133            source_dict['data'] = self.applyTransformations(source_dict['data'], stylesheet)
134
135            yield item
136
137    def applyTransformations(self, xml, xslt):
138        if not HAS_LIBS:
139            return xml
140        # parse document
141        doc = libxml2.parseDoc(xml)
142        # parse stylesheet
143        styledoc = libxml2.parseDoc(xslt)
144        # make style object
145        style = libxslt.parseStylesheetDoc(styledoc)
146        # apply style to document
147        result = style.applyStylesheet(doc, None)
148        # write result to a file
149        transformed = style.saveResultToString(result)
150        # free all documents
151        style.freeStylesheet()
152        doc.freeDoc()
153        result.freeDoc()
154        return transformed
Note: See TracBrowser for help on using the repository browser.