You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

XSLTProcess.java 58 kB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804
  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. package org.apache.tools.ant.taskdefs;
  19. import java.io.File;
  20. import java.util.ArrayList;
  21. import java.util.Collections;
  22. import java.util.EnumMap;
  23. import java.util.Enumeration;
  24. import java.util.List;
  25. import java.util.Map;
  26. import java.util.Vector;
  27. import javax.xml.namespace.QName;
  28. import javax.xml.xpath.XPath;
  29. import javax.xml.xpath.XPathConstants;
  30. import javax.xml.xpath.XPathExpression;
  31. import javax.xml.xpath.XPathExpressionException;
  32. import javax.xml.xpath.XPathFactory;
  33. import javax.xml.xpath.XPathVariableResolver;
  34. import org.apache.tools.ant.AntClassLoader;
  35. import org.apache.tools.ant.BuildException;
  36. import org.apache.tools.ant.DirectoryScanner;
  37. import org.apache.tools.ant.DynamicConfigurator;
  38. import org.apache.tools.ant.Project;
  39. import org.apache.tools.ant.ProjectComponent;
  40. import org.apache.tools.ant.PropertyHelper;
  41. import org.apache.tools.ant.taskdefs.optional.TraXLiaison;
  42. import org.apache.tools.ant.types.CommandlineJava;
  43. import org.apache.tools.ant.types.Environment;
  44. import org.apache.tools.ant.types.Mapper;
  45. import org.apache.tools.ant.types.Path;
  46. import org.apache.tools.ant.types.PropertySet;
  47. import org.apache.tools.ant.types.Reference;
  48. import org.apache.tools.ant.types.Resource;
  49. import org.apache.tools.ant.types.ResourceCollection;
  50. import org.apache.tools.ant.types.XMLCatalog;
  51. import org.apache.tools.ant.types.resources.FileProvider;
  52. import org.apache.tools.ant.types.resources.FileResource;
  53. import org.apache.tools.ant.types.resources.Resources;
  54. import org.apache.tools.ant.types.resources.Union;
  55. import org.apache.tools.ant.util.ClasspathUtils;
  56. import org.apache.tools.ant.util.FileNameMapper;
  57. import org.apache.tools.ant.util.FileUtils;
  58. import org.apache.tools.ant.util.ResourceUtils;
  59. import org.apache.tools.ant.util.StringUtils;
  60. /**
  61. * Processes a set of XML documents via XSLT. This is
  62. * useful for building views of XML based documentation.
  63. *
  64. *
  65. * @since Ant 1.1
  66. *
  67. * @ant.task name="xslt" category="xml"
  68. */
  69. public class XSLTProcess extends MatchingTask implements XSLTLogger {
  70. /** destination directory */
  71. private File destDir = null;
  72. /** where to find the source XML file, default is the project's basedir */
  73. private File baseDir = null;
  74. /** XSL stylesheet as a filename */
  75. private String xslFile = null;
  76. /** XSL stylesheet as a {@link org.apache.tools.ant.types.Resource} */
  77. private Resource xslResource = null;
  78. /** extension of the files produced by XSL processing */
  79. private String targetExtension = ".html";
  80. /** name for XSL parameter containing the filename */
  81. private String fileNameParameter = null;
  82. /** name for XSL parameter containing the file directory */
  83. private String fileDirParameter = null;
  84. /** additional parameters to be passed to the stylesheets */
  85. private final List<Param> params = new ArrayList<Param>();
  86. /** Input XML document to be used */
  87. private File inFile = null;
  88. /** Output file */
  89. private File outFile = null;
  90. /** The name of the XSL processor to use */
  91. private String processor;
  92. /** Classpath to use when trying to load the XSL processor */
  93. private Path classpath = null;
  94. /** The Liaison implementation to use to communicate with the XSL
  95. * processor */
  96. private XSLTLiaison liaison;
  97. /** Flag which indicates if the stylesheet has been loaded into
  98. * the processor */
  99. private boolean stylesheetLoaded = false;
  100. /** force output of target files even if they already exist */
  101. private boolean force = false;
  102. /** XSL output properties to be used */
  103. private final Vector outputProperties = new Vector();
  104. /** for resolving entities such as dtds */
  105. private final XMLCatalog xmlCatalog = new XMLCatalog();
  106. /** Utilities used for file operations */
  107. private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
  108. /**
  109. * Whether to style all files in the included directories as well.
  110. *
  111. * @since Ant 1.5
  112. */
  113. private boolean performDirectoryScan = true;
  114. /**
  115. * factory element for TraX processors only
  116. * @since Ant 1.6
  117. */
  118. private Factory factory = null;
  119. /**
  120. * whether to reuse Transformer if transforming multiple files.
  121. * @since 1.5.2
  122. */
  123. private boolean reuseLoadedStylesheet = true;
  124. /**
  125. * AntClassLoader for the nested &lt;classpath&gt; - if set.
  126. *
  127. * <p>We keep this here in order to reset the context classloader
  128. * in execute. We can't use liaison.getClass().getClassLoader()
  129. * since the actual liaison class may have been loaded by a loader
  130. * higher up (system classloader, for example).</p>
  131. *
  132. * @since Ant 1.6.2
  133. */
  134. private AntClassLoader loader = null;
  135. /**
  136. * Mapper to use when a set of files gets processed.
  137. *
  138. * @since Ant 1.6.2
  139. */
  140. private Mapper mapperElement = null;
  141. /**
  142. * Additional resource collections to process.
  143. *
  144. * @since Ant 1.7
  145. */
  146. private final Union resources = new Union();
  147. /**
  148. * Whether to use the implicit fileset.
  149. *
  150. * @since Ant 1.7
  151. */
  152. private boolean useImplicitFileset = true;
  153. /**
  154. * The default processor is trax
  155. * @since Ant 1.7
  156. */
  157. public static final String PROCESSOR_TRAX = "trax";
  158. /**
  159. * whether to suppress warnings.
  160. *
  161. * @since Ant 1.8.0
  162. */
  163. private boolean suppressWarnings = false;
  164. /**
  165. * whether to fail the build if an error occurs during transformation.
  166. *
  167. * @since Ant 1.8.0
  168. */
  169. private boolean failOnTransformationError = true;
  170. /**
  171. * whether to fail the build if an error occurs.
  172. *
  173. * @since Ant 1.8.0
  174. */
  175. private boolean failOnError = true;
  176. /**
  177. * Whether the build should fail if the nested resource collection
  178. * is empty.
  179. *
  180. * @since Ant 1.8.0
  181. */
  182. private boolean failOnNoResources = true;
  183. /**
  184. * For evaluating template params
  185. *
  186. * @since Ant 1.9.3
  187. */
  188. private XPathFactory xpathFactory;
  189. /**
  190. * For evaluating template params
  191. *
  192. * @since Ant 1.9.3
  193. */
  194. private XPath xpath;
  195. /**
  196. * System properties to set during transformation.
  197. *
  198. * @since Ant 1.8.0
  199. */
  200. private final CommandlineJava.SysProperties sysProperties =
  201. new CommandlineJava.SysProperties();
  202. /**
  203. * Trace configuration for Xalan2.
  204. *
  205. * @since Ant 1.8.0
  206. */
  207. private TraceConfiguration traceConfiguration;
  208. /**
  209. * Creates a new XSLTProcess Task.
  210. */
  211. public XSLTProcess() {
  212. } //-- XSLTProcess
  213. /**
  214. * Whether to style all files in the included directories as well;
  215. * optional, default is true.
  216. *
  217. * @param b true if files in included directories are processed.
  218. * @since Ant 1.5
  219. */
  220. public void setScanIncludedDirectories(final boolean b) {
  221. performDirectoryScan = b;
  222. }
  223. /**
  224. * Controls whether the stylesheet is reloaded for every transform.
  225. *
  226. * <p>Setting this to true may get around a bug in certain
  227. * Xalan-J versions, default is false.</p>
  228. * @param b a <code>boolean</code> value
  229. * @since Ant 1.5.2
  230. */
  231. public void setReloadStylesheet(final boolean b) {
  232. reuseLoadedStylesheet = !b;
  233. }
  234. /**
  235. * Defines the mapper to map source to destination files.
  236. * @param mapper the mapper to use
  237. * @exception BuildException if more than one mapper is defined
  238. * @since Ant 1.6.2
  239. */
  240. public void addMapper(final Mapper mapper) {
  241. if (mapperElement != null) {
  242. handleError("Cannot define more than one mapper");
  243. } else {
  244. mapperElement = mapper;
  245. }
  246. }
  247. /**
  248. * Adds a collection of resources to style in addition to the
  249. * given file or the implicit fileset.
  250. *
  251. * @param rc the collection of resources to style
  252. * @since Ant 1.7
  253. */
  254. public void add(final ResourceCollection rc) {
  255. resources.add(rc);
  256. }
  257. /**
  258. * Add a nested &lt;style&gt; element.
  259. * @param rc the configured Resources object represented as &lt;style&gt;.
  260. * @since Ant 1.7
  261. */
  262. public void addConfiguredStyle(final Resources rc) {
  263. if (rc.size() != 1) {
  264. handleError("The style element must be specified with exactly one"
  265. + " nested resource.");
  266. } else {
  267. setXslResource(rc.iterator().next());
  268. }
  269. }
  270. /**
  271. * API method to set the XSL Resource.
  272. * @param xslResource Resource to set as the stylesheet.
  273. * @since Ant 1.7
  274. */
  275. public void setXslResource(final Resource xslResource) {
  276. this.xslResource = xslResource;
  277. }
  278. /**
  279. * Adds a nested filenamemapper.
  280. * @param fileNameMapper the mapper to add
  281. * @exception BuildException if more than one mapper is defined
  282. * @since Ant 1.7.0
  283. */
  284. public void add(final FileNameMapper fileNameMapper) throws BuildException {
  285. final Mapper mapper = new Mapper(getProject());
  286. mapper.add(fileNameMapper);
  287. addMapper(mapper);
  288. }
  289. /**
  290. * Executes the task.
  291. *
  292. * @exception BuildException if there is an execution problem.
  293. * @todo validate that if either in or out is defined, then both are
  294. */
  295. @Override
  296. public void execute() throws BuildException {
  297. if ("style".equals(getTaskType())) {
  298. log("Warning: the task name <style> is deprecated. Use <xslt> instead.",
  299. Project.MSG_WARN);
  300. }
  301. final File savedBaseDir = baseDir;
  302. DirectoryScanner scanner;
  303. String[] list;
  304. String[] dirs;
  305. final String baseMessage =
  306. "specify the stylesheet either as a filename in style attribute "
  307. + "or as a nested resource";
  308. if (xslResource == null && xslFile == null) {
  309. handleError(baseMessage);
  310. return;
  311. }
  312. if (xslResource != null && xslFile != null) {
  313. handleError(baseMessage + " but not as both");
  314. return;
  315. }
  316. if (inFile != null && !inFile.exists()) {
  317. handleError("input file " + inFile + " does not exist");
  318. return;
  319. }
  320. try {
  321. setupLoader();
  322. if (sysProperties.size() > 0) {
  323. sysProperties.setSystem();
  324. }
  325. Resource styleResource;
  326. if (baseDir == null) {
  327. baseDir = getProject().getBaseDir();
  328. }
  329. liaison = getLiaison();
  330. // check if liaison wants to log errors using us as logger
  331. if (liaison instanceof XSLTLoggerAware) {
  332. ((XSLTLoggerAware) liaison).setLogger(this);
  333. }
  334. log("Using " + liaison.getClass().toString(), Project.MSG_VERBOSE);
  335. if (xslFile != null) {
  336. // If we enter here, it means that the stylesheet is supplied
  337. // via style attribute
  338. File stylesheet = getProject().resolveFile(xslFile);
  339. if (!stylesheet.exists()) {
  340. final File alternative = FILE_UTILS.resolveFile(baseDir, xslFile);
  341. /*
  342. * shouldn't throw out deprecation warnings before we know,
  343. * the wrong version has been used.
  344. */
  345. if (alternative.exists()) {
  346. log("DEPRECATED - the 'style' attribute should be "
  347. + "relative to the project's");
  348. log(" basedir, not the tasks's basedir.");
  349. stylesheet = alternative;
  350. }
  351. }
  352. final FileResource fr = new FileResource();
  353. fr.setProject(getProject());
  354. fr.setFile(stylesheet);
  355. styleResource = fr;
  356. } else {
  357. styleResource = xslResource;
  358. }
  359. if (!styleResource.isExists()) {
  360. handleError("stylesheet " + styleResource + " doesn't exist.");
  361. return;
  362. }
  363. // if we have an in file and out then process them
  364. if (inFile != null && outFile != null) {
  365. process(inFile, outFile, styleResource);
  366. return;
  367. }
  368. /*
  369. * if we get here, in and out have not been specified, we are
  370. * in batch processing mode.
  371. */
  372. //-- make sure destination directory exists...
  373. checkDest();
  374. if (useImplicitFileset) {
  375. scanner = getDirectoryScanner(baseDir);
  376. log("Transforming into " + destDir, Project.MSG_INFO);
  377. // Process all the files marked for styling
  378. list = scanner.getIncludedFiles();
  379. for (int i = 0; i < list.length; ++i) {
  380. process(baseDir, list[i], destDir, styleResource);
  381. }
  382. if (performDirectoryScan) {
  383. // Process all the directories marked for styling
  384. dirs = scanner.getIncludedDirectories();
  385. for (int j = 0; j < dirs.length; ++j) {
  386. list = new File(baseDir, dirs[j]).list();
  387. for (int i = 0; i < list.length; ++i) {
  388. process(baseDir, dirs[j] + File.separator + list[i], destDir,
  389. styleResource);
  390. }
  391. }
  392. }
  393. } else { // only resource collections, there better be some
  394. if (resources.size() == 0) {
  395. if (failOnNoResources) {
  396. handleError("no resources specified");
  397. }
  398. return;
  399. }
  400. }
  401. processResources(styleResource);
  402. } finally {
  403. if (loader != null) {
  404. loader.resetThreadContextLoader();
  405. loader.cleanup();
  406. loader = null;
  407. }
  408. if (sysProperties.size() > 0) {
  409. sysProperties.restoreSystem();
  410. }
  411. liaison = null;
  412. stylesheetLoaded = false;
  413. baseDir = savedBaseDir;
  414. }
  415. }
  416. /**
  417. * Set whether to check dependencies, or always generate;
  418. * optional, default is false.
  419. *
  420. * @param force true if always generate.
  421. */
  422. public void setForce(final boolean force) {
  423. this.force = force;
  424. }
  425. /**
  426. * Set the base directory;
  427. * optional, default is the project's basedir.
  428. *
  429. * @param dir the base directory
  430. **/
  431. public void setBasedir(final File dir) {
  432. baseDir = dir;
  433. }
  434. /**
  435. * Set the destination directory into which the XSL result
  436. * files should be copied to;
  437. * required, unless <tt>in</tt> and <tt>out</tt> are
  438. * specified.
  439. * @param dir the name of the destination directory
  440. **/
  441. public void setDestdir(final File dir) {
  442. destDir = dir;
  443. }
  444. /**
  445. * Set the desired file extension to be used for the target;
  446. * optional, default is html.
  447. * @param name the extension to use
  448. **/
  449. public void setExtension(final String name) {
  450. targetExtension = name;
  451. }
  452. /**
  453. * Name of the stylesheet to use - given either relative
  454. * to the project's basedir or as an absolute path; required.
  455. *
  456. * @param xslFile the stylesheet to use
  457. */
  458. public void setStyle(final String xslFile) {
  459. this.xslFile = xslFile;
  460. }
  461. /**
  462. * Set the optional classpath to the XSL processor
  463. *
  464. * @param classpath the classpath to use when loading the XSL processor
  465. */
  466. public void setClasspath(final Path classpath) {
  467. createClasspath().append(classpath);
  468. }
  469. /**
  470. * Set the optional classpath to the XSL processor
  471. *
  472. * @return a path instance to be configured by the Ant core.
  473. */
  474. public Path createClasspath() {
  475. if (classpath == null) {
  476. classpath = new Path(getProject());
  477. }
  478. return classpath.createPath();
  479. }
  480. /**
  481. * Set the reference to an optional classpath to the XSL processor
  482. *
  483. * @param r the id of the Ant path instance to act as the classpath
  484. * for loading the XSL processor
  485. */
  486. public void setClasspathRef(final Reference r) {
  487. createClasspath().setRefid(r);
  488. }
  489. /**
  490. * Set the name of the XSL processor to use; optional, default trax.
  491. *
  492. * @param processor the name of the XSL processor
  493. */
  494. public void setProcessor(final String processor) {
  495. this.processor = processor;
  496. }
  497. /**
  498. * Whether to use the implicit fileset.
  499. *
  500. * <p>Set this to false if you want explicit control with nested
  501. * resource collections.</p>
  502. * @param useimplicitfileset set to true if you want to use implicit fileset
  503. * @since Ant 1.7
  504. */
  505. public void setUseImplicitFileset(final boolean useimplicitfileset) {
  506. useImplicitFileset = useimplicitfileset;
  507. }
  508. /**
  509. * Add the catalog to our internal catalog
  510. *
  511. * @param xmlCatalog the XMLCatalog instance to use to look up DTDs
  512. */
  513. public void addConfiguredXMLCatalog(final XMLCatalog xmlCatalog) {
  514. this.xmlCatalog.addConfiguredXMLCatalog(xmlCatalog);
  515. }
  516. /**
  517. * Pass the filename of the current processed file as a xsl parameter
  518. * to the transformation. This value sets the name of that xsl parameter.
  519. *
  520. * @param fileNameParameter name of the xsl parameter retrieving the
  521. * current file name
  522. */
  523. public void setFileNameParameter(final String fileNameParameter) {
  524. this.fileNameParameter = fileNameParameter;
  525. }
  526. /**
  527. * Pass the directory name of the current processed file as a xsl parameter
  528. * to the transformation. This value sets the name of that xsl parameter.
  529. *
  530. * @param fileDirParameter name of the xsl parameter retrieving the
  531. * current file directory
  532. */
  533. public void setFileDirParameter(final String fileDirParameter) {
  534. this.fileDirParameter = fileDirParameter;
  535. }
  536. /**
  537. * Whether to suppress warning messages of the processor.
  538. *
  539. * @param b boolean
  540. * @since Ant 1.8.0
  541. */
  542. public void setSuppressWarnings(final boolean b) {
  543. suppressWarnings = b;
  544. }
  545. /**
  546. * Whether to suppress warning messages of the processor.
  547. *
  548. * @return boolean
  549. * @since Ant 1.8.0
  550. */
  551. public boolean getSuppressWarnings() {
  552. return suppressWarnings;
  553. }
  554. /**
  555. * Whether transformation errors should make the build fail.
  556. *
  557. * @param b boolean
  558. * @since Ant 1.8.0
  559. */
  560. public void setFailOnTransformationError(final boolean b) {
  561. failOnTransformationError = b;
  562. }
  563. /**
  564. * Whether any errors should make the build fail.
  565. *
  566. * @param b boolean
  567. * @since Ant 1.8.0
  568. */
  569. public void setFailOnError(final boolean b) {
  570. failOnError = b;
  571. }
  572. /**
  573. * Whether the build should fail if the nested resource collection is empty.
  574. *
  575. * @param b boolean
  576. * @since Ant 1.8.0
  577. */
  578. public void setFailOnNoResources(final boolean b) {
  579. failOnNoResources = b;
  580. }
  581. /**
  582. * A system property to set during transformation.
  583. *
  584. * @param sysp Environment.Variable
  585. * @since Ant 1.8.0
  586. */
  587. public void addSysproperty(final Environment.Variable sysp) {
  588. sysProperties.addVariable(sysp);
  589. }
  590. /**
  591. * A set of system properties to set during transformation.
  592. *
  593. * @param sysp PropertySet
  594. * @since Ant 1.8.0
  595. */
  596. public void addSyspropertyset(final PropertySet sysp) {
  597. sysProperties.addSyspropertyset(sysp);
  598. }
  599. /**
  600. * Enables Xalan2 traces and uses the given configuration.
  601. *
  602. * <p>Note that this element doesn't have any effect with a
  603. * processor other than trax or if the Transformer is not Xalan2's
  604. * transformer implementation.</p>
  605. *
  606. * @return TraceConfiguration
  607. * @since Ant 1.8.0
  608. */
  609. public TraceConfiguration createTrace() {
  610. if (traceConfiguration != null) {
  611. throw new BuildException("can't have more than one trace"
  612. + " configuration");
  613. }
  614. traceConfiguration = new TraceConfiguration();
  615. return traceConfiguration;
  616. }
  617. /**
  618. * Configuration for Xalan2 traces.
  619. *
  620. * @return TraceConfiguration
  621. * @since Ant 1.8.0
  622. */
  623. public TraceConfiguration getTraceConfiguration() {
  624. return traceConfiguration;
  625. }
  626. /**
  627. * Load processor here instead of in setProcessor - this will be
  628. * called from within execute, so we have access to the latest
  629. * classpath.
  630. *
  631. * @param proc the name of the processor to load.
  632. * @exception Exception if the processor cannot be loaded.
  633. */
  634. private void resolveProcessor(final String proc) throws Exception {
  635. if (proc.equals(PROCESSOR_TRAX)) {
  636. liaison = new TraXLiaison();
  637. } else {
  638. //anything else is a classname
  639. final Class clazz = loadClass(proc);
  640. liaison = (XSLTLiaison) clazz.newInstance();
  641. }
  642. }
  643. /**
  644. * Load named class either via the system classloader or a given
  645. * custom classloader.
  646. *
  647. * As a side effect, the loader is set as the thread context classloader
  648. * @param classname the name of the class to load.
  649. * @return the requested class.
  650. */
  651. private Class loadClass(final String classname) throws ClassNotFoundException {
  652. setupLoader();
  653. if (loader == null) {
  654. return Class.forName(classname);
  655. }
  656. return Class.forName(classname, true, loader);
  657. }
  658. /**
  659. * If a custom classpath has been defined but no loader created
  660. * yet, create the classloader and set it as the context
  661. * classloader.
  662. */
  663. private void setupLoader() {
  664. if (classpath != null && loader == null) {
  665. loader = getProject().createClassLoader(classpath);
  666. loader.setThreadContextLoader();
  667. }
  668. }
  669. /**
  670. * Specifies the output name for the styled result from the
  671. * <tt>in</tt> attribute; required if <tt>in</tt> is set
  672. *
  673. * @param outFile the output File instance.
  674. */
  675. public void setOut(final File outFile) {
  676. this.outFile = outFile;
  677. }
  678. /**
  679. * specifies a single XML document to be styled. Should be used
  680. * with the <tt>out</tt> attribute; required if <tt>out</tt> is set
  681. *
  682. * @param inFile the input file
  683. */
  684. public void setIn(final File inFile) {
  685. this.inFile = inFile;
  686. }
  687. /**
  688. * Throws a BuildException if the destination directory hasn't
  689. * been specified.
  690. * @since Ant 1.7
  691. */
  692. private void checkDest() {
  693. if (destDir == null) {
  694. handleError("destdir attributes must be set!");
  695. }
  696. }
  697. /**
  698. * Styles all existing resources.
  699. *
  700. * @param stylesheet style sheet to use
  701. * @since Ant 1.7
  702. */
  703. private void processResources(final Resource stylesheet) {
  704. for (final Resource r : resources) {
  705. if (!r.isExists()) {
  706. continue;
  707. }
  708. File base = baseDir;
  709. String name = r.getName();
  710. final FileProvider fp = r.as(FileProvider.class);
  711. if (fp != null) {
  712. final FileResource f = ResourceUtils.asFileResource(fp);
  713. base = f.getBaseDir();
  714. if (base == null) {
  715. name = f.getFile().getAbsolutePath();
  716. }
  717. }
  718. process(base, name, destDir, stylesheet);
  719. }
  720. }
  721. /**
  722. * Processes the given input XML file and stores the result
  723. * in the given resultFile.
  724. *
  725. * @param baseDir the base directory for resolving files.
  726. * @param xmlFile the input file
  727. * @param destDir the destination directory
  728. * @param stylesheet the stylesheet to use.
  729. * @exception BuildException if the processing fails.
  730. */
  731. private void process(final File baseDir, final String xmlFile, final File destDir, final Resource stylesheet)
  732. throws BuildException {
  733. File outF = null;
  734. File inF = null;
  735. try {
  736. final long styleSheetLastModified = stylesheet.getLastModified();
  737. inF = new File(baseDir, xmlFile);
  738. if (inF.isDirectory()) {
  739. log("Skipping " + inF + " it is a directory.", Project.MSG_VERBOSE);
  740. return;
  741. }
  742. FileNameMapper mapper = null;
  743. if (mapperElement != null) {
  744. mapper = mapperElement.getImplementation();
  745. } else {
  746. mapper = new StyleMapper();
  747. }
  748. final String[] outFileName = mapper.mapFileName(xmlFile);
  749. if (outFileName == null || outFileName.length == 0) {
  750. log("Skipping " + inFile + " it cannot get mapped to output.", Project.MSG_VERBOSE);
  751. return;
  752. } else if (outFileName.length > 1) {
  753. log("Skipping " + inFile + " its mapping is ambiguos.", Project.MSG_VERBOSE);
  754. return;
  755. }
  756. outF = new File(destDir, outFileName[0]);
  757. if (force || inF.lastModified() > outF.lastModified()
  758. || styleSheetLastModified > outF.lastModified()) {
  759. ensureDirectoryFor(outF);
  760. log("Processing " + inF + " to " + outF);
  761. configureLiaison(stylesheet);
  762. setLiaisonDynamicFileParameters(liaison, inF);
  763. liaison.transform(inF, outF);
  764. }
  765. } catch (final Exception ex) {
  766. // If failed to process document, must delete target document,
  767. // or it will not attempt to process it the second time
  768. log("Failed to process " + inFile, Project.MSG_INFO);
  769. if (outF != null) {
  770. outF.delete();
  771. }
  772. handleTransformationError(ex);
  773. }
  774. } //-- processXML
  775. /**
  776. * Process the input file to the output file with the given stylesheet.
  777. *
  778. * @param inFile the input file to process.
  779. * @param outFile the destination file.
  780. * @param stylesheet the stylesheet to use.
  781. * @exception BuildException if the processing fails.
  782. */
  783. private void process(final File inFile, final File outFile, final Resource stylesheet) throws BuildException {
  784. try {
  785. final long styleSheetLastModified = stylesheet.getLastModified();
  786. log("In file " + inFile + " time: " + inFile.lastModified(), Project.MSG_DEBUG);
  787. log("Out file " + outFile + " time: " + outFile.lastModified(), Project.MSG_DEBUG);
  788. log("Style file " + xslFile + " time: " + styleSheetLastModified, Project.MSG_DEBUG);
  789. if (force || inFile.lastModified() >= outFile.lastModified()
  790. || styleSheetLastModified >= outFile.lastModified()) {
  791. ensureDirectoryFor(outFile);
  792. log("Processing " + inFile + " to " + outFile, Project.MSG_INFO);
  793. configureLiaison(stylesheet);
  794. setLiaisonDynamicFileParameters(liaison, inFile);
  795. liaison.transform(inFile, outFile);
  796. } else {
  797. log("Skipping input file " + inFile + " because it is older than output file "
  798. + outFile + " and so is the stylesheet " + stylesheet, Project.MSG_DEBUG);
  799. }
  800. } catch (final Exception ex) {
  801. log("Failed to process " + inFile, Project.MSG_INFO);
  802. if (outFile != null) {
  803. outFile.delete();
  804. }
  805. handleTransformationError(ex);
  806. }
  807. }
  808. /**
  809. * Ensure the directory exists for a given file
  810. *
  811. * @param targetFile the file for which the directories are required.
  812. * @exception BuildException if the directories cannot be created.
  813. */
  814. private void ensureDirectoryFor(final File targetFile) throws BuildException {
  815. final File directory = targetFile.getParentFile();
  816. if (!directory.exists()) {
  817. if (!(directory.mkdirs() || directory.isDirectory())) {
  818. handleError("Unable to create directory: "
  819. + directory.getAbsolutePath());
  820. }
  821. }
  822. }
  823. /**
  824. * Get the factory instance configured for this processor
  825. *
  826. * @return the factory instance in use
  827. */
  828. public Factory getFactory() {
  829. return factory;
  830. }
  831. /**
  832. * Get the XML catalog containing entity definitions
  833. *
  834. * @return the XML catalog for the task.
  835. */
  836. public XMLCatalog getXMLCatalog() {
  837. xmlCatalog.setProject(getProject());
  838. return xmlCatalog;
  839. }
  840. /**
  841. * Get an enumeration on the outputproperties.
  842. * @return the outputproperties
  843. */
  844. public Enumeration getOutputProperties() {
  845. return outputProperties.elements();
  846. }
  847. /**
  848. * Get the Liaison implementation to use in processing.
  849. *
  850. * @return an instance of the XSLTLiaison interface.
  851. */
  852. protected XSLTLiaison getLiaison() {
  853. // if processor wasn't specified, use TraX.
  854. if (liaison == null) {
  855. if (processor != null) {
  856. try {
  857. resolveProcessor(processor);
  858. } catch (final Exception e) {
  859. handleError(e);
  860. }
  861. } else {
  862. try {
  863. resolveProcessor(PROCESSOR_TRAX);
  864. } catch (final Throwable e1) {
  865. log(StringUtils.getStackTrace(e1), Project.MSG_ERR);
  866. handleError(e1);
  867. }
  868. }
  869. }
  870. return liaison;
  871. }
  872. /**
  873. * Create an instance of an XSL parameter for configuration by Ant.
  874. *
  875. * @return an instance of the Param class to be configured.
  876. */
  877. public Param createParam() {
  878. final Param p = new Param();
  879. params.add(p);
  880. return p;
  881. }
  882. /**
  883. * The Param inner class used to store XSL parameters
  884. */
  885. public static class Param {
  886. /** The parameter name */
  887. private String name = null;
  888. /** The parameter's value */
  889. private String expression = null;
  890. /**
  891. * Type of the expression.
  892. * @see ParamType
  893. */
  894. private String type;
  895. private Object ifCond;
  896. private Object unlessCond;
  897. private Project project;
  898. /**
  899. * Set the current project
  900. *
  901. * @param project the current project
  902. */
  903. public void setProject(final Project project) {
  904. this.project = project;
  905. }
  906. /**
  907. * Set the parameter name.
  908. *
  909. * @param name the name of the parameter.
  910. */
  911. public void setName(final String name) {
  912. this.name = name;
  913. }
  914. /**
  915. * The parameter value -
  916. * can be a primitive type value or an XPath expression.
  917. * @param expression the parameter's value/expression.
  918. * @see #setType(java.lang.String)
  919. */
  920. public void setExpression(final String expression) {
  921. this.expression = expression;
  922. }
  923. /**
  924. * @param type String
  925. * @see ParamType
  926. * @since Ant 1.9.3
  927. */
  928. public void setType(final String type) {
  929. this.type = type;
  930. }
  931. /**
  932. * Get the parameter name
  933. *
  934. * @return the parameter name
  935. * @exception BuildException if the name is not set.
  936. */
  937. public String getName() throws BuildException {
  938. if (name == null) {
  939. throw new BuildException("Name attribute is missing.");
  940. }
  941. return name;
  942. }
  943. /**
  944. * Get the parameter's value
  945. *
  946. * @return the parameter value
  947. * @exception BuildException if the value is not set.
  948. * @see #getType()
  949. */
  950. public String getExpression() throws BuildException {
  951. if (expression == null) {
  952. throw new BuildException("Expression attribute is missing.");
  953. }
  954. return expression;
  955. }
  956. /**
  957. * @return String
  958. * @see ParamType
  959. * @since Ant 1.9.3
  960. */
  961. public String getType() {
  962. return type;
  963. }
  964. /**
  965. * Set whether this param should be used. It will be used if
  966. * the expression evaluates to true or the name of a property
  967. * which has been set, otherwise it won't.
  968. * @param ifCond evaluated expression
  969. * @since Ant 1.8.0
  970. */
  971. public void setIf(final Object ifCond) {
  972. this.ifCond = ifCond;
  973. }
  974. /**
  975. * Set whether this param should be used. It will be used if
  976. * the expression evaluates to true or the name of a property
  977. * which has been set, otherwise it won't.
  978. * @param ifProperty evaluated expression
  979. */
  980. public void setIf(final String ifProperty) {
  981. setIf((Object) ifProperty);
  982. }
  983. /**
  984. * Set whether this param should NOT be used. It will not be
  985. * used if the expression evaluates to true or the name of a
  986. * property which has been set, otherwise it will be used.
  987. * @param unlessCond evaluated expression
  988. * @since Ant 1.8.0
  989. */
  990. public void setUnless(final Object unlessCond) {
  991. this.unlessCond = unlessCond;
  992. }
  993. /**
  994. * Set whether this param should NOT be used. It will not be
  995. * used if the expression evaluates to true or the name of a
  996. * property which has been set, otherwise it will be used.
  997. * @param unlessProperty evaluated expression
  998. */
  999. public void setUnless(final String unlessProperty) {
  1000. setUnless((Object) unlessProperty);
  1001. }
  1002. /**
  1003. * Ensures that the param passes the conditions placed
  1004. * on it with <code>if</code> and <code>unless</code> properties.
  1005. * @return true if the task passes the "if" and "unless" parameters
  1006. */
  1007. public boolean shouldUse() {
  1008. final PropertyHelper ph = PropertyHelper.getPropertyHelper(project);
  1009. return ph.testIfCondition(ifCond)
  1010. && ph.testUnlessCondition(unlessCond);
  1011. }
  1012. } // Param
  1013. /**
  1014. * Enum for types of the parameter expression.
  1015. *
  1016. * <p>The expression can be:</p>
  1017. * <ul>
  1018. * <li>primitive type that will be parsed from the string value e.g.
  1019. * {@linkplain Integer#parseInt(java.lang.String)}</li>
  1020. * <li>XPath expression that will be evaluated (outside of the transformed
  1021. * document - on empty one) and casted to given type. Inside XPath
  1022. * expressions the Ant variables (properties) can be used (as XPath
  1023. * variables - e.g. $variable123). n.b. placeholders in form of
  1024. * ${variable123} will be substituted with their values before evaluating the
  1025. * XPath expression (so it can be used for dynamic XPath function names and
  1026. * other hacks).</li>
  1027. * </ul>
  1028. * <p>The parameter will be then passed to the XSLT template.</p>
  1029. *
  1030. * <p>Default type (if omitted) is primitive String. So if the expression is e.g
  1031. * "true" with no type, in XSLT it will be only a text string, not true
  1032. * boolean.</p>
  1033. *
  1034. * @see Param#setType(java.lang.String)
  1035. * @see Param#setExpression(java.lang.String)
  1036. * @since Ant 1.9.3
  1037. */
  1038. public enum ParamType {
  1039. STRING,
  1040. BOOLEAN,
  1041. INT,
  1042. LONG,
  1043. DOUBLE,
  1044. XPATH_STRING,
  1045. XPATH_BOOLEAN,
  1046. XPATH_NUMBER,
  1047. XPATH_NODE,
  1048. XPATH_NODESET;
  1049. public static final Map<ParamType, QName> XPATH_TYPES;
  1050. static {
  1051. final Map<ParamType, QName> m = new EnumMap<ParamType, QName>(ParamType.class);
  1052. m.put(XPATH_STRING, XPathConstants.STRING);
  1053. m.put(XPATH_BOOLEAN, XPathConstants.BOOLEAN);
  1054. m.put(XPATH_NUMBER, XPathConstants.NUMBER);
  1055. m.put(XPATH_NODE, XPathConstants.NODE);
  1056. m.put(XPATH_NODESET, XPathConstants.NODESET);
  1057. XPATH_TYPES = Collections.unmodifiableMap(m);
  1058. }
  1059. }
  1060. /**
  1061. * Create an instance of an output property to be configured.
  1062. * @return the newly created output property.
  1063. * @since Ant 1.5
  1064. */
  1065. public OutputProperty createOutputProperty() {
  1066. final OutputProperty p = new OutputProperty();
  1067. outputProperties.addElement(p);
  1068. return p;
  1069. }
  1070. /**
  1071. * Specify how the result tree should be output as specified
  1072. * in the <a href="http://www.w3.org/TR/xslt#output">
  1073. * specification</a>.
  1074. * @since Ant 1.5
  1075. */
  1076. public static class OutputProperty {
  1077. /** output property name */
  1078. private String name;
  1079. /** output property value */
  1080. private String value;
  1081. /**
  1082. * @return the output property name.
  1083. */
  1084. public String getName() {
  1085. return name;
  1086. }
  1087. /**
  1088. * set the name for this property
  1089. * @param name A non-null String that specifies an
  1090. * output property name, which may be namespace qualified.
  1091. */
  1092. public void setName(final String name) {
  1093. this.name = name;
  1094. }
  1095. /**
  1096. * @return the output property value.
  1097. */
  1098. public String getValue() {
  1099. return value;
  1100. }
  1101. /**
  1102. * set the value for this property
  1103. * @param value The non-null string value of the output property.
  1104. */
  1105. public void setValue(final String value) {
  1106. this.value = value;
  1107. }
  1108. }
  1109. /**
  1110. * Initialize internal instance of XMLCatalog.
  1111. * Initialize XPath for parameter evaluation.
  1112. * @throws BuildException on error
  1113. */
  1114. @Override
  1115. public void init() throws BuildException {
  1116. super.init();
  1117. xmlCatalog.setProject(getProject());
  1118. xpathFactory = XPathFactory.newInstance();
  1119. xpath = xpathFactory.newXPath();
  1120. xpath.setXPathVariableResolver(new XPathVariableResolver() {
  1121. public Object resolveVariable(final QName variableName) {
  1122. return getProject().getProperty(variableName.toString());
  1123. }
  1124. });
  1125. }
  1126. /**
  1127. * Loads the stylesheet and set xsl:param parameters.
  1128. *
  1129. * @param stylesheet the file from which to load the stylesheet.
  1130. * @exception BuildException if the stylesheet cannot be loaded.
  1131. * @deprecated since Ant 1.7
  1132. */
  1133. @Deprecated
  1134. protected void configureLiaison(final File stylesheet) throws BuildException {
  1135. final FileResource fr = new FileResource();
  1136. fr.setProject(getProject());
  1137. fr.setFile(stylesheet);
  1138. configureLiaison(fr);
  1139. }
  1140. /**
  1141. * Loads the stylesheet and set xsl:param parameters.
  1142. *
  1143. * @param stylesheet the resource from which to load the stylesheet.
  1144. * @exception BuildException if the stylesheet cannot be loaded.
  1145. * @since Ant 1.7
  1146. */
  1147. protected void configureLiaison(final Resource stylesheet) throws BuildException {
  1148. if (stylesheetLoaded && reuseLoadedStylesheet) {
  1149. return;
  1150. }
  1151. stylesheetLoaded = true;
  1152. try {
  1153. log("Loading stylesheet " + stylesheet, Project.MSG_INFO);
  1154. // We call liaison.configure() and then liaison.setStylesheet()
  1155. // so that the internal variables of liaison can be set up
  1156. if (liaison instanceof XSLTLiaison2) {
  1157. ((XSLTLiaison2) liaison).configure(this);
  1158. }
  1159. if (liaison instanceof XSLTLiaison3) {
  1160. // If we are here we can set the stylesheet as a
  1161. // resource
  1162. ((XSLTLiaison3) liaison).setStylesheet(stylesheet);
  1163. } else {
  1164. // If we are here we cannot set the stylesheet as
  1165. // a resource, but we can set it as a file. So,
  1166. // we make an attempt to get it as a file
  1167. final FileProvider fp =
  1168. stylesheet.as(FileProvider.class);
  1169. if (fp != null) {
  1170. liaison.setStylesheet(fp.getFile());
  1171. } else {
  1172. handleError(liaison.getClass().toString()
  1173. + " accepts the stylesheet only as a file");
  1174. return;
  1175. }
  1176. }
  1177. for (final Param p : params) {
  1178. if (p.shouldUse()) {
  1179. final Object evaluatedParam = evaluateParam(p);
  1180. if (liaison instanceof XSLTLiaison4) {
  1181. ((XSLTLiaison4) liaison).addParam(p.getName(), evaluatedParam);
  1182. } else {
  1183. if (evaluatedParam == null || evaluatedParam instanceof String) {
  1184. liaison.addParam(p.getName(), (String) evaluatedParam);
  1185. } else {
  1186. log("XSLTLiaison '" + liaison.getClass().getName()
  1187. + "' supports only String parameters. Converting parameter '" + p.getName()
  1188. + "' to its String value '" + evaluatedParam, Project.MSG_WARN);
  1189. liaison.addParam(p.getName(), String.valueOf(evaluatedParam));
  1190. }
  1191. }
  1192. }
  1193. }
  1194. } catch (final Exception ex) {
  1195. log("Failed to transform using stylesheet " + stylesheet, Project.MSG_INFO);
  1196. handleTransformationError(ex);
  1197. }
  1198. }
  1199. /**
  1200. * Evaluates parameter expression according to its type.
  1201. *
  1202. * @param param parameter from Ant build file
  1203. * @return value to be passed to XSLT as parameter
  1204. * @throws IllegalArgumentException if param type is unsupported
  1205. * @throws NumberFormatException if expression of numeric type is not
  1206. * desired numeric type
  1207. * @throws XPathExpressionException if XPath expression can not be compiled
  1208. * @since Ant 1.9.3
  1209. */
  1210. private Object evaluateParam(final Param param) throws XPathExpressionException {
  1211. final String typeName = param.getType();
  1212. final String expression = param.getExpression();
  1213. ParamType type;
  1214. if (typeName == null || "".equals(typeName)) {
  1215. type = ParamType.STRING; // String is default
  1216. } else {
  1217. try {
  1218. type = ParamType.valueOf(typeName);
  1219. } catch (final IllegalArgumentException e) {
  1220. throw new IllegalArgumentException("Invalid XSLT parameter type: " + typeName, e);
  1221. }
  1222. }
  1223. switch (type) {
  1224. case STRING:
  1225. return expression;
  1226. case BOOLEAN:
  1227. return Boolean.parseBoolean(expression);
  1228. case DOUBLE:
  1229. return Double.parseDouble(expression);
  1230. case INT:
  1231. return Integer.parseInt(expression);
  1232. case LONG:
  1233. return Long.parseLong(expression);
  1234. default: // XPath expression
  1235. final QName xpathType = ParamType.XPATH_TYPES.get(type);
  1236. if (xpathType == null) {
  1237. throw new IllegalArgumentException("Invalid XSLT parameter type: " + typeName);
  1238. } else {
  1239. final XPathExpression xpe = xpath.compile(expression);
  1240. // null = evaluate XPath on empty XML document
  1241. return xpe.evaluate((Object) null, xpathType);
  1242. }
  1243. }
  1244. }
  1245. /**
  1246. * Sets file parameter(s) for directory and filename if the attribute
  1247. * 'filenameparameter' or 'filedirparameter' are set in the task.
  1248. *
  1249. * @param liaison to change parameters for
  1250. * @param inFile to get the additional file information from
  1251. * @throws Exception if an exception occurs on filename lookup
  1252. *
  1253. * @since Ant 1.7
  1254. */
  1255. private void setLiaisonDynamicFileParameters(
  1256. final XSLTLiaison liaison, final File inFile) throws Exception { //NOSONAR
  1257. if (fileNameParameter != null) {
  1258. liaison.addParam(fileNameParameter, inFile.getName());
  1259. }
  1260. if (fileDirParameter != null) {
  1261. final String fileName = FileUtils.getRelativePath(baseDir, inFile);
  1262. final File file = new File(fileName);
  1263. // Give always a slash as file separator, so the stylesheet could be sure about that
  1264. // Use '.' so a dir + "/" + name would not result in an absolute path
  1265. liaison.addParam(fileDirParameter, file.getParent() != null ? file.getParent().replace(
  1266. '\\', '/') : ".");
  1267. }
  1268. }
  1269. /**
  1270. * Create the factory element to configure a trax liaison.
  1271. * @return the newly created factory element.
  1272. * @throws BuildException if the element is created more than one time.
  1273. */
  1274. public Factory createFactory() throws BuildException {
  1275. if (factory != null) {
  1276. handleError("'factory' element must be unique");
  1277. } else {
  1278. factory = new Factory();
  1279. }
  1280. return factory;
  1281. }
  1282. /**
  1283. * Throws an exception with the given message if failOnError is
  1284. * true, otherwise logs the message using the WARN level.
  1285. *
  1286. * @param msg String
  1287. * @since Ant 1.8.0
  1288. */
  1289. protected void handleError(final String msg) {
  1290. if (failOnError) {
  1291. throw new BuildException(msg, getLocation());
  1292. }
  1293. log(msg, Project.MSG_WARN);
  1294. }
  1295. /**
  1296. * Throws an exception with the given nested exception if
  1297. * failOnError is true, otherwise logs the message using the WARN
  1298. * level.
  1299. *
  1300. * @param ex Throwable
  1301. * @since Ant 1.8.0
  1302. */
  1303. protected void handleError(final Throwable ex) {
  1304. if (failOnError) {
  1305. throw new BuildException(ex);
  1306. } else {
  1307. log("Caught an exception: " + ex, Project.MSG_WARN);
  1308. }
  1309. }
  1310. /**
  1311. * Throws an exception with the given nested exception if
  1312. * failOnError and failOnTransformationError are true, otherwise
  1313. * logs the message using the WARN level.
  1314. *
  1315. * @param ex Exception
  1316. * @since Ant 1.8.0
  1317. */
  1318. protected void handleTransformationError(final Exception ex) {
  1319. if (failOnError && failOnTransformationError) {
  1320. throw new BuildException(ex);
  1321. } else {
  1322. log("Caught an error during transformation: " + ex,
  1323. Project.MSG_WARN);
  1324. }
  1325. }
  1326. /**
  1327. * The factory element to configure a transformer factory
  1328. * @since Ant 1.6
  1329. */
  1330. public static class Factory {
  1331. /** the factory class name to use for TraXLiaison */
  1332. private String name;
  1333. /**
  1334. * the list of factory attributes to use for TraXLiaison
  1335. */
  1336. private final List<Attribute> attributes = new ArrayList<Attribute>();
  1337. /**
  1338. * the list of factory features to use for TraXLiaison
  1339. */
  1340. private final List<Feature> features = new ArrayList<Feature>();
  1341. /**
  1342. * @return the name of the factory.
  1343. */
  1344. public String getName() {
  1345. return name;
  1346. }
  1347. /**
  1348. * Set the name of the factory
  1349. * @param name the name of the factory.
  1350. */
  1351. public void setName(final String name) {
  1352. this.name = name;
  1353. }
  1354. /**
  1355. * Create an instance of a factory attribute.
  1356. * @param attr the newly created factory attribute
  1357. */
  1358. public void addAttribute(final Attribute attr) {
  1359. attributes.add(attr);
  1360. }
  1361. /**
  1362. * return the attribute elements.
  1363. * @return the enumeration of attributes
  1364. */
  1365. public Enumeration getAttributes() {
  1366. return Collections.enumeration(attributes);
  1367. }
  1368. /**
  1369. * Create an instance of a factory feature.
  1370. * @param feature the newly created feature
  1371. * @since Ant 1.9.8
  1372. */
  1373. public void addFeature(final Feature feature) {
  1374. features.add(feature);
  1375. }
  1376. /**
  1377. * The configured features.
  1378. * @since Ant 1.9.8
  1379. *
  1380. * @return Iterable&lt;Feature&gt;
  1381. */
  1382. public Iterable<Feature> getFeatures() {
  1383. return features;
  1384. }
  1385. /**
  1386. * A JAXP factory attribute. This is mostly processor specific, for
  1387. * example for Xalan 2.3+, the following attributes could be set:
  1388. * <ul>
  1389. * <li>http://xml.apache.org/xalan/features/optimize (true|false) </li>
  1390. * <li>http://xml.apache.org/xalan/features/incremental (true|false) </li>
  1391. * </ul>
  1392. */
  1393. public static class Attribute
  1394. extends ProjectComponent
  1395. implements DynamicConfigurator {
  1396. /** attribute name, mostly processor specific */
  1397. private String name;
  1398. /** attribute value, often a boolean string */
  1399. private Object value;
  1400. /**
  1401. * @return the attribute name.
  1402. */
  1403. public String getName() {
  1404. return name;
  1405. }
  1406. /**
  1407. * @return the attribute value.
  1408. */
  1409. public Object getValue() {
  1410. return value;
  1411. }
  1412. /**
  1413. * Not used.
  1414. * @param name not used
  1415. * @return null
  1416. * @throws BuildException never
  1417. */
  1418. public Object createDynamicElement(final String name) throws BuildException {
  1419. return null;
  1420. }
  1421. /**
  1422. * Set an attribute.
  1423. * Only "name" and "value" are supported as names.
  1424. * @param name the name of the attribute
  1425. * @param value the value of the attribute
  1426. * @throws BuildException on error
  1427. */
  1428. public void setDynamicAttribute(final String name, final String value) throws BuildException {
  1429. // only 'name' and 'value' exist.
  1430. if ("name".equalsIgnoreCase(name)) {
  1431. this.name = value;
  1432. } else if ("value".equalsIgnoreCase(name)) {
  1433. // a value must be of a given type
  1434. // say boolean|integer|string that are mostly used.
  1435. if ("true".equalsIgnoreCase(value)) {
  1436. this.value = Boolean.TRUE;
  1437. } else if ("false".equalsIgnoreCase(value)) {
  1438. this.value = Boolean.FALSE;
  1439. } else {
  1440. try {
  1441. this.value = new Integer(value);
  1442. } catch (final NumberFormatException e) {
  1443. this.value = value;
  1444. }
  1445. }
  1446. } else if ("valueref".equalsIgnoreCase(name)) {
  1447. this.value = getProject().getReference(value);
  1448. } else if ("classloaderforpath".equalsIgnoreCase(name)) {
  1449. this.value =
  1450. ClasspathUtils.getClassLoaderForPath(getProject(),
  1451. new Reference(getProject(),
  1452. value));
  1453. } else {
  1454. throw new BuildException("Unsupported attribute: " + name);
  1455. }
  1456. }
  1457. } // -- class Attribute
  1458. /**
  1459. * A feature for the TraX factory.
  1460. * @since Ant 1.9.8
  1461. */
  1462. public static class Feature {
  1463. private String name;
  1464. private boolean value;
  1465. public Feature() { }
  1466. public Feature(String name, boolean value) {
  1467. this.name = name;
  1468. this.value = value;
  1469. }
  1470. /**
  1471. * @param name the feature name.
  1472. */
  1473. public void setName(String name) {
  1474. this.name = name;
  1475. }
  1476. /**
  1477. * @param value the feature value.
  1478. */
  1479. public void setValue(boolean value) {
  1480. this.value = value;
  1481. }
  1482. /**
  1483. * @return the feature name.
  1484. */
  1485. public String getName() {
  1486. return name;
  1487. }
  1488. /**
  1489. * @return the feature value.
  1490. */
  1491. public boolean getValue() {
  1492. return value;
  1493. }
  1494. }
  1495. } // -- class Factory
  1496. /**
  1497. * Mapper implementation of the "traditional" way &lt;xslt&gt;
  1498. * mapped filenames.
  1499. *
  1500. * <p>If the file has an extension, chop it off. Append whatever
  1501. * the user has specified as extension or ".html".</p>
  1502. *
  1503. * @since Ant 1.6.2
  1504. */
  1505. private class StyleMapper implements FileNameMapper {
  1506. public void setFrom(final String from) {
  1507. }
  1508. public void setTo(final String to) {
  1509. }
  1510. public String[] mapFileName(String xmlFile) {
  1511. final int dotPos = xmlFile.lastIndexOf('.');
  1512. if (dotPos > 0) {
  1513. xmlFile = xmlFile.substring(0, dotPos);
  1514. }
  1515. return new String[] {xmlFile + targetExtension};
  1516. }
  1517. }
  1518. /**
  1519. * Configuration for Xalan2 traces.
  1520. *
  1521. * @since Ant 1.8.0
  1522. */
  1523. public final class TraceConfiguration {
  1524. private boolean elements, extension, generation, selection, templates;
  1525. /**
  1526. * Set to true if the listener is to print events that occur
  1527. * as each node is 'executed' in the stylesheet.
  1528. *
  1529. * @param b boolean
  1530. */
  1531. public void setElements(final boolean b) {
  1532. elements = b;
  1533. }
  1534. /**
  1535. * True if the listener is to print events that occur as each
  1536. * node is 'executed' in the stylesheet.
  1537. *
  1538. * @return boolean
  1539. */
  1540. public boolean getElements() {
  1541. return elements;
  1542. }
  1543. /**
  1544. * Set to true if the listener is to print information after
  1545. * each extension event.
  1546. *
  1547. * @param b boolean
  1548. */
  1549. public void setExtension(final boolean b) {
  1550. extension = b;
  1551. }
  1552. /**
  1553. * True if the listener is to print information after each
  1554. * extension event.
  1555. *
  1556. * @return boolean
  1557. */
  1558. public boolean getExtension() {
  1559. return extension;
  1560. }
  1561. /**
  1562. * Set to true if the listener is to print information after
  1563. * each result-tree generation event.
  1564. *
  1565. * @param b boolean
  1566. */
  1567. public void setGeneration(final boolean b) {
  1568. generation = b;
  1569. }
  1570. /**
  1571. * True if the listener is to print information after each
  1572. * result-tree generation event.
  1573. *
  1574. * @return boolean
  1575. */
  1576. public boolean getGeneration() {
  1577. return generation;
  1578. }
  1579. /**
  1580. * Set to true if the listener is to print information after
  1581. * each selection event.
  1582. *
  1583. * @param b boolean
  1584. */
  1585. public void setSelection(final boolean b) {
  1586. selection = b;
  1587. }
  1588. /**
  1589. * True if the listener is to print information after each
  1590. * selection event.
  1591. *
  1592. * @return boolean
  1593. */
  1594. public boolean getSelection() {
  1595. return selection;
  1596. }
  1597. /**
  1598. * Set to true if the listener is to print an event whenever a
  1599. * template is invoked.
  1600. *
  1601. * @param b boolean
  1602. */
  1603. public void setTemplates(final boolean b) {
  1604. templates = b;
  1605. }
  1606. /**
  1607. * True if the listener is to print an event whenever a
  1608. * template is invoked.
  1609. *
  1610. * @return boolean
  1611. */
  1612. public boolean getTemplates() {
  1613. return templates;
  1614. }
  1615. /**
  1616. * The stream to write traces to.
  1617. *
  1618. * @return OutputStream
  1619. */
  1620. public java.io.OutputStream getOutputStream() {
  1621. return new LogOutputStream(XSLTProcess.this);
  1622. }
  1623. }
  1624. }