| 1 | # -*- coding: utf-8 -*- |
---|
| 2 | # |
---|
| 3 | # Copyright (C) 2005-2007 Christopher Lenz <cmlenz@gmx.de> |
---|
| 4 | # Copyright (C) 2007-2010 Edgewall Software |
---|
| 5 | # All rights reserved. |
---|
| 6 | # |
---|
| 7 | # This software is licensed as described in the file COPYING, which |
---|
| 8 | # you should have received as part of this distribution. The terms |
---|
| 9 | # are also available at http://bitten.edgewall.org/wiki/License. |
---|
| 10 | |
---|
1 | 11 | """Recipe commands for XML processing.""" |
---|
| 12 | |
---|
1 | 13 | import logging |
---|
1 | 14 | import os |
---|
| 15 | |
---|
1 | 16 | try: |
---|
1 | 17 | import libxml2 |
---|
1 | 18 | import libxslt |
---|
1 | 19 | have_libxslt = True |
---|
0 | 20 | except ImportError: |
---|
0 | 21 | have_libxslt = False |
---|
| 22 | |
---|
1 | 23 | if not have_libxslt and os.name == 'nt': |
---|
0 | 24 | try: |
---|
0 | 25 | import win32com.client |
---|
0 | 26 | have_msxml = True |
---|
0 | 27 | except ImportError: |
---|
0 | 28 | have_msxml = False |
---|
0 | 29 | else: |
---|
1 | 30 | have_msxml = False |
---|
| 31 | |
---|
1 | 32 | log = logging.getLogger('bitten.build.xmltools') |
---|
| 33 | |
---|
1 | 34 | __docformat__ = 'restructuredtext en' |
---|
| 35 | |
---|
1 | 36 | def transform(ctxt, src=None, dest=None, stylesheet=None): |
---|
| 37 | """Apply an XSLT stylesheet to a source XML document. |
---|
| 38 | |
---|
| 39 | This command requires either libxslt (with Python bindings), or MSXML to |
---|
| 40 | be installed. |
---|
| 41 | |
---|
| 42 | :param ctxt: the build context |
---|
| 43 | :type ctxt: `Context` |
---|
| 44 | :param src: name of the XML input file |
---|
| 45 | :param dest: name of the XML output file |
---|
| 46 | :param stylesheet: name of the file containing the XSLT stylesheet |
---|
| 47 | """ |
---|
4 | 48 | assert src, 'Missing required attribute "src"' |
---|
3 | 49 | assert dest, 'Missing required attribute "dest"' |
---|
2 | 50 | assert stylesheet, 'Missing required attribute "stylesheet"' |
---|
| 51 | |
---|
1 | 52 | if have_libxslt: |
---|
1 | 53 | log.debug('Using libxslt for XSLT transformation') |
---|
1 | 54 | srcdoc, styledoc, result = None, None, None |
---|
1 | 55 | try: |
---|
1 | 56 | srcdoc = libxml2.parseFile(ctxt.resolve(src)) |
---|
1 | 57 | styledoc = libxslt.parseStylesheetFile(ctxt.resolve(stylesheet)) |
---|
1 | 58 | result = styledoc.applyStylesheet(srcdoc, None) |
---|
1 | 59 | styledoc.saveResultToFilename(ctxt.resolve(dest), result, 0) |
---|
1 | 60 | finally: |
---|
1 | 61 | if styledoc: |
---|
1 | 62 | styledoc.freeStylesheet() |
---|
1 | 63 | if srcdoc: |
---|
1 | 64 | srcdoc.freeDoc() |
---|
1 | 65 | if result: |
---|
1 | 66 | result.freeDoc() |
---|
| 67 | |
---|
0 | 68 | elif have_msxml: |
---|
0 | 69 | log.debug('Using MSXML for XSLT transformation') |
---|
0 | 70 | srcdoc = win32com.client.Dispatch('MSXML2.DOMDocument.3.0') |
---|
0 | 71 | if not srcdoc.load(ctxt.resolve(src)): |
---|
0 | 72 | err = srcdoc.parseError |
---|
0 | 73 | ctxt.error('Failed to parse XML source %s: %s' % (src, err.reason)) |
---|
0 | 74 | return |
---|
0 | 75 | styledoc = win32com.client.Dispatch('MSXML2.DOMDocument.3.0') |
---|
0 | 76 | if not styledoc.load(ctxt.resolve(stylesheet)): |
---|
0 | 77 | err = styledoc.parseError |
---|
0 | 78 | ctxt.error('Failed to parse XSLT stylesheet %s: %s' % |
---|
0 | 79 | (stylesheet, err.reason)) |
---|
0 | 80 | return |
---|
0 | 81 | result = srcdoc.transformNode(styledoc) |
---|
| 82 | |
---|
| 83 | # MSXML seems to always write produce the resulting XML document using |
---|
| 84 | # UTF-16 encoding, regardless of the encoding specified in the |
---|
| 85 | # stylesheet. For better interoperability, recode to UTF-8 here. |
---|
0 | 86 | result = result.encode('utf-8').replace(' encoding="UTF-16"?>', '?>') |
---|
| 87 | |
---|
0 | 88 | dest_file = file(ctxt.resolve(dest), 'w') |
---|
0 | 89 | try: |
---|
0 | 90 | dest_file.write(result) |
---|
0 | 91 | finally: |
---|
0 | 92 | dest_file.close() |
---|
| 93 | |
---|
0 | 94 | else: |
---|
0 | 95 | ctxt.error('No usable XSLT implementation found') |
---|
| 96 | |
---|
| 97 | # TODO: as a last resort, try to invoke 'xsltproc' to do the |
---|
| 98 | # transformation? |
---|