KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > taskdefs > XSLTProcess


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */

18
19 package org.apache.tools.ant.taskdefs;
20
21 import java.io.File JavaDoc;
22 import java.util.Enumeration JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.Vector JavaDoc;
25 import org.apache.tools.ant.AntClassLoader;
26 import org.apache.tools.ant.BuildException;
27 import org.apache.tools.ant.DirectoryScanner;
28 import org.apache.tools.ant.DynamicConfigurator;
29 import org.apache.tools.ant.Project;
30 import org.apache.tools.ant.types.Mapper;
31 import org.apache.tools.ant.types.Path;
32 import org.apache.tools.ant.types.Reference;
33 import org.apache.tools.ant.types.Resource;
34 import org.apache.tools.ant.types.ResourceCollection;
35 import org.apache.tools.ant.types.XMLCatalog;
36 import org.apache.tools.ant.types.resources.FileResource;
37 import org.apache.tools.ant.types.resources.Resources;
38 import org.apache.tools.ant.types.resources.Union;
39 import org.apache.tools.ant.util.FileNameMapper;
40 import org.apache.tools.ant.util.FileUtils;
41
42 /**
43  * Processes a set of XML documents via XSLT. This is
44  * useful for building views of XML based documentation.
45  *
46  *
47  * @since Ant 1.1
48  *
49  * @ant.task name="xslt" category="xml"
50  */

