ASF Bugzilla – Attachment 30943 Details for
Bug 21525
[PATCH] XSLT/param@expression used as string instead of as expression as documented
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
improved patch - adds documentation and tests
xslt-param-types-4.diff (text/plain), 21.85 KB, created by
František Kučera <xkucf03/>
on 2013-10-18 18:56:38 UTC
(
hide
)
Description:
improved patch - adds documentation and tests
Filename:
MIME Type:
Creator:
František Kučera <xkucf03/>
Created:
2013-10-18 18:56:38 UTC
Size:
21.85 KB
patch
obsolete
>Index: src/tests/antunit/taskdefs/xslt-test.xml >=================================================================== >--- src/tests/antunit/taskdefs/xslt-test.xml (revision 1532335) >+++ src/tests/antunit/taskdefs/xslt-test.xml (working copy) >@@ -34,7 +34,47 @@ > resource="${output}/out.xml" > value="set='myvalue'"/> > </target> >+ >+ <target name="testParameterTypes" depends="setUp" description="parameters of various data types and XPath expressions"> > >+ <property name="antProperty1" value="ANT_PROPERTY_1"/> >+ <property name="antProperty2" value="ANT_PROPERTY_2"/> >+ <property name="antProperty3" value="3"/> >+ <property name="antProperty4" value="substring-before"/> >+ >+ <xslt in="${legacy.dir}/data.xml" >+ out="${output}/out.xml"> >+ <param name="p1" expression="123" type="INT"/> >+ <param name="p2" expression="64 * 64 div 128 + 10" type="XPATH_NUMBER"/> >+ <param name="p3" expression="${antProperty4}($antProperty2, '_')" type="XPATH_STRING"/> >+ >+ <style> >+ <string><![CDATA[<xsl:stylesheet >+ version="1.0" >+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >+ xmlns:fo="http://www.w3.org/1999/XSL/Format"> >+ >+<!-- get the xsl-parameter --> >+<xsl:param name="p1"/> >+<xsl:param name="p2"/> >+<xsl:param name="p3"/> >+ >+<!-- use the xsl-parameter --> >+<xsl:template match="/"> >+p1_result='<xsl:value-of select="$p1 + 321"/>' >+p2_result='<xsl:value-of select="$p2"/>' >+p3_result='<xsl:value-of select="$p3"/>' >+</xsl:template> >+ >+</xsl:stylesheet> >+]]></string> >+ </style> >+ </xslt> >+ <au:assertResourceContains resource="${output}/out.xml" value="p1_result='444'"/> >+ <au:assertResourceContains resource="${output}/out.xml" value="p2_result='42'"/> >+ <au:assertResourceContains resource="${output}/out.xml" value="p3_result='ANT'"/> >+ </target> >+ > <target name="testInlineStyleSheet" depends="setUp"> > <xslt in="${legacy.dir}/data.xml" > out="${output}/out.xml"> >Index: src/main/org/apache/tools/ant/taskdefs/XSLTLiaison4.java >=================================================================== >--- src/main/org/apache/tools/ant/taskdefs/XSLTLiaison4.java (revision 0) >+++ src/main/org/apache/tools/ant/taskdefs/XSLTLiaison4.java (working copy) >@@ -0,0 +1,41 @@ >+/* >+ * Licensed to the Apache Software Foundation (ASF) under one or more >+ * contributor license agreements. See the NOTICE file distributed with >+ * this work for additional information regarding copyright ownership. >+ * The ASF licenses this file to You under the Apache License, Version 2.0 >+ * (the "License"); you may not use this file except in compliance with >+ * the License. You may obtain a copy of the License at >+ * >+ * http://www.apache.org/licenses/LICENSE-2.0 >+ * >+ * Unless required by applicable law or agreed to in writing, software >+ * distributed under the License is distributed on an "AS IS" BASIS, >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. >+ * See the License for the specific language governing permissions and >+ * limitations under the License. >+ * >+ */ >+package org.apache.tools.ant.taskdefs; >+ >+/** >+ * Extends Proxy interface for XSLT processors: adds support for XSLT parameters >+ * of various types (not only String) >+ * >+ * >+ * @see XSLTProcess >+ * @author Frantisek Kucera (xkucf03) >+ * @since Ant 1.9.3 >+ */ >+public interface XSLTLiaison4 extends XSLTLiaison3 { >+ >+ /** >+ * Add a parameter to be set during the XSL transformation. >+ * >+ * @param name the parameter name. >+ * @param value the parameter value as String, Boolean, int, etc. >+ * @throws Exception thrown if any problems happens. >+ * @since Ant 1.9.3 >+ * @see Transformer#setParameter(java.lang.String, java.lang.Object) >+ */ >+ void addParam(String name, Object value) throws Exception; >+} >Index: src/main/org/apache/tools/ant/taskdefs/XSLTLiaison.java >=================================================================== >--- src/main/org/apache/tools/ant/taskdefs/XSLTLiaison.java (revision 1532335) >+++ src/main/org/apache/tools/ant/taskdefs/XSLTLiaison.java (working copy) >@@ -51,6 +51,7 @@ > * @param name the parameter name. > * @param expression the parameter value as an expression string. > * @throws Exception thrown if any problems happens. >+ * @see XSLTLiaison4#addParam(java.lang.String, java.lang.Object) > * @since Ant 1.3 > */ > void addParam(String name, String expression) throws Exception; >Index: src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java >=================================================================== >--- src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java (revision 1532335) >+++ src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java (working copy) >@@ -18,8 +18,20 @@ > package org.apache.tools.ant.taskdefs; > > import java.io.File; >+import java.util.ArrayList; >+import java.util.Collections; >+import java.util.EnumMap; > import java.util.Enumeration; >+import java.util.List; >+import java.util.Map; > import java.util.Vector; >+import javax.xml.namespace.QName; >+import javax.xml.xpath.XPath; >+import javax.xml.xpath.XPathConstants; >+import javax.xml.xpath.XPathExpression; >+import javax.xml.xpath.XPathExpressionException; >+import javax.xml.xpath.XPathFactory; >+import javax.xml.xpath.XPathVariableResolver; > import org.apache.tools.ant.AntClassLoader; > import org.apache.tools.ant.BuildException; > import org.apache.tools.ant.DirectoryScanner; >@@ -76,7 +88,7 @@ > private String fileDirParameter = null; > > /** additional parameters to be passed to the stylesheets */ >- private Vector params = new Vector(); >+ private List<Param> params = new ArrayList<Param>(); > > /** Input XML document to be used */ > private File inFile = null; >@@ -196,6 +208,19 @@ > * @since Ant 1.8.0 > */ > private boolean failOnNoResources = true; >+ >+ /** >+ * For evaluating template params >+ * >+ * @since Ant 1.9.3 >+ */ >+ private XPathFactory xpathFactory; >+ /** >+ * For evaluating template params >+ * >+ * @since Ant 1.9.3 >+ */ >+ private XPath xpath; > > /** > * System properties to set during transformation. >@@ -305,8 +330,9 @@ > * Executes the task. > * > * @exception BuildException if there is an execution problem. >- * @todo validate that if either in or our is defined, then both are >+ * @todo validate that if either in or out is defined, then both are > */ >+ @Override > public void execute() throws BuildException { > if ("style".equals(getTaskType())) { > log("Warning: the task name <style> is deprecated. Use <xslt> instead.", >@@ -937,7 +963,7 @@ > */ > public Param createParam() { > Param p = new Param(); >- params.addElement(p); >+ params.add(p); > return p; > } > >@@ -950,6 +976,12 @@ > > /** The parameter's value */ > private String expression = null; >+ >+ /** >+ * Type of the expression. >+ * @see ParamType >+ */ >+ private String type; > > private Object ifCond; > private Object unlessCond; >@@ -974,15 +1006,24 @@ > } > > /** >- * The parameter value >- * NOTE : was intended to be an XSL expression. >- * @param expression the parameter's value. >+ * The parameter value - >+ * can be a primitive type value or an XPath expression. >+ * @param expression the parameter's value/expression. >+ * @see #setType(java.lang.String) > */ > public void setExpression(String expression) { > this.expression = expression; > } > > /** >+ * @see ParamType >+ * @since Ant 1.9.3 >+ */ >+ public void setType(String type) { >+ this.type = type; >+ } >+ >+ /** > * Get the parameter name > * > * @return the parameter name >@@ -1000,6 +1041,7 @@ > * > * @return the parameter value > * @exception BuildException if the value is not set. >+ * @see #getType() > */ > public String getExpression() throws BuildException { > if (expression == null) { >@@ -1009,6 +1051,14 @@ > } > > /** >+ * @see ParamType >+ * @since Ant 1.9.3 >+ */ >+ public String getType() { >+ return type; >+ } >+ >+ /** > * Set whether this param should be used. It will be used if > * the expression evaluates to true or the name of a property > * which has been set, otherwise it won't. >@@ -1061,7 +1111,58 @@ > && ph.testUnlessCondition(unlessCond); > } > } // Param >+ >+ /** >+ * Enum for types of the parameter expression. >+ * >+ * <p>The expression can be:</p> >+ * <ul> >+ * <li>primitive type that will be parsed from the string value e.g. >+ * {@linkplain Integer#parseInt(java.lang.String)}</li> >+ * <li>XPath expression that will be evaluated (outside of the transformed >+ * document - on empty one) and casted to given type. Inside XPath >+ * expressions the Ant variables (properties) can be used (as XPath >+ * variables - e.g. $variable123). n.b. placeholders in form of >+ * ${variable123} will be substituted with their values before evaluating the >+ * XPath expression (so it can be used for dynamic XPath function names and >+ * other hacks).</li> >+ * </ul> >+ * <p>The parameter will be then passed to the XSLT template.</p> >+ * >+ * <p>Default type (if omited) is primitive String. So if the expression is e.g >+ * "true" with no type, in XSLT it will be only a text string, not true >+ * boolean.</p> >+ * >+ * @see Param#setType(java.lang.String) >+ * @see Param#setExpression(java.lang.String) >+ * @since Ant 1.9.3 >+ */ >+ public enum ParamType { > >+ STRING, >+ BOOLEAN, >+ INT, >+ LONG, >+ DOUBLE, >+ XPATH_STRING, >+ XPATH_BOOLEAN, >+ XPATH_NUMBER, >+ XPATH_NODE, >+ XPATH_NODESET; >+ >+ public static final Map<ParamType, QName> XPATH_TYPES; >+ >+ static { >+ Map<ParamType, QName> m = new EnumMap<ParamType, QName>(ParamType.class); >+ m.put(XPATH_STRING, XPathConstants.STRING); >+ m.put(XPATH_BOOLEAN, XPathConstants.BOOLEAN); >+ m.put(XPATH_NUMBER, XPathConstants.NUMBER); >+ m.put(XPATH_NODE, XPathConstants.NODE); >+ m.put(XPATH_NODESET, XPathConstants.NODESET); >+ XPATH_TYPES = Collections.unmodifiableMap(m); >+ } >+ } >+ > /** > * Create an instance of an output property to be configured. > * @return the newly created output property. >@@ -1119,12 +1220,22 @@ > } > > /** >- * Initialize internal instance of XMLCatalog >+ * Initialize internal instance of XMLCatalog. >+ * Initialize XPath for parameter evaluation. > * @throws BuildException on error > */ >+ @Override > public void init() throws BuildException { > super.init(); > xmlCatalog.setProject(getProject()); >+ >+ xpathFactory = XPathFactory.newInstance(); >+ xpath = xpathFactory.newXPath(); >+ xpath.setXPathVariableResolver(new XPathVariableResolver() { >+ public Object resolveVariable(QName variableName) { >+ return getProject().getProperty(variableName.toString()); >+ } >+ }); > } > > /** >@@ -1179,10 +1290,21 @@ > return; > } > } >- for (Enumeration e = params.elements(); e.hasMoreElements();) { >- Param p = (Param) e.nextElement(); >+ for (Param p : params) { > if (p.shouldUse()) { >- liaison.addParam(p.getName(), p.getExpression()); >+ Object evaluatedParam = evaluateParam(p); >+ if (liaison instanceof XSLTLiaison4) { >+ ((XSLTLiaison4)liaison).addParam(p.getName(), evaluatedParam); >+ } else { >+ if (evaluatedParam == null || evaluatedParam instanceof String) { >+ liaison.addParam(p.getName(), (String)evaluatedParam); >+ } else { >+ log("XSLTLiaison '" + liaison.getClass().getName() >+ + "' supports only String parameters. Converting parameter '" + p.getName() >+ + "' to its String value '" + evaluatedParam, Project.MSG_WARN); >+ liaison.addParam(p.getName(), String.valueOf(evaluatedParam)); >+ } >+ } > } > } > } catch (Exception ex) { >@@ -1190,7 +1312,57 @@ > handleTransformationError(ex); > } > } >+ >+ /** >+ * Evaluates parameter expression according to its type. >+ * >+ * @param param parameter from Ant build file >+ * @return value to be passed to XSLT as parameter >+ * @throws IllegalArgumentException if param type is unsupported >+ * @throws NumberFormatException if expression of numeric type is not >+ * desired numeric type >+ * @throws XPathExpressionException if XPath expression can not be compiled >+ * @since Ant 1.9.3 >+ */ >+ private Object evaluateParam(Param param) throws XPathExpressionException { >+ String typeName = param.getType(); >+ String expression = param.getExpression(); > >+ ParamType type; >+ >+ if (typeName == null || typeName.isEmpty()) { >+ type = ParamType.STRING; // String is default >+ } else { >+ try { >+ type = ParamType.valueOf(typeName); >+ } catch (IllegalArgumentException e) { >+ throw new IllegalArgumentException("Invalid XSLT parameter type: " + typeName, e); >+ } >+ } >+ >+ switch (type) { >+ case STRING: >+ return expression; >+ case BOOLEAN: >+ return Boolean.parseBoolean(expression); >+ case DOUBLE: >+ return Double.parseDouble(expression); >+ case INT: >+ return Integer.parseInt(expression); >+ case LONG: >+ return Long.parseLong(expression); >+ default: // XPath expression >+ QName xpathType = ParamType.XPATH_TYPES.get(type); >+ if (xpathType == null) { >+ throw new IllegalArgumentException("Invalid XSLT parameter type: " + typeName); >+ } else { >+ XPathExpression xpe = xpath.compile(expression); >+ // null = evaluate XPath on empty XML document >+ return xpe.evaluate((Object) null, xpathType); >+ } >+ } >+ } >+ > /** > * Sets file parameter(s) for directory and filename if the attribute > * 'filenameparameter' or 'filedirparameter' are set in the task. >Index: src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java >=================================================================== >--- src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java (revision 1532335) >+++ src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java (working copy) >@@ -47,7 +47,7 @@ > import javax.xml.transform.TransformerConfigurationException; > import org.apache.tools.ant.BuildException; > import org.apache.tools.ant.Project; >-import org.apache.tools.ant.taskdefs.XSLTLiaison3; >+import org.apache.tools.ant.taskdefs.XSLTLiaison4; > import org.apache.tools.ant.taskdefs.XSLTLogger; > import org.apache.tools.ant.taskdefs.XSLTLoggerAware; > import org.apache.tools.ant.taskdefs.XSLTProcess; >@@ -68,7 +68,7 @@ > * > * @since Ant 1.3 > */ >-public class TraXLiaison implements XSLTLiaison3, ErrorListener, XSLTLoggerAware { >+public class TraXLiaison implements XSLTLiaison4, ErrorListener, XSLTLoggerAware { > > /** > * Helper for transforming filenames to URIs. >@@ -118,7 +118,7 @@ > private Vector outputProperties = new Vector(); > > /** stylesheet parameters */ >- private Hashtable params = new Hashtable(); >+ private Hashtable<String, Object> params = new Hashtable<String, Object>(); > > /** factory attributes */ > private Vector attributes = new Vector(); >@@ -369,7 +369,7 @@ > for (final Enumeration enumeration = params.keys(); > enumeration.hasMoreElements();) { > final String name = (String) enumeration.nextElement(); >- final String value = (String) params.get(name); >+ final Object value = params.get(name); > transformer.setParameter(name, value); > } > } >@@ -505,6 +505,16 @@ > public void addParam(String name, String value) { > params.put(name, value); > } >+ >+ /** >+ * Add a parameter. >+ * @param name the name of the parameter >+ * @param value the value of the parameter >+ * @since Ant 1.9.3 >+ */ >+ public void addParam(String name, Object value) { >+ params.put(name, value); >+ } > > /** > * Set a logger. >Index: manual/Tasks/style.html >=================================================================== >--- manual/Tasks/style.html (revision 1532335) >+++ manual/Tasks/style.html (working copy) >@@ -295,11 +295,33 @@ > </tr> > <tr> > <td valign="top">expression</td> >- <td valign="top">Text value to be placed into the param.<br> >- Was originally intended to be an XSL expression.</td> >+ <td valign="top"> >+ The value to be placed into the param or an XPath expression >+ (depending on <code>type</code>). >+ </td> > <td align="center" valign="top">Yes</td> > </tr> > <tr> >+ <td valign="top">type</td> >+ <td valign="top"> >+ Data type of the parameter. Possible values are: >+ <ul> >+ <li><code>STRING</code></li> >+ <li><code>BOOLEAN</code></li> >+ <li><code>INT</code></li> >+ <li><code>LONG</code></li> >+ <li><code>DOUBLE</code></li> >+ <li><code>XPATH_STRING</code></li> >+ <li><code>XPATH_BOOLEAN</code></li> >+ <li><code>XPATH_NUMBER</code></li> >+ <li><code>XPATH_NODE</code></li> >+ <li><code>XPATH_NODESET</code></li> >+ </ul> >+ <em>since Ant 1.9.3</em> >+ </td> >+ <td align="center" valign="top">No; default is <code>STRING</code></td> >+ </tr> >+ <tr> > <td valign="top">if</td> > <td valign="top">The param will only be passed <a href="../properties.html#if+unless">if this property is set</a>.</td> > <td align="center" valign="top">No</td> >@@ -313,6 +335,18 @@ > </table> > </blockquote> > >+ <p> >+ The <code>XPATH_*</code> types says that the <code>expression</code> is not just a primitive-type value but an XPath expression. >+ This expression will be evaluated on an empty XML document and the result will be passed to the XSLT transformer as a parameter of given type. >+ In these expressions the declared Ant properties can be used as XPath variables e.g. <code>$someProperty</code>. >+ So you can compute something using standard XPath functions and operators. >+ </p> >+ <p> >+ If you write <code>${someProperty}</code> instead of <code>$someProperty</code>, >+ the value will be simply substituted by Ant before evaluating the XPath expression >+ (this substitution works also for primitive types). >+ </p> >+ > <h4>outputproperty ('trax' processors only)</h4> > <p>Used to specify how you wish the result tree to be output > as specified in the <a href="http://www.w3.org/TR/xslt#output"> >@@ -459,6 +493,7 @@ > </xslt> > </pre> > <h4>Using XSL parameters</h4> >+ <p>Simple String parameter:</p> > <pre> > <xslt basedir="doc" destdir="build/doc" > extension=".html" style="style/apache.xsl"> >@@ -469,7 +504,56 @@ > element <xsl:param name="date"/>, the variable > <code>$date</code> will subsequently have the value 07-01-2000. > </p> >+ >+ <p>Various data types and XPath expressions:</p> >+ >+ <pre><property name="antProperty1" value="ANT_PROPERTY_1"/> >+<property name="antProperty2" value="ANT_PROPERTY_2"/> >+<property name="antProperty3" value="3"/> >+<property name="antProperty4" value="substring-before"/> > >+<!-- >+ ${this} is substituted by Ant itself >+ and $this is evaluated by XPath as a variable >+--> >+ >+<xslt in="in.xml" out="out.xml" style="template.xsl"> >+ >+ <!-- Simple String parameter: --> >+ <param name="p0" expression="some nice string" type="STRING"/> >+ >+ <!-- A value substituted by Ant --> >+ <param name="p1" expression="some string with ${antProperty1} constructed by Ant" type="STRING"/> >+ >+ <!-- XPath resulting in: and this is done in XPath: ANT_PROPERTY_2 --> >+ <param name="p2" expression="concat('and this is done in XPath: ', $antProperty2)" type="XPATH_STRING"/> >+ >+ <!-- Some XPath math, result: 42 --> >+ <param name="p3" expression="64 * 64 div 128 + 10" type="XPATH_NUMBER"/> >+ >+ <!-- Some numeric parameter: --> >+ <param name="p4" expression="123.45" type="DOUBLE"/> >+ >+ <!-- XPath expression, result: true boolean --> >+ <param name="p5" expression="$antProperty1 = 'ANT_PROPERTY_1'" type="XPATH_BOOLEAN"/> >+ >+ <!-- First one is an XPath variable, second one is a text substituted by Ant, result: true boolean --> >+ <param name="p6" expression="$antProperty2 = '${antProperty2}'" type="XPATH_BOOLEAN"/> >+ >+ <!-- Some XPath math with a variable, result: 64 --> >+ <param name="p7" expression="$antProperty3 * 4 * 5 + 4" type="XPATH_NUMBER"/> >+ >+ <!-- >+ XPath expression with substituted function name and a variable: >+ substring-before($antProperty2, '_') >+ result: ANT >+ --> >+ <param name="p8" expression="${antProperty4}($antProperty2, '_')" type="XPATH_STRING"/> >+ >+ <!-- Without type attribute: --> >+ <param name="p9" expression="default type is String"/> >+</xslt></pre> >+ > <h4>Using output properties</h4> > <pre> > <xslt in="doc.xml" out="build/doc/output.xml"
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 21525
:
30495
|
30496
|
30928
|
30929
| 30943