KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > util > XSLTransformer


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.util;
11
12 import java.io.*;
13 import java.util.*;
14 import java.net.URL JavaDoc;
15
16 import javax.xml.transform.*;
17 import javax.xml.parsers.*;
18 import javax.xml.transform.stream.StreamResult JavaDoc;
19 import javax.xml.transform.stream.StreamSource JavaDoc;
20 import javax.xml.transform.dom.DOMSource JavaDoc;
21
22 import org.mmbase.bridge.*;
23 import org.mmbase.bridge.util.xml.Generator;
24
25
26 import org.mmbase.cache.xslt.*;
27
28 import org.mmbase.util.xml.URIResolver;
29 import org.mmbase.util.logging.Logger;
30 import org.mmbase.util.logging.Logging;
31
32
33 /**
34  * Make XSL Transformations
35  *
36  * @core (?) Not specific to MMBase, but used by build files for generation of documentation.
37  * @move org.mmbase.util.xml
38  * @author Case Roole, cjr@dds.nl
39  * @author Michiel Meeuwissen
40  * @version $Id: XSLTransformer.java,v 1.31 2005/08/16 15:22:08 michiel Exp $
41  */

42 public class XSLTransformer {
43     private static final Logger log = Logging.getLoggerInstance(XSLTransformer.class);
44     /**
45      * Empty constructor
46      * @deprecated All methods are static.
47      */

48     public XSLTransformer() {}
49
50     /**
51      * Transform an XML document using a certain XSL document.
52      *
53      * @param xmlPath Path to XML file
54      * @param xslPath Path to XSL file
55      * @return String with converted XML document
56      */

57     public static String JavaDoc transform(String JavaDoc xmlPath, String JavaDoc xslPath) {
58         return transform(xmlPath, xslPath, false);
59     }
60
61     /**
62      * Transform an XML document using a certain XSL document, on
63      * MMBase specic way (error handling, entitity resolving, uri
64      * resolving, logging), and write it to string, which optionally can be
65      * 'cut'.
66      *
67      * @param xmlPath Path to XML file
68      * @param xslPath Path to XSL file
69      * @param cutXML if <code>true</code>, cuts the &lt;?xml&gt; line that normally starts an
70      * xml document
71      * @return String with converted XML document
72      *
73      *
74      */

75     public static String JavaDoc transform(String JavaDoc xmlPath, String JavaDoc xslPath, boolean cutXML) {
76         try {
77             StringWriter res = new StringWriter();
78             transform(new File(xmlPath), new File(xslPath), new StreamResult JavaDoc(res), null, true);
79             String JavaDoc s = res.toString();
80             int n = s.indexOf("\n");
81             if (cutXML && s.length() > n) {
82                 s = s.substring(n + 1);
83             }
84             return s;
85         } catch (Exception JavaDoc e) {
86             log.error(e.getMessage());
87             log.error(Logging.stackTrace(e));
88             return "Error during XSLT tranformation: "+e.getMessage();
89         }
90     }
91
92     /**
93      * This is the base function which calls the actual XSL
94      * transformations. Performs XSL transformation on MMBase specific
95      * way (using MMBase cache, and URIResolver).
96      * @javadoc
97      *
98      * @since MMBase-1.6
99      */

100     public static void transform(Source JavaDoc xml, File xslFile, Result JavaDoc result, Map params) throws TransformerException {
101         transform(xml, xslFile, result, params, true);
102     }
103
104     /**
105      * This is the base function which calls the actual XSL
106      * transformations. Performs XSL transformation on MMBase specific
107      * way (using MMBase cache, and URIResolver).
108      * @param xml The source XML
109      * @param xslFile The XSL which must be used for the transformation
110      * @param result The XSL out will be written to this
111      * @param params <code>null</code> or a Map to XSL transformations parameters
112      * @param considerDir If <code>true</code>, an URIResolver will be instantiated which can resolve entities relative to the XSL file.
113      *
114      * @since MMBase-1.6
115      */

116     public static void transform(Source JavaDoc xml, File xslFile, Result JavaDoc result, Map params, boolean considerDir) throws TransformerException {
117         try {
118             transform(xml, xslFile.toURL(), result, params, considerDir);
119         } catch (java.net.MalformedURLException JavaDoc mfe) {
120             throw new TransformerException(mfe.getMessage(), mfe);
121         }
122     }
123
124     /**
125      * @since MMBase-1.8
126      */

127     public static void transform(Source JavaDoc xml, URL JavaDoc xslFile, Result JavaDoc result, Map params) throws TransformerException {
128         transform(xml, xslFile, result, params, true);
129     }
130
131     /**
132      * @since MMBase-1.8
133      */

134     public static void transform(Source JavaDoc xml, URL JavaDoc xslFile, Result JavaDoc result, Map params, boolean considerDir) throws TransformerException {
135         TemplateCache cache= TemplateCache.getCache();
136         Source JavaDoc xsl;
137         try {
138             xsl = new StreamSource JavaDoc(xslFile.openStream());
139         } catch (IOException ioe) {
140             throw new TransformerException(ioe.getMessage(), ioe);
141         }
142         try {
143             xsl.setSystemId(xslFile.toString());
144         } catch (Exception JavaDoc e) {
145         }
146         URIResolver uri;
147         if (considerDir) {
148             try {
149                 uri = new URIResolver(new URL JavaDoc(xslFile, "."));
150             } catch (java.net.MalformedURLException JavaDoc mfe) {
151                 // oddd..
152
throw new TransformerException(mfe.getMessage(), mfe);
153             }
154         } else {
155             uri = new URIResolver();
156         }
157         Templates cachedXslt = cache.getTemplates(xsl, uri);
158         if (log.isDebugEnabled()) {
159             // log.debug("Size of cached XSLT " + SizeOf.getByteSize(cachedXslt) + " bytes");
160
log.debug("Size of URIResolver " + SizeOf.getByteSize(uri) + " bytes");
161             log.debug("template cache sze " + cache.size() + " entries");
162         }
163         if (cachedXslt == null) {
164             TransformerFactory tf = FactoryCache.getCache().getFactory(uri);
165             cachedXslt = tf.newTemplates(xsl);
166             cache.put(xsl, cachedXslt, uri);
167         } else {
168             if (log.isDebugEnabled()) log.debug("Used xslt from cache with " + xsl.getSystemId());
169         }
170         Transformer transformer = cachedXslt.newTransformer();
171         //Transformer transformer = TransformerFactory.newInstance().newTransformer();
172
if (log.isDebugEnabled()) {
173             log.debug("Size of transformer " + SizeOf.getByteSize(transformer) + " bytes");
174         }
175         if (params != null) {
176             Iterator i = params.entrySet().iterator();
177             while (i.hasNext()){
178                 Map.Entry entry = (Map.Entry) i.next();
179                 if (log.isDebugEnabled()) log.debug("setting param " + entry.getKey() + " to " + entry.getValue());
180                 transformer.setParameter((String JavaDoc) entry.getKey(), entry.getValue());
181             }
182         }
183         transformer.transform(xml, result);
184     }
185
186     /**
187      * Perfoms XSL Transformation on XML-file which is parsed MMBase
188      * specificly (useing MMBasse EntityResolver and Errorhandler).
189      * @javadoc
190      *
191      * @since MMBase-1.6
192      */

193     public static void transform(File xmlFile, File xslFile, Result JavaDoc result, Map params, boolean considerDir) throws TransformerException, ParserConfigurationException, java.io.IOException JavaDoc, org.xml.sax.SAXException JavaDoc {
194         // create the input xml.
195
DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
196
197         // turn validating on
198
XMLEntityResolver resolver = new XMLEntityResolver(true);
199         dfactory.setNamespaceAware(true);
200         DocumentBuilder db = dfactory.newDocumentBuilder();
201
202         XMLErrorHandler handler = new XMLErrorHandler();
203         db.setErrorHandler(handler);
204         db.setEntityResolver(resolver);
205         org.w3c.dom.Document JavaDoc xmlDoc = db.parse(xmlFile);
206         Source JavaDoc s = new DOMSource JavaDoc(xmlDoc);
207         s.setSystemId(xmlFile.toURL().toString());
208         transform(s, xslFile, result, params, considerDir);
209     }
210
211
212     /**
213      * Can be used to transform a directory of XML-files. Of course the result must be written to files too.
214      *
215      * The transformations will be called with a paramter "root" which
216      * points back to the root directory relatively. You need this
217      * when all your transformations results (probably html's) need to
218      * refer to the same file which is relative to the root of the transformation.
219      * @javadoc
220      *
221      * @since MMBase-1.6
222      */

223     public static void transform(File xmlDir, File xslFile, File resultDir, boolean recurse, Map params, boolean considerDir) throws TransformerException, ParserConfigurationException, java.io.IOException JavaDoc, org.xml.sax.SAXException JavaDoc {
224         if (! xmlDir.isDirectory()) {
225             throw new TransformerException("" + xmlDir + " is not a directory");
226         }
227         if (! resultDir.exists()) {
228             resultDir.mkdir();
229         }
230         if (! resultDir.isDirectory()) {
231             throw new TransformerException("" + resultDir + " is not a directory");
232         }
233         if (params == null) params = new HashMap();
234
235         List exclude = (List) params.get("exclude");
236
237         File[] files = xmlDir.listFiles();
238         for (int i = 0; i < files.length; i++) {
239             if (exclude.contains(files[i].getName())) continue;
240
241             if (recurse && files[i].isDirectory()) {
242                 if ("CVS".equals(files[i].getName())) continue;
243                 File resultSubDir = new File(resultDir, files[i].getName());
244                 Map myParams;
245                 if (params == null) {
246                     myParams = new HashMap();
247                 } else {
248                     myParams = new HashMap(params);
249                 }
250
251                 if (myParams.get("root") == null) {
252                     myParams.put("root", "../");
253                 } else {
254                     if ("./".equals(myParams.get("root"))) {
255                         myParams.put("root", "../");
256                     } else {
257                         myParams.put("root", myParams.get("root") + "../");
258                     }
259                 }
260                 log.info("Transforming directory " + files[i] + " (root is " + myParams.get("root") + ")");
261                 transform(files[i], xslFile, resultSubDir, recurse, myParams, considerDir);
262             } else {
263                 if (! files[i].getName().endsWith(".xml")) continue;
264                 String JavaDoc fileName = files[i].getName();
265                 fileName = fileName.substring(0, fileName.length() - 4);
266                 params.put("filename", fileName);
267                 String JavaDoc extension = (String JavaDoc) params.get("extension");
268                 if (extension == null) extension = "html";
269                 File resultFile = new File(resultDir, fileName + "." + extension);
270                 if (resultFile.lastModified() > files[i].lastModified()) {
271                     log.info("Not transforming " + files[i] + " because " + resultFile + " is up to date");
272                 } else {
273                     log.info("Transforming file " + files[i] + " to " + resultFile);
274                     try {
275                         Result JavaDoc res;
276                         if ("true".equals(params.get("dontopenfile"))) {
277                             res = new StreamResult JavaDoc(System.out);
278                         } else {
279                             res = new StreamResult JavaDoc(resultFile);
280                         }
281                         transform(files[i], xslFile, res, params, considerDir);
282                     } catch (Exception JavaDoc e) {
283                         log.error(e.toString());
284                         log.error(Logging.stackTrace(e));
285                     }
286                 }
287             }
288         }
289     }
290
291
292     public static Result JavaDoc getResult(String JavaDoc[] argv) throws Exception JavaDoc {
293         if (argv.length > 2) {
294             FileOutputStream stream = new FileOutputStream(argv[2]);
295             Writer f = new OutputStreamWriter(stream,"utf-8");
296             return new StreamResult JavaDoc(f);
297         } else {
298             return new StreamResult JavaDoc(new OutputStreamWriter(System.out, "utf-8"));
299         }
300     }
301
302
303     /**
304      * Invocation of the class from the commandline for testing/building
305      */

306     public static void main(String JavaDoc[] argv) {
307
308         // log.setLevel(org.mmbase.util.logging.Level.DEBUG);
309
if (argv.length < 2) {
310             log.info("Use with two arguments: <xslt-file>|SER <xml-inputfile|node-number> [xml-outputfile]");
311             log.info("Use with tree arguments: xslt-file xml-inputdir xml-outputdir [key=value options]");
312             log.info("special options can be:");
313             log.info(" usecache=true: Use the Template cache or not (to speed up)");
314             log.info(" exclude=<filename>: File/directory name to exclude (can be used multiple times");
315             log.info(" extension=<file extensions>: File extensions to use in transformation results (defaults to html)");
316
317             log.info("Other options are passed to XSL-stylesheet as parameters.");
318
319         } else {
320             Map params = new HashMap();
321             if (argv.length > 3) {
322                 for (int i = 3; i<argv.length; i++) {
323                     String JavaDoc key = argv[i];
324                     String JavaDoc value = "";
325                     int p = key.indexOf("=");
326                     if (p > 0) {
327                         if (p<key.length()-1) value = key.substring(p+1);
328                         key = key.substring(0, p);
329                     }
330                     if (key.equals("usecache")) {
331                         TemplateCache.getCache().setActive(value.equals("true"));
332                     } else if (key.equals("exclude")) {
333                         if (params.get("exclude") == null) {
334                             params.put("exclude", new ArrayList());
335                         }
336                         List excludes = (List) params.get("exclude");
337                         excludes.add(value);
338                     } else {
339                         params.put(key, value);
340                     }
341                 }
342             }
343             try {
344                 File in = new File(argv[1]);
345                 if (in.exists()) {
346                     if (in.isDirectory()) {
347                         log.info("Transforming directory " + in);
348                         long start = System.currentTimeMillis();
349                         try {
350                             transform(in, new File(argv[0]), new File(argv[2]), true, params, true);
351                         } catch (Exception JavaDoc e) {
352                             log.error("Error: " + e.toString());
353                         }
354                         log.info("Transforming took " + (System.currentTimeMillis() - start) / 1000.0 + " seconds");
355                     } else {
356                         log.info("Transforming file " + argv[1]);
357                         transform(new File(argv[1]), new File(argv[0]), getResult(argv), params, true);
358                     }
359                 } else {
360                     log.debug("" + in + " does not exist, interpreting it as a node, connecting using RMMCI");
361                     Result JavaDoc result = getResult(argv);
362                     String JavaDoc nodeNumber = argv[1];
363                     CloudContext cc = ContextProvider.getDefaultCloudContext();
364                     Cloud cloud = cc.getCloud("mmbase", "anonymous", null);
365                     params.put("cloud", cloud);
366                     Node node = cloud.getNode(nodeNumber);
367                     DocumentBuilder documentBuilder = org.mmbase.util.xml.DocumentReader.getDocumentBuilder();
368                     Generator generator = new Generator(documentBuilder, cloud);
369                     generator.setNamespaceAware(true);
370                     generator.add(node, node.getNodeManager().getField("body"));
371                     //generator.add(node);
372
//log.info("" + node.getXMLValue("body").getDocumentElement().getNamespaceURI());
373
generator.add(node.getRelations("idrel"));
374                     NodeList relatedNodes = node.getRelatedNodes("object", "idrel", "both");
375                     generator.add(relatedNodes);
376                     log.debug("transforming");
377                     transform(new DOMSource JavaDoc(generator.getDocument()), new File(argv[0]), result, params, true);
378                 }
379             } catch (Exception JavaDoc ex) {
380                 log.error(ex.getMessage(), ex);
381                 Throwable JavaDoc cause = ex.getCause();
382                 while (cause != null) {
383                     log.error("CAUSE" + cause.getMessage(), cause);
384                     cause = cause.getCause();
385                 }
386             }
387         }
388     }
389 }
390
Popular Tags