51
52 public class XSLTProcess extends MatchingTask implements XSLTLogger {
53     /** destination directory */
54     private File JavaDoc destDir = null;
55
56     /** where to find the source XML file, default is the project's basedir */
57     private File JavaDoc baseDir = null;
58
59     /** XSL stylesheet as a filename */
60     private String JavaDoc xslFile = null;
61
62     /** XSL stylesheet as a {@link org.apache.tools.ant.types.Resource} */
63     private Resource xslResource = null;
64
65     /** extension of the files produced by XSL processing */
66     private String JavaDoc targetExtension = ".html";
67
68     /** name for XSL parameter containing the filename */
69     private String JavaDoc fileNameParameter = null;
70
71     /** name for XSL parameter containing the file directory */
72     private String JavaDoc fileDirParameter = null;
73
74     /** additional parameters to be passed to the stylesheets */
75     private Vector JavaDoc params = new Vector JavaDoc();
76
77     /** Input XML document to be used */
78     private File JavaDoc inFile = null;
79
80     /** Output file */
81     private File JavaDoc outFile = null;
82
83     /** The name of the XSL processor to use */
84     private String JavaDoc processor;
85
86     /** Classpath to use when trying to load the XSL processor */
87     private Path classpath = null;
88
89     /** The Liason implementation to use to communicate with the XSL
90      * processor */

91     private XSLTLiaison liaison;
92
93     /** Flag which indicates if the stylesheet has been loaded into
94      * the processor */

95     private boolean stylesheetLoaded = false;
96
97     /** force output of target files even if they already exist */
98     private boolean force = false;
99
100     /** XSL output properties to be used */
101     private Vector JavaDoc outputProperties = new Vector JavaDoc();
102
103     /** for resolving entities such as dtds */
104     private XMLCatalog xmlCatalog = new XMLCatalog();
105
106     /** Name of the TRAX Liaison class */
107     private static final String JavaDoc TRAX_LIAISON_CLASS =
108                         "org.apache.tools.ant.taskdefs.optional.TraXLiaison";
109
110     /** Utilities used for file operations */
111     private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
112
113     /**
114      * Whether to style all files in the included directories as well.
115      *
116      * @since Ant 1.5
117      */

118     private boolean performDirectoryScan = true;
119
120     /**
121      * factory element for TraX processors only
122      * @since Ant 1.6
123      */

124     private Factory factory = null;
125
126     /**
127      * whether to reuse Transformer if transforming multiple files.
128      * @since 1.5.2
129      */

130     private boolean reuseLoadedStylesheet = true;
131
132     /**
133      * AntClassLoader for the nested <classpath> - if set.
134      *
135      * <p>We keep this here in order to reset the context classloader
136      * in execute. We can't use liaison.getClass().getClassLoader()
137      * since the actual liaison class may have been loaded by a loader
138      * higher up (system classloader, for example).</p>
139      *
140      * @since Ant 1.6.2
141      */

142     private AntClassLoader loader = null;
143
144     /**
145      * Mapper to use when a set of files gets processed.
146      *
147      * @since Ant 1.6.2
148      */

149     private Mapper mapperElement = null;
150
151     /**
152      * Additional resource collections to process.
153      *
154      * @since Ant 1.7
155      */

156     private Union resources = new Union();
157
158     /**
159      * Whether to use the implicit fileset.
160      *
161      * @since Ant 1.7
162      */

163     private boolean useImplicitFileset = true;
164
165     /**
166      * The default processor is trax
167      * @since Ant 1.7
168      */

169     public static final String JavaDoc PROCESSOR_TRAX = "trax";
170
171     /**
172      * Creates a new XSLTProcess Task.
173      */

174     public XSLTProcess() {
175     } //-- XSLTProcess
176

177     /**
178      * Whether to style all files in the included directories as well;
179      * optional, default is true.
180      *
181      * @param b true if files in included directories are processed.
182      * @since Ant 1.5
183      */

184     public void setScanIncludedDirectories(boolean b) {
185         performDirectoryScan = b;
186     }
187
188     /**
189      * Controls whether the stylesheet is reloaded for every transform.
190      *
191      * <p>Setting this to true may get around a bug in certain
192      * Xalan-J versions, default is false.</p>
193      * @param b a <code>boolean</code> value
194      * @since Ant 1.5.2
195      */

196     public void setReloadStylesheet(boolean b) {
197         reuseLoadedStylesheet = !b;
198     }
199
200     /**
201      * Defines the mapper to map source to destination files.
202      * @param mapper the mapper to use
203      * @exception BuildException if more than one mapper is defined
204      * @since Ant 1.6.2
205      */

206     public void addMapper(Mapper mapper) {
207         if (mapperElement != null) {
208             throw new BuildException("Cannot define more than one mapper",
209                                      getLocation());
210         }
211         mapperElement = mapper;
212     }
213
214     /**
215      * Adds a collection of resources to style in addition to the
216      * given file or the implicit fileset.
217      *
218      * @param rc the collection of resources to style
219      * @since Ant 1.7
220      */

221     public void add(ResourceCollection rc) {
222         resources.add(rc);
223     }
224
225     /**
226      * Add a nested &lt;style&gt; element.
227      * @param rc the configured Resources object represented as &lt;style&gt;.
228      * @since Ant 1.7
229      */

230     public void addConfiguredStyle(Resources rc) {
231         if (rc.size() != 1) {
232             throw new BuildException("The style element must be specified"
233                     + " with exactly one nested resource.");
234         }
235         setXslResource((Resource) rc.iterator().next());
236     }
237
238     /**
239      * API method to set the XSL Resource.
240      * @param xslResource Resource to set as the stylesheet.
241      * @since Ant 1.7
242      */

243     public void setXslResource(Resource xslResource) {
244         this.xslResource = xslResource;
245     }
246
247     /**
248      * Adds a nested filenamemapper.
249      * @param fileNameMapper the mapper to add
250      * @exception BuildException if more than one mapper is defined
251      * @since Ant 1.7.0
252      */

253     public void add(FileNameMapper fileNameMapper) throws BuildException {
254        Mapper mapper = new Mapper(getProject());
255        mapper.add(fileNameMapper);
256        addMapper(mapper);
257     }
258
259     /**
260      * Executes the task.
261      *
262      * @exception BuildException if there is an execution problem.
263      * @todo validate that if either in or our is defined, then both are
264      */

265     public void execute() throws BuildException {
266         if ("style".equals(getTaskType())) {
267             log("Warning: the task name <style> is deprecated. Use <xslt> instead.",
268                     Project.MSG_WARN);
269         }
270
271         File JavaDoc savedBaseDir = baseDir;
272
273         DirectoryScanner scanner;
274         String JavaDoc[] list;
275         String JavaDoc[] dirs;
276
277         if (xslResource == null && xslFile == null) {
278             throw new BuildException("specify the "
279                 + "stylesheet either as a filename in style "
280                 + "attribute or as a nested resource", getLocation());
281
282         }
283         if (xslResource != null && xslFile != null) {
284             throw new BuildException("specify the "
285                 + "stylesheet either as a filename in style "
286                 + "attribute or as a nested resource but not "
287                 + "as both", getLocation());
288         }
289
290         if (inFile != null && !inFile.exists()) {
291             throw new BuildException(
292                 "input file " + inFile.toString() + " does not exist", getLocation());
293         }
294
295         try {
296             if (baseDir == null) {
297                 baseDir = getProject().resolveFile(".");
298             }
299
300             liaison = getLiaison();
301
302             // check if liaison wants to log errors using us as logger
303
if (liaison instanceof XSLTLoggerAware) {
304                 ((XSLTLoggerAware) liaison).setLogger(this);
305             }
306
307             log("Using " + liaison.getClass().toString(), Project.MSG_VERBOSE);
308
309             if (xslFile != null) {
310                 // If we enter here, it means that the stylesheet is supplied
311
// via style attribute
312
File JavaDoc stylesheet = getProject().resolveFile(xslFile);
313                 if (!stylesheet.exists()) {
314                     stylesheet = FILE_UTILS.resolveFile(baseDir, xslFile);
315                     /*
316                      * shouldn't throw out deprecation warnings before we know,
317                      * the wrong version has been used.
318                      */

319                     if (stylesheet.exists()) {
320                         log("DEPRECATED - the 'style' attribute should be relative "
321                                 + "to the project's");
322                         log(" basedir, not the tasks's basedir.");
323                     }
324                 }
325                 FileResource fr = new FileResource();
326                 fr.setProject(getProject());
327                 fr.setFile(stylesheet);
328                 xslResource = fr;
329             }
330
331             // if we have an in file and out then process them
332
if (inFile != null && outFile != null) {
333                 process(inFile, outFile, xslResource);
334                 return;
335             }
336
337             /*
338              * if we get here, in and out have not been specified, we are
339              * in batch processing mode.
340              */

341
342             //-- make sure destination directory exists...
343
checkDest();
344
345             if (useImplicitFileset) {
346                 scanner = getDirectoryScanner(baseDir);
347                 log("Transforming into " + destDir, Project.MSG_INFO);
348
349                 // Process all the files marked for styling
350
list = scanner.getIncludedFiles();
351                 for (int i = 0; i < list.length; ++i) {
352                     process(baseDir, list[i], destDir, xslResource);
353                 }
354                 if (performDirectoryScan) {
355                     // Process all the directories marked for styling
356
dirs = scanner.getIncludedDirectories();
357                     for (int j = 0; j < dirs.length; ++j) {
358                         list = new File JavaDoc(baseDir, dirs[j]).list();
359                         for (int i = 0; i < list.length; ++i) {
360                             process(baseDir, dirs[j] + File.separator + list[i],
361                                     destDir, xslResource);
362                         }
363                     }
364                 }
365             } else { // only resource collections, there better be some
366
if (resources.size() == 0) {
367                     throw new BuildException("no resources specified");
368                 }
369             }
370             processResources(xslResource);
371         } finally {
372             if (loader != null) {
373                 loader.resetThreadContextLoader();
374                 loader.cleanup();
375                 loader = null;
376             }
377             liaison = null;
378             stylesheetLoaded = false;
379             baseDir = savedBaseDir;
380         }
381     }
382
383     /**
384      * Set whether to check dependencies, or always generate;
385      * optional, default is false.
386      *
387      * @param force true if always generate.
388      */

389     public void setForce(boolean force) {
390         this.force = force;
391     }
392
393     /**
394      * Set the base directory;
395      * optional, default is the project's basedir.
396      *
397      * @param dir the base directory
398      **/

399     public void setBasedir(File JavaDoc dir) {
400         baseDir = dir;
401     }
402
403     /**
404      * Set the destination directory into which the XSL result
405      * files should be copied to;
406      * required, unless <tt>in</tt> and <tt>out</tt> are
407      * specified.
408      * @param dir the name of the destination directory
409      **/

410     public void setDestdir(File JavaDoc dir) {
411         destDir = dir;
412     }
413
414     /**
415      * Set the desired file extension to be used for the target;
416      * optional, default is html.
417      * @param name the extension to use
418      **/

419     public void setExtension(String JavaDoc name) {
420         targetExtension = name;
421     }
422
423     /**
424      * Name of the stylesheet to use - given either relative
425      * to the project's basedir or as an absolute path; required.
426      *
427      * @param xslFile the stylesheet to use
428      */

429     public void setStyle(String JavaDoc xslFile) {
430         this.xslFile = xslFile;
431     }
432
433     /**
434      * Set the optional classpath to the XSL processor
435      *
436      * @param classpath the classpath to use when loading the XSL processor
437      */

438     public void setClasspath(Path classpath) {
439         createClasspath().append(classpath);
440     }
441
442     /**
443      * Set the optional classpath to the XSL processor
444      *
445      * @return a path instance to be configured by the Ant core.
446      */

447     public Path createClasspath() {
448         if (classpath == null) {
449             classpath = new Path(getProject());
450         }
451         return classpath.createPath();
452     }
453
454     /**
455      * Set the reference to an optional classpath to the XSL processor
456      *
457      * @param r the id of the Ant path instance to act as the classpath
458      * for loading the XSL processor
459      */

460     public void setClasspathRef(Reference r) {
461         createClasspath().setRefid(r);
462     }
463
464     /**
465      * Set the name of the XSL processor to use; optional, default trax.
466      * Other values are "xalan" for Xalan1
467      *
468      * @param processor the name of the XSL processor
469      */

470     public void setProcessor(String JavaDoc processor) {
471         this.processor = processor;
472     }
473
474     /**
475      * Whether to use the implicit fileset.
476      *
477      * <p>Set this to false if you want explicit control with nested
478      * resource collections.</p>
479      * @param useimplicitfileset set to true if you want to use implicit fileset
480      * @since Ant 1.7
481      */

482     public void setUseImplicitFileset(boolean useimplicitfileset) {
483         useImplicitFileset = useimplicitfileset;
484     }
485
486     /**
487      * Add the catalog to our internal catalog
488      *
489      * @param xmlCatalog the XMLCatalog instance to use to look up DTDs
490      */

491     public void addConfiguredXMLCatalog(XMLCatalog xmlCatalog) {
492         this.xmlCatalog.addConfiguredXMLCatalog(xmlCatalog);
493     }
494
495     /**
496      * Pass the filename of the current processed file as a xsl parameter
497      * to the transformation. This value sets the name of that xsl parameter.
498      *
499      * @param fileNameParameter name of the xsl parameter retrieving the
500      * current file name
501      */

502     public void setFileNameParameter(String JavaDoc fileNameParameter) {
503         this.fileNameParameter = fileNameParameter;
504     }
505
506     /**
507      * Pass the directory name of the current processed file as a xsl parameter
508      * to the transformation. This value sets the name of that xsl parameter.
509      *
510      * @param fileDirParameter name of the xsl parameter retrieving the
511      * current file directory
512      */

513     public void setFileDirParameter(String JavaDoc fileDirParameter) {
514         this.fileDirParameter = fileDirParameter;
515     }
516
517     /**
518      * Load processor here instead of in setProcessor - this will be
519      * called from within execute, so we have access to the latest
520      * classpath.
521      *
522      * @param proc the name of the processor to load.
523      * @exception Exception if the processor cannot be loaded.
524      */

525     private void resolveProcessor(String JavaDoc proc) throws Exception JavaDoc {
526         String JavaDoc classname;
527         if (proc.equals(PROCESSOR_TRAX)) {
528             classname = TRAX_LIAISON_CLASS;
529         } else {
530             //anything else is a classname
531
classname = proc;
532         }
533         Class JavaDoc clazz = loadClass(classname);
534         liaison = (XSLTLiaison) clazz.newInstance();
535     }
536
537     /**
538      * Load named class either via the system classloader or a given
539      * custom classloader.
540      *
541      * As a side effect, the loader is set as the thread context classloader
542      * @param classname the name of the class to load.
543      * @return the requested class.
544      * @exception Exception if the class could not be loaded.
545      */

546     private Class JavaDoc loadClass(String JavaDoc classname) throws Exception JavaDoc {
547         if (classpath == null) {
548             return Class.forName(classname);
549         } else {
550             loader = getProject().createClassLoader(classpath);
551             loader.setThreadContextLoader();
552             Class JavaDoc c = Class.forName(classname, true, loader);
553             return c;
554         }
555     }
556
557     /**
558      * Specifies the output name for the styled result from the
559      * <tt>in</tt> attribute; required if <tt>in</tt> is set
560      *
561      * @param outFile the output File instance.
562      */

563     public void setOut(File JavaDoc outFile) {
564         this.outFile = outFile;
565     }
566
567     /**
568      * specifies a single XML document to be styled. Should be used
569      * with the <tt>out</tt> attribute; ; required if <tt>out</tt> is set
570      *
571      * @param inFile the input file
572      */

573     public void setIn(File JavaDoc inFile) {
574         this.inFile = inFile;
575     }
576
577     /**
578      * Throws a BuildException if the destination directory hasn't
579      * been specified.
580      * @since Ant 1.7
581      */

582     private void checkDest() {
583         if (destDir == null) {
584             String JavaDoc msg = "destdir attributes must be set!";
585             throw new BuildException(msg);
586         }
587     }
588
589     /**
590      * Styles all existing resources.
591      *
592      * @since Ant 1.7
593      */

594     private void processResources(Resource stylesheet) {
595         Iterator JavaDoc iter = resources.iterator();
596         while (iter.hasNext()) {
597             Resource r = (Resource) iter.next();
598             if (!r.isExists()) {
599                 continue;
600             }
601             File JavaDoc base = baseDir;
602             String JavaDoc name = r.getName();
603             if (r instanceof FileResource) {
604                 FileResource f = (FileResource) r;
605                 base = f.getBaseDir();
606                 if (base == null) {
607                     name = f.getFile().getAbsolutePath();
608                 }
609             }
610             process(base, name, destDir, stylesheet);
611         }
612     }
613
614     /**
615      * Processes the given input XML file and stores the result
616      * in the given resultFile.
617      *
618      * @param baseDir the base directory for resolving files.
619      * @param xmlFile the input file
620      * @param destDir the destination directory
621      * @param stylesheet the stylesheet to use.
622      * @exception BuildException if the processing fails.
623      */

624     private void process(File JavaDoc baseDir, String JavaDoc xmlFile, File JavaDoc destDir,
625                          Resource stylesheet)
626         throws BuildException {
627
628         File JavaDoc outF = null;
629         File JavaDoc inF = null;
630
631         try {
632             long styleSheetLastModified = stylesheet.getLastModified();
633             inF = new File JavaDoc(baseDir, xmlFile);
634
635             if (inF.isDirectory()) {
636                 log("Skipping " + inF + " it is a directory.",
637                     Project.MSG_VERBOSE);
638                 return;
639             }
640
641             FileNameMapper mapper = null;
642             if (mapperElement != null) {
643                 mapper = mapperElement.getImplementation();
644             } else {
645                 mapper = new StyleMapper();
646             }
647
648             String JavaDoc[] outFileName = mapper.mapFileName(xmlFile);
649             if (outFileName == null || outFileName.length == 0) {
650                 log("Skipping " + inFile + " it cannot get mapped to output.",
651                     Project.MSG_VERBOSE);
652                 return;
653             } else if (outFileName == null || outFileName.length > 1) {
654                 log("Skipping " + inFile + " its mapping is ambiguos.",
655                     Project.MSG_VERBOSE);
656                 return;
657             }
658
659             outF = new File JavaDoc(destDir, outFileName[0]);
660
661             if (force
662                 || inF.lastModified() > outF.lastModified()
663                 || styleSheetLastModified > outF.lastModified()) {
664                 ensureDirectoryFor(outF);
665                 log("Processing " + inF + " to " + outF);
666
667                 configureLiaison(stylesheet);
668                 setLiaisonDynamicFileParameters(liaison, inF);
669                 liaison.transform(inF, outF);
670             }
671         } catch (Exception JavaDoc ex) {
672             // If failed to process document, must delete target document,
673
// or it will not attempt to process it the second time
674
log("Failed to process " + inFile, Project.MSG_INFO);
675             if (outF != null) {
676                 outF.delete();
677             }
678
679             throw new BuildException(ex);
680         }
681
682     } //-- processXML
683

684     /**
685      * Process the input file to the output file with the given stylesheet.
686      *
687      * @param inFile the input file to process.
688      * @param outFile the destination file.
689      * @param stylesheet the stylesheet to use.
690      * @exception BuildException if the processing fails.
691      */

692     private void process(File JavaDoc inFile, File JavaDoc outFile, Resource stylesheet)
693          throws BuildException {
694         try {
695             long styleSheetLastModified = stylesheet.getLastModified();
696             log("In file " + inFile + " time: " + inFile.lastModified(),
697                 Project.MSG_DEBUG);
698             log("Out file " + outFile + " time: " + outFile.lastModified(),
699                 Project.MSG_DEBUG);
700             log("Style file " + xslFile + " time: " + styleSheetLastModified,
701                 Project.MSG_DEBUG);
702             if (force || inFile.lastModified() >= outFile.lastModified()
703                 || styleSheetLastModified >= outFile.lastModified()) {
704                 ensureDirectoryFor(outFile);
705                 log("Processing " + inFile + " to " + outFile,
706                     Project.MSG_INFO);
707                 configureLiaison(stylesheet);
708                 setLiaisonDynamicFileParameters(liaison, inFile);
709                 liaison.transform(inFile, outFile);
710             } else {
711                 log("Skipping input file " + inFile
712                     + " because it is older than output file " + outFile
713                     + " and so is the stylesheet " + stylesheet, Project.MSG_DEBUG);
714             }
715         } catch (Exception JavaDoc ex) {
716             log("Failed to process " + inFile, Project.MSG_INFO);
717             if (outFile != null) {
718                 outFile.delete();
719             }
720             throw new BuildException(ex);
721         }
722     }
723
724     /**
725      * Ensure the directory exists for a given file
726      *
727      * @param targetFile the file for which the directories are required.
728      * @exception BuildException if the directories cannot be created.
729      */

730     private void ensureDirectoryFor(File JavaDoc targetFile)
731          throws BuildException {
732         File JavaDoc directory = targetFile.getParentFile();
733         if (!directory.exists()) {
734             if (!directory.mkdirs()) {
735                 throw new BuildException("Unable to create directory: "
736                                          + directory.getAbsolutePath());
737             }
738         }
739     }
740
741     /**
742      * Get the factory instance configured for this processor
743      *
744      * @return the factory instance in use
745      */

746     public Factory getFactory() {
747         return factory;
748     }
749
750     /**
751      * Get the XML catalog containing entity definitions
752      *
753      * @return the XML catalog for the task.
754      */

755     public XMLCatalog getXMLCatalog() {
756         xmlCatalog.setProject(getProject());
757         return xmlCatalog;
758     }
759
760     /**
761      * Get an enumeration on the outputproperties.
762      * @return the outputproperties
763      */

764     public Enumeration JavaDoc getOutputProperties() {
765         return outputProperties.elements();
766     }
767
768     /**
769      * Get the Liason implementation to use in processing.
770      *
771      * @return an instance of the XSLTLiason interface.
772      */

773     protected XSLTLiaison getLiaison() {
774         // if processor wasn't specified, see if TraX is available. If not,
775
// default it to xalan, depending on which is in the classpath
776
if (liaison == null) {
777             if (processor != null) {
778                 try {
779                     resolveProcessor(processor);
780                 } catch (Exception JavaDoc e) {
781                     throw new BuildException(e);
782                 }
783             } else {
784                 try {
785                     resolveProcessor(PROCESSOR_TRAX);
786                 } catch (Throwable JavaDoc e1) {
787                     e1.printStackTrace();
788                     throw new BuildException(e1);
789                 }
790             }
791         }
792         return liaison;
793     }
794
795     /**
796      * Create an instance of an XSL parameter for configuration by Ant.
797      *
798      * @return an instance of the Param class to be configured.
799      */

800     public Param createParam() {
801         Param p = new Param();
802         params.addElement(p);
803         return p;
804     }
805
806     /**
807      * The Param inner class used to store XSL parameters
808      */

809     public static class Param {
810         /** The parameter name */
811         private String JavaDoc name = null;
812
813         /** The parameter's value */
814         private String JavaDoc expression = null;
815
816         private String JavaDoc ifProperty;
817         private String JavaDoc unlessProperty;
818         private Project project;
819
820         /**
821          * Set the current project
822          *
823          * @param project the current project
824          */

825         public void setProject(Project project) {
826             this.project = project;
827         }
828
829         /**
830          * Set the parameter name.
831          *
832          * @param name the name of the parameter.
833          */

834         public void setName(String JavaDoc name) {
835             this.name = name;
836         }
837
838         /**
839          * The parameter value
840          * NOTE : was intended to be an XSL expression.
841          * @param expression the parameter's value.
842          */

843         public void setExpression(String JavaDoc expression) {
844             this.expression = expression;
845         }
846
847         /**
848          * Get the parameter name
849          *
850          * @return the parameter name
851          * @exception BuildException if the name is not set.
852          */

853         public String JavaDoc getName() throws BuildException {
854             if (name == null) {
855                 throw new BuildException("Name attribute is missing.");
856             }
857             return name;
858         }
859
860         /**
861          * Get the parameter's value
862          *
863          * @return the parameter value
864          * @exception BuildException if the value is not set.
865          */

866         public String JavaDoc getExpression() throws BuildException {
867             if (expression == null) {
868                 throw new BuildException("Expression attribute is missing.");
869             }
870             return expression;
871         }
872
873         /**
874          * Set whether this param should be used. It will be
875          * used if the property has been set, otherwise it won't.
876          * @param ifProperty name of property
877          */

878         public void setIf(String JavaDoc ifProperty) {
879             this.ifProperty = ifProperty;
880         }
881
882         /**
883          * Set whether this param should NOT be used. It
884          * will not be used if the property has been set, otherwise it
885          * will be used.
886          * @param unlessProperty name of property
887          */

888         public void setUnless(String JavaDoc unlessProperty) {
889             this.unlessProperty = unlessProperty;
890         }
891         /**
892          * Ensures that the param passes the conditions placed
893          * on it with <code>if</code> and <code>unless</code> properties.
894          * @return true if the task passes the "if" and "unless" parameters
895          */

896         public boolean shouldUse() {
897             if (ifProperty != null && project.getProperty(ifProperty) == null) {
898                 return false;
899             } else if (unlessProperty != null
900                     && project.getProperty(unlessProperty) != null) {
901                 return false;
902             }
903
904             return true;
905         }
906     } // Param
907

908
909     /**
910      * Create an instance of an output property to be configured.
911      * @return the newly created output property.
912      * @since Ant 1.5
913      */

914     public OutputProperty createOutputProperty() {
915         OutputProperty p = new OutputProperty();
916         outputProperties.addElement(p);
917         return p;
918     }
919
920
921     /**
922      * Specify how the result tree should be output as specified
923      * in the <a HREF="http://www.w3.org/TR/xslt#output">
924      * specification</a>.
925      * @since Ant 1.5
926      */

927     public static class OutputProperty {
928         /** output property name */
929         private String JavaDoc name;
930
931         /** output property value */
932         private String JavaDoc value;
933
934         /**
935          * @return the output property name.
936          */

937         public String JavaDoc getName() {
938             return name;
939         }
940
941         /**
942          * set the name for this property
943          * @param name A non-null String that specifies an
944          * output property name, which may be namespace qualified.
945          */

946         public void setName(String JavaDoc name) {
947             this.name = name;
948         }
949
950         /**
951          * @return the output property value.
952          */

953         public String JavaDoc getValue() {
954             return value;
955         }
956
957         /**
958          * set the value for this property
959          * @param value The non-null string value of the output property.
960          */

961         public void setValue(String JavaDoc value) {
962             this.value = value;
963         }
964     }
965
966     /**
967      * Initialize internal instance of XMLCatalog
968      * @throws BuildException on error
969      */

970     public void init() throws BuildException {
971         super.init();
972         xmlCatalog.setProject(getProject());
973     }
974
975     /**
976      * Loads the stylesheet and set xsl:param parameters.
977      *
978      * @param stylesheet the file from which to load the stylesheet.
979      * @exception BuildException if the stylesheet cannot be loaded.
980      * @deprecated since Ant 1.7
981      */

982     protected void configureLiaison(File JavaDoc stylesheet) throws BuildException {
983         FileResource fr = new FileResource();
984         fr.setProject(getProject());
985         fr.setFile(stylesheet);
986         configureLiaison(fr);
987     }
988     /**
989      * Loads the stylesheet and set xsl:param parameters.
990      *
991      * @param stylesheet the resource from which to load the stylesheet.
992      * @exception BuildException if the stylesheet cannot be loaded.
993      * @since Ant 1.7
994      */

995     protected void configureLiaison(Resource stylesheet) throws BuildException {
996         if (stylesheetLoaded && reuseLoadedStylesheet) {
997             return;
998         }
999         stylesheetLoaded = true;
1000
1001        try {
1002            log("Loading stylesheet " + stylesheet, Project.MSG_INFO);
1003            // We call liason.configure() and then liaison.setStylesheet()
1004
// so that the internal variables of liaison can be set up
1005
if (liaison instanceof XSLTLiaison2) {
1006                ((XSLTLiaison2) liaison).configure(this);
1007            }
1008
1009            if (liaison instanceof XSLTLiaison3) {
1010                // If we are here we can set the stylesheet as a
1011
// resource
1012
((XSLTLiaison3) liaison).setStylesheet(stylesheet);
1013            } else {
1014                // If we are here we cannot set the stylesheet as
1015
// a resource, but we can set it as a file. So,
1016
// we make an attempt to get it as a file
1017
if (stylesheet instanceof FileResource) {
1018                    liaison.setStylesheet(
1019                            ((FileResource) stylesheet).getFile());
1020                } else {
1021                    throw new BuildException(liaison.getClass().toString()
1022                            + " accepts the stylesheet only as a file",
1023                            getLocation());
1024                }
1025            }
1026            for (Enumeration JavaDoc e = params.elements(); e.hasMoreElements();) {
1027                Param p = (Param) e.nextElement();
1028                if (p.shouldUse()) {
1029                    liaison.addParam(p.getName(), p.getExpression());
1030                }
1031            }
1032        } catch (Exception JavaDoc ex) {
1033            log("Failed to transform using stylesheet " + stylesheet,
1034                 Project.MSG_INFO);
1035            throw new BuildException(ex);
1036        }
1037    }
1038
1039    /**
1040     * Sets file parameter(s) for directory and filename if the attribute
1041     * 'filenameparameter' or 'filedirparameter' are set in the task.
1042     *
1043     * @param liaison to change parameters for
1044     * @param inFile to get the additional file information from
1045     * @throws Exception if an exception occurs on filename lookup
1046     *
1047     * @since Ant 1.7
1048     */

1049    private void setLiaisonDynamicFileParameters(
1050        XSLTLiaison liaison,
1051        File JavaDoc inFile
1052    ) throws Exception JavaDoc {
1053        if (fileNameParameter != null) {
1054            liaison.addParam(fileNameParameter, inFile.getName());
1055        }
1056        if (fileDirParameter != null) {
1057            String JavaDoc fileName = FileUtils.getRelativePath(baseDir, inFile);
1058            File JavaDoc file = new File JavaDoc(fileName);
1059            // Give always a slash as file separator, so the stylesheet could be sure about that
1060
// Use '.' so a dir+"/"+name would not result in an absolute path
1061
liaison.addParam(
1062                fileDirParameter,
1063                (file.getParent() != null)
1064                ? file.getParent().replace('\\', '/') : ".");
1065        }
1066    }
1067
1068    /**
1069     * Create the factory element to configure a trax liaison.
1070     * @return the newly created factory element.
1071     * @throws BuildException if the element is created more than one time.
1072     */

1073    public Factory createFactory() throws BuildException {
1074        if (factory != null) {
1075            throw new BuildException("'factory' element must be unique");
1076        }
1077        factory = new Factory();
1078        return factory;
1079    }
1080
1081    /**
1082     * The factory element to configure a transformer factory
1083     * @since Ant 1.6
1084     */

1085    public static class Factory {
1086
1087        /** the factory class name to use for TraXLiaison */
1088        private String JavaDoc name;
1089
1090        /**
1091         * the list of factory attributes to use for TraXLiaison
1092         */

1093        private Vector JavaDoc attributes = new Vector JavaDoc();
1094
1095        /**
1096         * @return the name of the factory.
1097         */

1098        public String JavaDoc getName() {
1099            return name;
1100        }
1101
1102        /**
1103         * Set the name of the factory
1104         * @param name the name of the factory.
1105         */

1106        public void setName(String JavaDoc name) {
1107            this.name = name;
1108        }
1109
1110        /**
1111         * Create an instance of a factory attribute.
1112         * @param attr the newly created factory attribute
1113         */

1114        public void addAttribute(Attribute attr) {
1115            attributes.addElement(attr);
1116        }
1117
1118        /**
1119         * return the attribute elements.
1120         * @return the enumeration of attributes
1121         */

1122        public Enumeration JavaDoc getAttributes() {
1123            return attributes.elements();
1124        }
1125
1126        /**
1127         * A JAXP factory attribute. This is mostly processor specific, for
1128         * example for Xalan 2.3+, the following attributes could be set:
1129         * <ul>
1130         * <li>http://xml.apache.org/xalan/features/optimize (true|false) </li>
1131         * <li>http://xml.apache.org/xalan/features/incremental (true|false) </li>
1132         * </ul>
1133         */

1134        public static class Attribute implements DynamicConfigurator {
1135
1136            /** attribute name, mostly processor specific */
1137            private String JavaDoc name;
1138
1139            /** attribute value, often a boolean string */
1140            private Object JavaDoc value;
1141
1142            /**
1143             * @return the attribute name.
1144             */

1145            public String JavaDoc getName() {
1146                return name;
1147            }
1148
1149            /**
1150             * @return the output property value.
1151             */

1152            public Object JavaDoc getValue() {
1153                return value;
1154            }
1155
1156            /**
1157             * Not used.
1158             * @param name not used
1159             * @return null
1160             * @throws BuildException never
1161             */

1162            public Object JavaDoc createDynamicElement(String JavaDoc name) throws BuildException {
1163                return null;
1164            }
1165
1166            /**
1167             * Set an attribute.
1168             * Only "name" and "value" are supported as names.
1169             * @param name the name of the attribute
1170             * @param value the value of the attribute
1171             * @throws BuildException on error
1172             */

1173            public void setDynamicAttribute(String JavaDoc name, String JavaDoc value)
1174                    throws BuildException {
1175                // only 'name' and 'value' exist.
1176
if ("name".equalsIgnoreCase(name)) {
1177                    this.name = value;
1178                } else if ("value".equalsIgnoreCase(name)) {
1179                    // a value must be of a given type
1180
// say boolean|integer|string that are mostly used.
1181
if ("true".equalsIgnoreCase(value)) {
1182                        this.value = Boolean.TRUE;
1183                    } else if ("false".equalsIgnoreCase(value)) {
1184                        this.value = Boolean.FALSE;
1185                    } else {
1186                        try {
1187                            this.value = new Integer JavaDoc(value);
1188                        } catch (NumberFormatException JavaDoc e) {
1189                            this.value = value;
1190                        }
1191                    }
1192                } else {
1193                    throw new BuildException("Unsupported attribute: " + name);
1194                }
1195            }
1196        } // -- class Attribute
1197

1198    } // -- class Factory
1199

1200    /**
1201     * Mapper implementation of the "traditional" way &lt;xslt&gt;
1202     * mapped filenames.
1203     *
1204     * <p>If the file has an extension, chop it off. Append whatever
1205     * the user has specified as extension or ".html".</p>
1206     *
1207     * @since Ant 1.6.2
1208     */

1209    private class StyleMapper implements FileNameMapper {
1210        public void setFrom(String JavaDoc from) {
1211        }
1212        public void setTo(String JavaDoc to) {
1213        }
1214        public String JavaDoc[] mapFileName(String JavaDoc xmlFile) {
1215            int dotPos = xmlFile.lastIndexOf('.');
1216            if (dotPos > 0) {
1217                xmlFile = xmlFile.substring(0, dotPos);
1218            }
1219            return new String JavaDoc[] {xmlFile + targetExtension};
1220        }
1221    }
1222
1223}
1224
Popular Tags