git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@422692 13f79535-47bb-0310-9956-ffa450edef68master
@@ -239,6 +239,7 @@ Tom Cunningham | |||
Tom Dimock | |||
Tom Eugelink | |||
Ulrich Schmidt | |||
Victor Toni | |||
Waldek Herka | |||
Will Wang | |||
William Ferguson | |||
@@ -950,6 +950,10 @@ | |||
<first>Ulrich</first> | |||
<last>Schmidt</last> | |||
</name> | |||
<name> | |||
<first>Victor</first> | |||
<last>Toni</last> | |||
</name> | |||
<name> | |||
<first>Will</first> | |||
<last>Wang</last> | |||
@@ -16,7 +16,7 @@ | |||
or for generating code.</p> | |||
<p><b>Note:</b> If you are using JDK 1.4 or higher, this task does not require external libraries | |||
not supplied in the Ant distribution. However, often the built in XSL engine is not as up | |||
to date as a fresh download, so an update is still highly recommended. | |||
to date as a fresh download, so an update is still highly recommended. | |||
See <a href="../install.html#librarydependencies">Library Dependencies</a> for more information.</p> | |||
<p>It is possible to refine the set of files that are being processed. This can be | |||
done with the <i>includes</i>, <i>includesfile</i>, <i>excludes</i>, <i>excludesfile</i> and <i>defaultexcludes</i> | |||
@@ -189,6 +189,22 @@ element which is used to perform Entity and URI resolution.</p> | |||
<em>Since Ant 1.7</em>.</td> | |||
<td valign="top" align="center">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">filenameparameter</td> | |||
<td valign="top">Specifies a xsl parameter for accessing the name | |||
of the current processed file. If not set, the file name is not | |||
passed to the transformation. | |||
<em>Since Ant 1.7</em>.</td> | |||
<td valign="top" align="center">No</td> | |||
</tr> | |||
<tr> | |||
<td valign="top">filedirparameter</td> | |||
<td valign="top">Specifies a xsl parameter for accessing the directory | |||
of the current processed file. If not set, the directory is not | |||
passed to the transformation. | |||
<em>Since Ant 1.7</em>.</td> | |||
<td valign="top" align="center">No</td> | |||
</tr> | |||
</table> | |||
<h3>Parameters specified as nested elements</h3> | |||
@@ -312,7 +328,7 @@ And in Saxon 7.x: | |||
<li>http://saxon.sf.net/feature/linenumbering (integer)</li> | |||
<li>...</li> | |||
</ul> | |||
<blockquote> | |||
<blockquote> | |||
<h4>Parameters</h4> | |||
<table width="60%" border="1" cellpadding="2" cellspacing="0"> | |||
<tr> | |||
@@ -417,10 +433,33 @@ See <a href="../CoreTypes/resources.html">resources</a> to see the concrete synt | |||
<param name="set" expression="value"/> | |||
</xslt></pre> | |||
<h4>Print the current processed file name</h4> | |||
<pre> | |||
<project> | |||
<xslt style="printFilename.xsl" destdir="out" basedir="in" extension=".txt" | |||
filenameparameter="filename" | |||
filedirparameter="filedir" | |||
/> | |||
</project> | |||
<xsl:stylesheet | |||
version="1.0" | |||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> | |||
<xsl:param name="filename"></xsl:param> | |||
<xsl:param name="filedir">.</xsl:param> | |||
<xsl:template match="/"> | |||
Current file is <xsl:value-of select="$filename"/> in directory <xsl:value-of select="$filedir"/>. | |||
</xsl:template> | |||
</xsl:stylesheet> | |||
</pre> | |||
</blockquote> | |||
<hr> | |||
<p align="center">Copyright © 2000-2006 The Apache Software Foundation. All rights | |||
Reserved.</p> | |||
</body> | |||
</html> | |||
</html> |
@@ -11,6 +11,7 @@ | |||
<target name="teardown"> | |||
<delete dir="${out.dir}" failonerror="false" /> | |||
</target> | |||
<target name="testStyleIsSet"> | |||
<xslt in="data.xml" out="${out.dir}/out.xml"/> | |||
@@ -128,5 +129,55 @@ | |||
<param name="set" expression="value"/> | |||
</xslt> | |||
</target> | |||
</project> | |||
<target name="testFilenameAndFiledirAsParam"> | |||
<mkdir dir="${out.dir}/xml/dir"/> | |||
<mkdir dir="${out.dir}/out"/> | |||
<copy file="data.xml" tofile="${out.dir}/xml/one.xml"/> | |||
<copy file="data.xml" tofile="${out.dir}/xml/two.xml"/> | |||
<copy file="data.xml" tofile="${out.dir}/xml/three.xml"/> | |||
<copy file="data.xml" tofile="${out.dir}/xml/dir/four.xml"/> | |||
<xslt style="printFilename.xsl" | |||
destdir="${out.dir}/out" | |||
basedir="${out.dir}/xml" | |||
includes="**/*.xml" | |||
extension=".txt" | |||
filenameparameter="filename" | |||
filedirparameter="filedir" | |||
/> | |||
</target> | |||
<target name="testFilenameAsParam"> | |||
<mkdir dir="${out.dir}/xml/dir"/> | |||
<mkdir dir="${out.dir}/out"/> | |||
<copy file="data.xml" tofile="${out.dir}/xml/one.xml"/> | |||
<copy file="data.xml" tofile="${out.dir}/xml/two.xml"/> | |||
<copy file="data.xml" tofile="${out.dir}/xml/three.xml"/> | |||
<copy file="data.xml" tofile="${out.dir}/xml/dir/four.xml"/> | |||
<xslt style="printFilename.xsl" | |||
destdir="${out.dir}/out" | |||
basedir="${out.dir}/xml" | |||
includes="**/*.xml" | |||
extension=".txt" | |||
filenameparameter="filename" | |||
/> | |||
</target> | |||
<target name="testFilenameAsParamNoSetting"> | |||
<mkdir dir="${out.dir}/xml/dir"/> | |||
<mkdir dir="${out.dir}/out"/> | |||
<copy file="data.xml" tofile="${out.dir}/xml/one.xml"/> | |||
<copy file="data.xml" tofile="${out.dir}/xml/two.xml"/> | |||
<copy file="data.xml" tofile="${out.dir}/xml/three.xml"/> | |||
<copy file="data.xml" tofile="${out.dir}/xml/dir/four.xml"/> | |||
<xslt style="printFilename.xsl" | |||
destdir="${out.dir}/out" | |||
basedir="${out.dir}/xml" | |||
includes="**/*.xml" | |||
extension=".txt" | |||
/> <!-- without 'filenameparameter' to check, that the xsl:param is NOT set --> | |||
</target> | |||
</project> |
@@ -0,0 +1,22 @@ | |||
<?xml version="1.0"?> | |||
<xsl:stylesheet | |||
version="1.0" | |||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> | |||
<xsl:output indent="no" method="text"/> | |||
<xsl:strip-space elements="*"/> | |||
<xsl:param name="filename">-not-set-</xsl:param> | |||
<xsl:param name="filedir">-not-set-</xsl:param> | |||
<!-- use the xsl-parameter --> | |||
<xsl:template match="/"> | |||
filename='<xsl:value-of select="$filename"/>' | |||
filedir ='<xsl:value-of select="$filedir"/>' | |||
</xsl:template> | |||
<!-- delete the raw xml data --> | |||
<xsl:template match="*"/> | |||
</xsl:stylesheet> |
@@ -63,6 +63,12 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { | |||
/** extension of the files produced by XSL processing */ | |||
private String targetExtension = ".html"; | |||
/** name for XSL parameter containing the filename */ | |||
private String fileNameParameter = null; | |||
/** name for XSL parameter containing the file directory */ | |||
public String fileDirParameter = null; | |||
/** additional parameters to be passed to the stylesheets */ | |||
private Vector params = new Vector(); | |||
@@ -472,6 +478,28 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { | |||
this.xmlCatalog.addConfiguredXMLCatalog(xmlCatalog); | |||
} | |||
/** | |||
* Pass the filename of the current processed file as a xsl parameter | |||
* to the transformation. This value sets the name of that xsl parameter. | |||
* | |||
* @param fileNameParameter name of the xsl parameter retrieving the | |||
* current file name | |||
*/ | |||
public void setFileNameParameter(String fileNameParameter) { | |||
this.fileNameParameter = fileNameParameter; | |||
} | |||
/** | |||
* Pass the directory name of the current processed file as a xsl parameter | |||
* to the transformation. This value sets the name of that xsl parameter. | |||
* | |||
* @param fileDirParameter name of the xsl parameter retrieving the | |||
* current file directory | |||
*/ | |||
public void setFileDirParameter(String fileDirParameter) { | |||
this.fileDirParameter = fileDirParameter; | |||
} | |||
/** | |||
* Load processor here instead of in setProcessor - this will be | |||
* called from within execute, so we have access to the latest | |||
@@ -623,6 +651,7 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { | |||
log("Processing " + inF + " to " + outF); | |||
configureLiaison(stylesheet); | |||
setLiaisonDynamicFileParameters(liaison, inF); | |||
liaison.transform(inF, outF); | |||
} | |||
} catch (Exception ex) { | |||
@@ -662,6 +691,7 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { | |||
log("Processing " + inFile + " to " + outFile, | |||
Project.MSG_INFO); | |||
configureLiaison(stylesheet); | |||
setLiaisonDynamicFileParameters(liaison, inFile); | |||
liaison.transform(inFile, outFile); | |||
} else { | |||
log("Skipping input file " + inFile | |||
@@ -721,7 +751,6 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { | |||
return outputProperties.elements(); | |||
} | |||
/** | |||
* Get the Liason implementation to use in processing. | |||
* | |||
@@ -993,6 +1022,31 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { | |||
} | |||
} | |||
/** | |||
* Sets file parameter(s) for directory and filename if the attribute | |||
* 'filenameparameter' or 'filedirparameter' are set in the task. | |||
* | |||
* @param liaison to change parameters for | |||
* @param inFile to get the additional file information from | |||
* @throws Exception if an exception occurs on filename lookup | |||
* | |||
* @since Ant 1.7 | |||
*/ | |||
private void setLiaisonDynamicFileParameters( | |||
XSLTLiaison liaison, | |||
File inFile | |||
) throws Exception { | |||
String fileName = FileUtils.getRelativePath(baseDir, inFile); | |||
File file = new File(fileName); | |||
if (fileNameParameter != null) { | |||
liaison.addParam(fileNameParameter, inFile.getName()); | |||
} | |||
if (fileDirParameter != null) { | |||
liaison.addParam(fileDirParameter, (file.getParent()!=null) ? file.getParent() : "" ); | |||
} | |||
} | |||
/** | |||
* Create the factory element to configure a trax liaison. | |||
* @return the newly created factory element. | |||
@@ -1148,4 +1202,4 @@ public class XSLTProcess extends MatchingTask implements XSLTLogger { | |||
} | |||
} | |||
} | |||
} |
@@ -25,6 +25,7 @@ import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.util.Hashtable; | |||
import java.util.Vector; | |||
import java.util.Enumeration; | |||
import java.net.URL; | |||
@@ -114,7 +115,7 @@ public class TraXLiaison implements XSLTLiaison3, ErrorListener, XSLTLoggerAware | |||
private Vector outputProperties = new Vector(); | |||
/** stylesheet parameters */ | |||
private Vector params = new Vector(); | |||
private Hashtable params = new Hashtable(); | |||
/** factory attributes */ | |||
private Vector attributes = new Vector(); | |||
@@ -177,6 +178,11 @@ public class TraXLiaison implements XSLTLiaison3, ErrorListener, XSLTLoggerAware | |||
// not sure what could be the need of this... | |||
res.setSystemId(JAXPUtils.getSystemId(outfile)); | |||
Source src = getSource(fis, infile); | |||
// set parameters on each transformation, maybe something has changed | |||
//(e.g. value of file name parameter) | |||
setTransformationParameters(); | |||
transformer.transform(src, res); | |||
} finally { | |||
// make sure to close all handles, otherwise the garbage | |||
@@ -320,16 +326,23 @@ public class TraXLiaison implements XSLTLiaison3, ErrorListener, XSLTLoggerAware | |||
if (uriResolver != null) { | |||
transformer.setURIResolver(uriResolver); | |||
} | |||
for (int i = 0; i < params.size(); i++) { | |||
final String[] pair = (String[]) params.elementAt(i); | |||
transformer.setParameter(pair[0], pair[1]); | |||
} | |||
for (int i = 0; i < outputProperties.size(); i++) { | |||
final String[] pair = (String[]) outputProperties.elementAt(i); | |||
transformer.setOutputProperty(pair[0], pair[1]); | |||
} | |||
} | |||
/** | |||
* Sets the paramters for the transformer. | |||
*/ | |||
private void setTransformationParameters() { | |||
for (final Enumeration enumeration = params.keys(); enumeration.hasMoreElements(); ) { | |||
final String name = (String) enumeration.nextElement(); | |||
final String value = (String) params.get(name); | |||
transformer.setParameter(name, value); | |||
} | |||
} | |||
/** | |||
* return the Transformer factory associated to this liaison. | |||
* @return the Transformer factory associated to this liaison. | |||
@@ -426,8 +439,7 @@ public class TraXLiaison implements XSLTLiaison3, ErrorListener, XSLTLoggerAware | |||
* @param value the value of the parameter | |||
*/ | |||
public void addParam(String name, String value) { | |||
final String[] pair = new String[]{name, value}; | |||
params.addElement(pair); | |||
params.put(name, value); | |||
} | |||
/** | |||
@@ -552,4 +564,4 @@ public class TraXLiaison implements XSLTLiaison3, ErrorListener, XSLTLoggerAware | |||
setOutputProperty(prop.getName(), prop.getValue()); | |||
} | |||
} | |||
} | |||
} |
@@ -27,6 +27,10 @@ import java.io.OutputStream; | |||
import java.net.MalformedURLException; | |||
import java.net.URL; | |||
import java.text.DecimalFormat; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.Iterator; | |||
import java.util.List; | |||
import java.util.Random; | |||
import java.util.Stack; | |||
import java.util.StringTokenizer; | |||
@@ -85,7 +89,7 @@ public class FileUtils { | |||
* | |||
* @return a new instance of FileUtils. | |||
* @deprecated since 1.7. | |||
* Use getFileUtils instead, | |||
* Use getFileUtils instead, | |||
* FileUtils do not have state. | |||
*/ | |||
public static FileUtils newFileUtils() { | |||
@@ -617,7 +621,7 @@ public class FileUtils { | |||
* | |||
* @return the native version of the specified path or | |||
* an empty string if the path is <code>null</code> or empty. | |||
* | |||
* | |||
* @since ant 1.7 | |||
* @see PathTokenizer | |||
*/ | |||
@@ -1342,5 +1346,139 @@ public class FileUtils { | |||
file.delete(); | |||
} | |||
} | |||
} | |||
/** | |||
* Calculates the relative path between to files. | |||
* <p> | |||
* Implementation note:<br/> This function my throw an IOException if an | |||
* I/O error occurs because its use of the canonical pathname may require | |||
* filesystem queries. | |||
* </p> | |||
* | |||
* @param fromFile | |||
* the <code>File</code> to calculate the path from | |||
* @param toFile | |||
* the <code>File</code> to calculate the path to | |||
* @return | |||
* @throws Exception | |||
* @see {@link File#getCanonicalPath()} | |||
* | |||
* @since Ant 1.7 | |||
*/ | |||
public static String getRelativePath( | |||
File fromFile, | |||
File toFile | |||
) throws Exception { | |||
String fromPath = fromFile.getCanonicalPath(); | |||
String toPath = toFile.getCanonicalPath(); | |||
// build the path stack info to compare | |||
String[] fromPathStack = getPathStack(fromPath); | |||
String[] toPathStack = getPathStack(toPath); | |||
if (0 < toPathStack.length && 0 < fromPathStack.length) { | |||
if (!fromPathStack[0].equals(toPathStack[0])) { | |||
// not the same device (would be "" on Linux/Unix) | |||
return getPath(Arrays.asList(toPathStack)); | |||
} | |||
} else { | |||
// no comparison possible | |||
return getPath(Arrays.asList(toPathStack)); | |||
} | |||
int minLength = Math | |||
.min(fromPathStack.length, toPathStack.length); | |||
int same = 1; | |||
// get index of parts which are equal | |||
for (; same < minLength; same++) { | |||
if (!fromPathStack[same].equals(toPathStack[same])) { | |||
break; | |||
} | |||
} | |||
List relativePathStack = new ArrayList(); | |||
// if "from" part is longer, fill it up with ".." | |||
// to reach path which is equal to both paths | |||
for (int i = same; i < fromPathStack.length; i++) { | |||
relativePathStack.add(".."); | |||
} | |||
// fill it up path with parts which were not equal | |||
for (int i = same; i < toPathStack.length; i++) { | |||
relativePathStack.add(toPathStack[i]); | |||
} | |||
return getPath(relativePathStack); | |||
} | |||
/** | |||
* Gets all names of the path as an array of <code>String</code>s. | |||
* | |||
* @param path | |||
* to get names from | |||
* @return <code>String</code>s, never <code>null</code> | |||
* | |||
* @since Ant 1.7 | |||
*/ | |||
public static String[] getPathStack(String path) { | |||
String normalizedPath = path.replace(File.separatorChar, '/'); | |||
// since Java 1.4 | |||
//return normalizedPath.split("/"); | |||
// workaround for Java 1.2-1.3 | |||
Object[] tokens = StringUtils.split(normalizedPath, '/').toArray(); | |||
String[] rv = new String[tokens.length]; | |||
System.arraycopy(tokens, 0, rv, 0, tokens.length); | |||
return rv; | |||
} | |||
/** | |||
* Gets path from a <code>List</code> of <code>String</code>s. | |||
* | |||
* @param pathStack | |||
* <code>List</code> of <code>String</code>s to be concated | |||
* as a path. | |||
* @return <code>String</code>, never <code>null</code> | |||
* | |||
* @since Ant 1.7 | |||
*/ | |||
public static String getPath(List pathStack) { | |||
// can safely use '/' because Windows understands '/' as separator | |||
return getPath(pathStack, '/'); | |||
} | |||
/** | |||
* Gets path from a <code>List</code> of <code>String</code>s. | |||
* | |||
* @param pathStack | |||
* <code>List</code> of <code>String</code>s to be concated | |||
* as a path. | |||
* @param separatorChar | |||
* <code>char</code> to be used as separator between names in | |||
* path | |||
* @return <code>String</code>, never <code>null</code> | |||
* | |||
* @since Ant 1.7 | |||
*/ | |||
public static String getPath(final List pathStack, final char separatorChar) { | |||
final StringBuffer buffer = new StringBuffer(); | |||
final Iterator iter = pathStack.iterator(); | |||
if (iter.hasNext()) { | |||
buffer.append(iter.next()); | |||
} | |||
while (iter.hasNext()) { | |||
buffer.append(separatorChar); | |||
buffer.append(iter.next()); | |||
} | |||
return buffer.toString(); | |||
} | |||
} |
@@ -86,7 +86,6 @@ public class StyleTest extends BuildFileTest { | |||
"new-value"); | |||
} | |||
public void testDefaultMapper() throws Exception { | |||
testDefaultMapper("testDefaultMapper"); | |||
} | |||
@@ -149,6 +148,32 @@ public class StyleTest extends BuildFileTest { | |||
expectFileContains("testWithUrlResource", "out/out.xml", "set='value'"); | |||
} | |||
public void testFilenameAsParam() throws Exception { | |||
executeTarget("testFilenameAsParam"); | |||
assertFileContains("out/out/one.txt", "filename='one.xml'"); | |||
assertFileContains("out/out/two.txt", "filename='two.xml'"); | |||
assertFileContains("out/out/three.txt", "filename='three.xml'"); | |||
assertFileContains("out/out/dir/four.txt", "filename='four.xml'"); | |||
assertFileContains("out/out/dir/four.txt", "filedir ='-not-set-'"); | |||
} | |||
public void testFilenameAsParamNoSetting() throws Exception { | |||
executeTarget("testFilenameAsParamNoSetting"); | |||
assertFileContains("out/out/one.txt", "filename='-not-set-'"); | |||
assertFileContains("out/out/two.txt", "filename='-not-set-'"); | |||
assertFileContains("out/out/three.txt", "filename='-not-set-'"); | |||
assertFileContains("out/out/dir/four.txt", "filename='-not-set-'"); | |||
} | |||
public void testFilenameAndFiledirAsParam() throws Exception { | |||
executeTarget("testFilenameAndFiledirAsParam"); | |||
assertFileContains("out/out/one.txt", "filename='one.xml'"); | |||
assertFileContains("out/out/one.txt", "filedir =''"); | |||
assertFileContains("out/out/dir/four.txt", "filename='four.xml'"); | |||
assertFileContains("out/out/dir/four.txt", "filedir ='dir'"); | |||
} | |||
// ************* copied from ConcatTest ************* | |||
// ------------------------------------------------------ | |||
@@ -166,25 +191,23 @@ public class StyleTest extends BuildFileTest { | |||
finally { | |||
FileUtils.close(r); | |||
} | |||
} | |||
private String getFileString(String target, String filename) | |||
private void expectFileContains( | |||
String target, String filename, String contains) | |||
throws IOException | |||
{ | |||
executeTarget(target); | |||
return getFileString(filename); | |||
assertFileContains(filename, contains); | |||
} | |||
private void expectFileContains( | |||
String target, String filename, String contains) | |||
throws IOException | |||
{ | |||
String content = getFileString(target, filename); | |||
private void assertFileContains(String filename, String contains) throws IOException { | |||
String content = getFileString(filename); | |||
assertTrue( | |||
"expecting file " + filename + " to contain " + | |||
contains + | |||
" but got " + content, content.indexOf(contains) > -1); | |||
"expecting file " + filename | |||
+ " to contain " + contains | |||
+ " but got " + content, | |||
content.indexOf(contains) > -1); | |||
} | |||
} | |||
} |