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 57 kB

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