Browse Source

Bug 21042 "Setting XSL parameter to input filename when processed whole directory."

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@422692 13f79535-47bb-0310-9956-ffa450edef68
master
Jan Materne 19 years ago
parent
commit
303b70f86b
9 changed files with 375 additions and 31 deletions
  1. +1
    -0
      CONTRIBUTORS
  2. +4
    -0
      contributors.xml
  3. +42
    -3
      docs/manual/CoreTasks/style.html
  4. +53
    -2
      src/etc/testcases/taskdefs/style/build.xml
  5. +22
    -0
      src/etc/testcases/taskdefs/style/printFilename.xsl
  6. +56
    -2
      src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java
  7. +20
    -8
      src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java
  8. +141
    -3
      src/main/org/apache/tools/ant/util/FileUtils.java
  9. +36
    -13
      src/testcases/org/apache/tools/ant/taskdefs/StyleTest.java

+ 1
- 0
CONTRIBUTORS View File

@@ -239,6 +239,7 @@ Tom Cunningham
Tom Dimock
Tom Eugelink
Ulrich Schmidt
Victor Toni
Waldek Herka
Will Wang
William Ferguson


+ 4
- 0
contributors.xml View File

@@ -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>


+ 42
- 3
docs/manual/CoreTasks/style.html View File

@@ -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
&lt;param name="set" expression="value"/&gt;
&lt;/xslt&gt;</pre>

<h4>Print the current processed file name</h4>
<pre>
&lt;project&gt;
&lt;xslt style=&quot;printFilename.xsl&quot; destdir=&quot;out&quot; basedir=&quot;in&quot; extension=&quot;.txt&quot;
filenameparameter=&quot;filename&quot;
filedirparameter=&quot;filedir&quot;
/&gt;
&lt;/project&gt;

&lt;xsl:stylesheet
version=&quot;1.0&quot;
xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;

&lt;xsl:param name=&quot;filename&quot;&gt;&lt;/xsl:param&gt;
&lt;xsl:param name=&quot;filedir&quot;&gt;.&lt;/xsl:param&gt;

&lt;xsl:template match=&quot;/&quot;&gt;
Current file is &lt;xsl:value-of select=&quot;$filename&quot;/&gt; in directory &lt;xsl:value-of select=&quot;$filedir&quot;/&gt;.
&lt;/xsl:template&gt;

&lt;/xsl:stylesheet&gt;
</pre>

</blockquote>
<hr>
<p align="center">Copyright &copy; 2000-2006 The Apache Software Foundation. All rights
Reserved.</p>

</body>
</html>
</html>

+ 53
- 2
src/etc/testcases/taskdefs/style/build.xml View File

@@ -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>

+ 22
- 0
src/etc/testcases/taskdefs/style/printFilename.xsl View File

@@ -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>

+ 56
- 2
src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java View File

@@ -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 {
}
}

}
}

+ 20
- 8
src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java View File

@@ -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());
}
}
}
}

+ 141
- 3
src/main/org/apache/tools/ant/util/FileUtils.java View File

@@ -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();
}

}

+ 36
- 13
src/testcases/org/apache/tools/ant/taskdefs/StyleTest.java View File

@@ -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);
}

}
}

Loading…
Cancel
Save