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.

XmlProperty.java 25 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 2002-2003 The Apache Software Foundation. All rights
  5. * reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if
  20. * any, must include the following acknowlegement:
  21. * "This product includes software developed by the
  22. * Apache Software Foundation (http://www.apache.org/)."
  23. * Alternately, this acknowlegement may appear in the software itself,
  24. * if and wherever such third-party acknowlegements normally appear.
  25. *
  26. * 4. The names "The Jakarta Project", "Ant", and "Apache Software
  27. * Foundation" must not be used to endorse or promote products derived
  28. * from this software without prior written permission. For written
  29. * permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache"
  32. * nor may "Apache" appear in their names without prior written
  33. * permission of the Apache Group.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation. For more
  51. * information on the Apache Software Foundation, please see
  52. * <http://www.apache.org/>.
  53. */
  54. package org.apache.tools.ant.taskdefs;
  55. import java.io.BufferedInputStream;
  56. import java.io.File;
  57. import java.io.FileInputStream;
  58. import java.io.IOException;
  59. import java.util.Hashtable;
  60. import java.util.Enumeration;
  61. import javax.xml.parsers.DocumentBuilder;
  62. import javax.xml.parsers.DocumentBuilderFactory;
  63. import javax.xml.parsers.ParserConfigurationException;
  64. import org.apache.tools.ant.BuildException;
  65. import org.apache.tools.ant.Project;
  66. import org.apache.tools.ant.types.Path;
  67. import org.apache.tools.ant.types.Reference;
  68. import org.apache.tools.ant.util.FileUtils;
  69. import org.w3c.dom.Element;
  70. import org.w3c.dom.NamedNodeMap;
  71. import org.w3c.dom.Node;
  72. import org.w3c.dom.NodeList;
  73. import org.xml.sax.SAXException;
  74. /**
  75. * Loads property values from a valid XML file, generating the
  76. * property names from the file's element and attribute names.
  77. *
  78. * <p>Example:</p>
  79. * <pre>
  80. * &lt;root-tag myattr="true"&gt;
  81. * &lt;inner-tag someattr="val"&gt;Text&lt;/inner-tag&gt;
  82. * &lt;a2&gt;&lt;a3&gt;&lt;a4&gt;false&lt;/a4&gt;&lt;/a3&gt;&lt;/a2&gt;
  83. * &lt;x&gt;x1&lt;/x&gt;
  84. * &lt;x&gt;x2&lt;/x&gt;
  85. * &lt;/root-tag&gt;
  86. *</pre>
  87. *
  88. * <p>this generates the following properties:</p>
  89. *
  90. * <pre>
  91. * root-tag(myattr)=true
  92. * root-tag.inner-tag=Text
  93. * root-tag.inner-tag(someattr)=val
  94. * root-tag.a2.a3.a4=false
  95. * root-tag.x=x1,x2
  96. * </pre>
  97. *
  98. * <p>The <i>collapseAttributes</i> property of this task can be set
  99. * to true (the default is false) which will instead result in the
  100. * following properties (note the difference in names of properties
  101. * corresponding to XML attributes):</p>
  102. *
  103. * <pre>
  104. * root-tag.myattr=true
  105. * root-tag.inner-tag=Text
  106. * root-tag.inner-tag.someattr=val
  107. * root-tag.a2.a3.a4=false
  108. * root-tag.x=x1,x2
  109. * </pre>
  110. *
  111. * <p>Optionally, to more closely mirror the abilities of the Property
  112. * task, a selected set of attributes can be treated specially. To
  113. * enable this behavior, the "semanticAttributes" property of this task
  114. * must be set to true (it defaults to false). If this attribute is
  115. * specified, the following attributes take on special meaning
  116. * (setting this to true implicitly sets collapseAttributes to true as
  117. * well):</p>
  118. *
  119. * <ul>
  120. * <li><b>value</b>: Identifies a text value for a property.</li>
  121. * <li><b>location</b>: Identifies a file location for a property.</li>
  122. * <li><b>id</b>: Sets an id for a property</li>
  123. * <li><b>refid</b>: Sets a property to the value of another property
  124. * based upon the provided id</li>
  125. * <li><b>pathid</b>: Defines a path rather than a property with
  126. * the given id.</li>
  127. * </ul>
  128. *
  129. * <p>For example, with keepRoot = false, the following properties file:</p>
  130. *
  131. * <pre>
  132. * &lt;root-tag&gt;
  133. * &lt;build&gt;
  134. * &lt;build folder="build"&gt;
  135. * &lt;classes id="build.classes" location="${build.folder}/classes"/&gt;
  136. * &lt;reference refid="build.classes"/&gt;
  137. * &lt;/build&gt;
  138. * &lt;compile&gt;
  139. * &lt;classpath pathid="compile.classpath"&gt;
  140. * &lt;pathelement location="${build.classes}"/&gt;
  141. * &lt;/classpath&gt;
  142. * &lt;/compile&gt;
  143. * &lt;run-time&gt;
  144. * &lt;jars&gt;*.jar&lt;/jars&gt;
  145. * &lt;classpath pathid="run-time.classpath"&gt;
  146. * &lt;path refid="compile.classpath"/&gt;
  147. * &lt;pathelement path="${run-time.jars}"/&gt;
  148. * &lt;/classpath&gt;
  149. * &lt;/run-time&gt;
  150. * &lt;/root-tag&gt;
  151. * </pre>
  152. *
  153. * <p>is equivalent to the following entries in a build file:</p>
  154. *
  155. * <pre>
  156. * &lt;property name="build" location="build"/&gt;
  157. * &lt;property name="build.classes" location="${build.location}/classes"/&gt;
  158. * &lt;property name="build.reference" refid="build.classes"/&gt;
  159. *
  160. * &lt;property name="run-time.jars" value="*.jar/&gt;
  161. *
  162. * &lt;classpath id="compile.classpath"&gt;
  163. * &lt;pathelement location="${build.classes}"/&gt;
  164. * &lt;/classpath&gt;
  165. *
  166. * &lt;classpath id="run-time.classpath"&gt;
  167. * &lt;path refid="compile.classpath"/&gt;
  168. * &lt;pathelement path="${run-time.jars}"/&gt;
  169. * &lt;/classpath&gt;
  170. * </pre>
  171. *
  172. * <p> This task <i>requires</i> the following attributes:</p>
  173. *
  174. * <ul>
  175. * <li><b>file</b>: The name of the file to load.</li>
  176. * </ul>
  177. *
  178. * <p>This task supports the following attributes:</p>
  179. *
  180. * <ul>
  181. * <li><b>prefix</b>: Optionally specify a prefix applied to
  182. * all properties loaded. Defaults to an empty string.</li>
  183. * <li><b>keepRoot</b>: Indicate whether the root xml element
  184. * is kept as part of property name. Defaults to true.</li>
  185. * <li><b>validate</b>: Indicate whether the xml file is validated.
  186. * Defaults to false.</li>
  187. * <li><b>collapseAttributes</b>: Indicate whether attributes are
  188. * stored in property names with parens or with period
  189. * delimiters. Defaults to false, meaning properties
  190. * are stored with parens (i.e., foo(attr)).</li>
  191. * <li><b>semanticAttributes</b>: Indicate whether attributes
  192. * named "location", "value", "refid" and "path"
  193. * are interpreted as ant properties. Defaults
  194. * to false.</li>
  195. * <li><b>rootDirectory</b>: Indicate the directory to use
  196. * as the root directory for resolving location
  197. * properties. Defaults to the directory
  198. * of the project using the task.</li>
  199. * <li><b>includeSemanticAttribute</b>: Indicate whether to include
  200. * the semantic attribute ("location" or "value") as
  201. * part of the property name. Defaults to false.</li>
  202. * </ul>
  203. *
  204. * @author <a href="mailto:nicolaken@apache.org">Nicola Ken Barozzi</a>
  205. * @author Erik Hatcher
  206. * @author <a href="mailto:paul@priorartisans.com">Paul Christmann</a>
  207. *
  208. * @ant.task name="xmlproperty" category="xml"
  209. */
  210. public class XmlProperty extends org.apache.tools.ant.Task {
  211. private File src;
  212. private String prefix = "";
  213. private boolean keepRoot = true;
  214. private boolean validate = false;
  215. private boolean collapseAttributes = false;
  216. private boolean semanticAttributes = false;
  217. private boolean includeSemanticAttribute = false;
  218. private File rootDirectory = null;
  219. private FileUtils fileUtils = FileUtils.newFileUtils();
  220. private Hashtable addedAttributes = new Hashtable();
  221. private static final String ID = "id";
  222. private static final String REF_ID = "refid";
  223. private static final String LOCATION = "location";
  224. private static final String VALUE = "value";
  225. private static final String PATH = "path";
  226. private static final String PATHID = "pathid";
  227. private static final String[] ATTRIBUTES = new String[] {
  228. ID, REF_ID, LOCATION, VALUE, PATH, PATHID
  229. };
  230. /**
  231. * Constructor.
  232. */
  233. public XmlProperty() {
  234. super();
  235. }
  236. /**
  237. * Initializes the task.
  238. */
  239. public void init() {
  240. super.init();
  241. }
  242. /**
  243. * Run the task.
  244. * @throws BuildException The exception raised during task execution.
  245. * @todo validate the source file is valid before opening, print a better error message
  246. * @todo add a verbose level log message listing the name of the file being loaded
  247. */
  248. public void execute()
  249. throws BuildException {
  250. if (getFile() == null) {
  251. String msg = "XmlProperty task requires a file attribute";
  252. throw new BuildException(msg);
  253. }
  254. BufferedInputStream configurationStream = null;
  255. try {
  256. log("Loading " + src.getAbsolutePath(), Project.MSG_VERBOSE);
  257. if (src.exists()) {
  258. configurationStream =
  259. new BufferedInputStream(new FileInputStream(src));
  260. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  261. factory.setValidating(validate);
  262. factory.setNamespaceAware(false);
  263. Element topElement = factory.newDocumentBuilder().parse(configurationStream).getDocumentElement();
  264. // Keep a hashtable of attributes added by this task.
  265. // This task is allow to override its own properties
  266. // but not other properties. So we need to keep track
  267. // of which properties we've added.
  268. addedAttributes = new Hashtable();
  269. if (keepRoot) {
  270. addNodeRecursively(topElement, prefix, null);
  271. } else {
  272. NodeList topChildren = topElement.getChildNodes();
  273. int numChildren = topChildren.getLength();
  274. for (int i = 0; i < numChildren; i++) {
  275. addNodeRecursively(topChildren.item(i), prefix, null);
  276. }
  277. }
  278. } else {
  279. log("Unable to find property file: " + src.getAbsolutePath(),
  280. Project.MSG_VERBOSE);
  281. }
  282. } catch (SAXException sxe) {
  283. // Error generated during parsing
  284. Exception x = sxe;
  285. if (sxe.getException() != null)
  286. x = sxe.getException();
  287. throw new BuildException(x);
  288. } catch (ParserConfigurationException pce) {
  289. // Parser with specified options can't be built
  290. throw new BuildException(pce);
  291. } catch (IOException ioe) {
  292. // I/O error
  293. throw new BuildException(ioe);
  294. } finally {
  295. if (configurationStream != null) {
  296. try {
  297. configurationStream.close();
  298. } catch (Exception e) {
  299. }
  300. }
  301. }
  302. }
  303. /** Iterate through all nodes in the tree. */
  304. private void addNodeRecursively(Node node, String prefix,
  305. Object container) {
  306. // Set the prefix for this node to include its tag name.
  307. String nodePrefix = prefix;
  308. if (node.getNodeType() != Node.TEXT_NODE) {
  309. if (prefix.trim().length() > 0) {
  310. nodePrefix += ".";
  311. }
  312. nodePrefix += node.getNodeName();
  313. }
  314. // Pass the container to the processing of this node,
  315. Object nodeObject = processNode(node, nodePrefix, container);
  316. // now, iterate through children.
  317. if (node.hasChildNodes()) {
  318. NodeList nodeChildren = node.getChildNodes();
  319. int numChildren = nodeChildren.getLength();
  320. for (int i = 0; i < numChildren; i++) {
  321. // For each child, pass the object added by
  322. // processNode to its children -- in other word, each
  323. // object can pass information along to its children.
  324. addNodeRecursively(nodeChildren.item(i), nodePrefix,
  325. nodeObject);
  326. }
  327. }
  328. }
  329. void addNodeRecursively(org.w3c.dom.Node node, String prefix) {
  330. addNodeRecursively(node, prefix, null);
  331. }
  332. /**
  333. * Process the given node, adding any required attributes from
  334. * this child node alone -- but <em>not</em> processing any
  335. * children.
  336. *
  337. * @param node the XML Node to parse
  338. * @param prefix A string to prepend to any properties that get
  339. * added by this node.
  340. * @param container Optionally, an object that a parent node
  341. * generated that this node might belong to. For example, this
  342. * node could be within a node that generated a Path.
  343. * @return the Object created by this node. Generally, this is
  344. * either a String if this node resulted in setting an attribute,
  345. * or a Path.
  346. */
  347. public Object processNode (Node node, String prefix, Object container) {
  348. // Parse the attribute(s) and text of this node, adding
  349. // properties for each.
  350. // if the "path" attribute is specified, then return the created path
  351. // which will be passed to the children of this node.
  352. Object addedPath = null;
  353. // The value of an id attribute of this node.
  354. String id = null;
  355. if (node.hasAttributes()) {
  356. NamedNodeMap nodeAttributes = node.getAttributes();
  357. // Is there an id attribute?
  358. Node idNode = nodeAttributes.getNamedItem(ID);
  359. id = (semanticAttributes && idNode != null
  360. ? idNode.getNodeValue() : null);
  361. // Now, iterate through the attributes adding them.
  362. for (int i = 0; i < nodeAttributes.getLength(); i++) {
  363. Node attributeNode = nodeAttributes.item(i);
  364. if (!semanticAttributes) {
  365. String attributeName = getAttributeName(attributeNode);
  366. String attributeValue = getAttributeValue(attributeNode);
  367. addProperty(prefix + attributeName, attributeValue, null);
  368. } else {
  369. String nodeName = attributeNode.getNodeName();
  370. String attributeValue = getAttributeValue(attributeNode);
  371. Path containingPath =
  372. (container != null && container instanceof Path
  373. ? (Path) container : null );
  374. /*
  375. * The main conditional logic -- if the attribute
  376. * is somehow "special" (i.e., it has known
  377. * semantic meaning) then deal with it
  378. * appropriately.
  379. */
  380. if (nodeName.equals(ID)) {
  381. // ID has already been found above.
  382. continue;
  383. } else if (containingPath != null
  384. && nodeName.equals(PATH)) {
  385. // A "path" attribute for a node within a Path object.
  386. containingPath.setPath(attributeValue);
  387. } else if (container instanceof Path
  388. && nodeName.equals(REF_ID)) {
  389. // A "refid" attribute for a node within a Path object.
  390. containingPath.setPath(attributeValue);
  391. } else if (container instanceof Path
  392. && nodeName.equals(LOCATION)) {
  393. // A "location" attribute for a node within a
  394. // Path object.
  395. containingPath.setLocation(resolveFile(attributeValue));
  396. } else if (nodeName.equals(PATHID)) {
  397. // A node identifying a new path
  398. if (container != null) {
  399. throw new BuildException("XmlProperty does not "
  400. + "support nested paths");
  401. }
  402. addedPath = new Path(getProject());
  403. getProject().addReference(attributeValue, addedPath);
  404. } else {
  405. // An arbitrary attribute.
  406. String attributeName = getAttributeName(attributeNode);
  407. addProperty(prefix + attributeName, attributeValue, id);
  408. }
  409. }
  410. }
  411. }
  412. if (node.getNodeType() == Node.TEXT_NODE) {
  413. // If the containing object was a String, then use it as the ID.
  414. if (semanticAttributes && id == null
  415. && container instanceof String) {
  416. id = (String) container;
  417. }
  418. // For the text node, add a property.
  419. String nodeText = getAttributeValue(node);
  420. if (nodeText.trim().length() != 0) {
  421. addProperty(prefix, nodeText, id);
  422. }
  423. }
  424. // Return the Path we added or the ID of this node for
  425. // children to reference if needed. Path objects are
  426. // definitely used by child path elements, and ID may be used
  427. // for a child text node.
  428. return (addedPath != null ? addedPath : id);
  429. }
  430. /**
  431. * Actually add the given property/value to the project
  432. * after writing a log message.
  433. */
  434. private void addProperty (String name, String value, String id) {
  435. String msg = name + ":" + value;
  436. if (id != null) {
  437. msg += ("(id=" + id + ")");
  438. }
  439. log(msg, Project.MSG_DEBUG);
  440. if (addedAttributes.containsKey(name)) {
  441. // If this attribute was added by this task, then
  442. // we append this value to the existing value.
  443. // We use the setProperty method which will
  444. // forcibly override the property if it already exists.
  445. // We need to put these properties into the project
  446. // when we read them, though (instead of keeping them
  447. // outside of the project and batch adding them at the end)
  448. // to allow other properties to reference them.
  449. value = (String)addedAttributes.get(name) + "," + value;
  450. getProject().setProperty(name, value);
  451. } else {
  452. getProject().setNewProperty(name, value);
  453. }
  454. addedAttributes.put(name, value);
  455. if (id != null) {
  456. getProject().addReference(id, value);
  457. }
  458. }
  459. /**
  460. * Return a reasonable attribute name for the given node.
  461. * If we are using semantic attributes or collapsing
  462. * attributes, the returned name is ".nodename".
  463. * Otherwise, we return "(nodename)". This is long-standing
  464. * (and default) &lt;xmlproperty&gt; behavior.
  465. */
  466. private String getAttributeName (Node attributeNode) {
  467. String attributeName = attributeNode.getNodeName();
  468. if (semanticAttributes) {
  469. // Never include the "refid" attribute as part of the
  470. // attribute name.
  471. if (attributeName.equals(REF_ID)) {
  472. return "";
  473. // Otherwise, return it appended unless property to hide it is set.
  474. } else if (!isSemanticAttribute(attributeName)
  475. || includeSemanticAttribute) {
  476. return "." + attributeName;
  477. } else {
  478. return "";
  479. }
  480. } else if (collapseAttributes) {
  481. return "." + attributeName;
  482. } else {
  483. return "(" + attributeName + ")";
  484. }
  485. }
  486. /**
  487. * Return whether the provided attribute name is recognized or not.
  488. */
  489. private static boolean isSemanticAttribute (String attributeName) {
  490. for (int i=0;i<ATTRIBUTES.length;i++) {
  491. if (attributeName.equals(ATTRIBUTES[i])) {
  492. return true;
  493. }
  494. }
  495. return false;
  496. }
  497. /**
  498. * Return the value for the given attribute.
  499. * If we are not using semantic attributes, its just the
  500. * literal string value of the attribute.
  501. *
  502. * <p>If we <em>are</em> using semantic attributes, then first
  503. * dependent properties are resolved (i.e., ${foo} is resolved
  504. * based on the foo property value), and then an appropriate data
  505. * type is used. In particular, location-based properties are
  506. * resolved to absolute file names. Also for refid values, look
  507. * up the referenced object from the project.</p>
  508. */
  509. private String getAttributeValue (Node attributeNode) {
  510. String nodeValue = attributeNode.getNodeValue().trim();
  511. if (semanticAttributes) {
  512. String attributeName = attributeNode.getNodeName();
  513. nodeValue = getProject().replaceProperties(nodeValue);
  514. if (attributeName.equals(LOCATION)) {
  515. File f = resolveFile(nodeValue);
  516. return f.getPath();
  517. } else if (attributeName.equals(REF_ID)) {
  518. Object ref = getProject().getReference(nodeValue);
  519. if (ref != null) {
  520. return ref.toString();
  521. }
  522. }
  523. }
  524. return nodeValue;
  525. }
  526. /**
  527. * The XML file to parse; required.
  528. */
  529. public void setFile(File src) {
  530. this.src = src;
  531. }
  532. /**
  533. * the prefix to prepend to each property
  534. */
  535. public void setPrefix(String prefix) {
  536. this.prefix = prefix.trim();
  537. }
  538. /**
  539. * flag to include the xml root tag as a
  540. * first value in the property name; optional,
  541. * default is true
  542. */
  543. public void setKeeproot(boolean keepRoot) {
  544. this.keepRoot = keepRoot;
  545. }
  546. /**
  547. * flag to validate the XML file; optional, default false
  548. */
  549. public void setValidate(boolean validate) {
  550. this.validate = validate;
  551. }
  552. /**
  553. * flag to treat attributes as nested elements;
  554. * optional, default false
  555. */
  556. public void setCollapseAttributes(boolean collapseAttributes) {
  557. this.collapseAttributes = collapseAttributes;
  558. }
  559. public void setSemanticAttributes (boolean semanticAttributes) {
  560. this.semanticAttributes = semanticAttributes;
  561. }
  562. public void setRootDirectory (File rootDirectory) {
  563. this.rootDirectory = rootDirectory;
  564. }
  565. public void setIncludeSemanticAttribute (boolean includeSemanticAttribute) {
  566. this.includeSemanticAttribute = includeSemanticAttribute;
  567. }
  568. /* Expose members for extensibility */
  569. protected File getFile () {
  570. return this.src;
  571. }
  572. protected String getPrefix () {
  573. return this.prefix;
  574. }
  575. protected boolean getKeeproot () {
  576. return this.keepRoot;
  577. }
  578. protected boolean getValidate () {
  579. return this.validate;
  580. }
  581. protected boolean getCollapseAttributes () {
  582. return this.collapseAttributes;
  583. }
  584. protected boolean getSemanticAttributes () {
  585. return this.semanticAttributes;
  586. }
  587. protected File getRootDirectory () {
  588. return this.rootDirectory;
  589. }
  590. protected boolean getIncludeSementicAttribute () {
  591. return this.includeSemanticAttribute;
  592. }
  593. /**
  594. * Let project resolve the file - or do it ourselves if
  595. * rootDirectory has been set.
  596. */
  597. private File resolveFile(String fileName) {
  598. if (rootDirectory == null) {
  599. return getProject().resolveFile(fileName);
  600. }
  601. return fileUtils.resolveFile(rootDirectory, fileName);
  602. }
  603. }