diff --git a/docs/manual/CoreTasks/macrodef.html b/docs/manual/CoreTasks/macrodef.html index 8c3d1ff03..7d7fa7e40 100644 --- a/docs/manual/CoreTasks/macrodef.html +++ b/docs/manual/CoreTasks/macrodef.html @@ -11,7 +11,7 @@

Description

This defines a new task using a <sequential> or <parallel> - nested task as a template. Nested elements <param> and + nested task as a template. Nested elements <attribute> and <element> are used to specify attributes and elements of the new task. These get substituted into the <sequential> or <parallel> task when the new task is run. @@ -28,7 +28,7 @@ name - the name of the new definition + The name of the new definition Yes @@ -38,9 +38,20 @@ No + + attributestyle + + Temporary + this attribute specifies if the attribute is in ant style + (i.e. ${attributeName}) or xpath style (i.e @attributeName). + Valid values are "ant" and "xpath". The default value + is "ant". + + No +

Parameters specified as nested elements

-

param

+

attribute

This is used to specify attributes of the new task. The values of the attributes get substituted into the templated task. @@ -52,6 +63,11 @@ task using the ant property notation - ${attribute name}. Note that is not an actual ant property.

+

+ If the attribute style is set to "xpath", the attribute is + specified in the body of the template task by prefixing the + name with a "@". +

Parameters

@@ -61,13 +77,13 @@ - + @@ -87,13 +103,13 @@ - + @@ -109,7 +125,7 @@
 <macrodef name="testing">
-   <param name="v" default="NOT SET"/>
+   <attribute name="v" default="NOT SET"/>
    <element name="some-tasks" optional="yes"/>
    <sequential>
       <echo>v is ${v}</echo>
@@ -124,6 +140,23 @@
 </testing>
       
+

+ The following fragment sets the attribute style to "xpath" + for the macro definition <testing> and calls the + macro. The fragment should output "attribute is this is a test". +

+
+
+<macrodef name="testing" attributestyle="xpath">
+   <attribute name="abc"/>
+   <sequential>
+      <echo>attribute is @abc</echo>
+   </sequential>
+</macrodef>
+
+<testing abc="this is a test"/>
+      
+

The following fragment defines a task called <call-cc> which take the attributes "target", "link" and "target.dir" and the @@ -134,9 +167,9 @@

 <macrodef name="call-cc">
-   <param name="target"/>
-   <param name="link"/>
-   <param name="target.dir"/>
+   <attribute name="target"/>
+   <attribute name="link"/>
+   <attribute name="target.dir"/>
    <element name="cc-elements"/>
    <sequential>
       <mkdir dir="${obj.dir}/${target}"/>
diff --git a/src/etc/testcases/taskdefs/macrodef.xml b/src/etc/testcases/taskdefs/macrodef.xml
index 72a88a511..8a67d47ac 100644
--- a/src/etc/testcases/taskdefs/macrodef.xml
+++ b/src/etc/testcases/taskdefs/macrodef.xml
@@ -2,7 +2,7 @@
 
   
     
-      
+      
       
         
       
@@ -12,7 +12,7 @@
 
   
     
-      
+      
       
         ${text}
       
@@ -22,7 +22,7 @@
 
   
     
-      
+      
       
         
       
@@ -44,4 +44,15 @@
       
     
   
+
+  
+    
+      
+      
+        attribute is @abc@abc
+      
+    
+
+    
+  
 
diff --git a/src/main/org/apache/tools/ant/taskdefs/MacroDef.java b/src/main/org/apache/tools/ant/taskdefs/MacroDef.java
index 68fe20ab1..dd5a05d62 100644
--- a/src/main/org/apache/tools/ant/taskdefs/MacroDef.java
+++ b/src/main/org/apache/tools/ant/taskdefs/MacroDef.java
@@ -68,6 +68,8 @@ import org.apache.tools.ant.Task;
 import org.apache.tools.ant.TaskContainer;
 import org.apache.tools.ant.UnknownElement;
 
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
 /**
  * Describe class MacroDef here.
  *
@@ -78,9 +80,10 @@ public class MacroDef extends Task implements AntlibInterface, TaskContainer {
     private UnknownElement nestedTask;
     private String     name;
     private String     componentName;
-    private List       params = new ArrayList();
+    private List       attributes = new ArrayList();
     private Map        elements = new HashMap();
-    private String         uri;
+    private String     uri;
+    private int        attributeStyle = AttributeStyle.ANT;
 
     /**
      * Name of the definition
@@ -105,6 +108,46 @@ public class MacroDef extends Task implements AntlibInterface, TaskContainer {
         this.uri = uri;
     }
 
+    /**
+     * Enumerated type for attributeStyle attribute
+     *
+     * @see EnumeratedAttribute
+     */
+    public static class AttributeStyle extends EnumeratedAttribute {
+        /** Enumerated values */
+        public static final int ANT = 0, XPATH = 1;
+
+        /**
+         * get the values
+         * @return an array of the allowed values for this attribute.
+         */
+        public String[] getValues() {
+            return new String[] {"ant", "xpath"};
+        }
+    }
+
+    /**
+     * Expermential
+     * I am uncertain at the moment how to encode attributes
+     * using ant style ${attribute} or xpath style @attribute.
+     * The first may get mixed up with ant properties and
+     * the second may get mixed up with xpath.
+     * The default at the moment is ant s
+     *
+     * @param style an AttributeStyle value
+     */
+    public void setAttributeStyle(AttributeStyle style) {
+        attributeStyle = style.getIndex();
+    }
+
+    /**
+     * Expermential
+     * @return the attribute style
+     */
+    public int getAttributeStyle() {
+        return attributeStyle;
+    }
+
     /**
      * Set the class loader.
      * Not used
@@ -139,10 +182,10 @@ public class MacroDef extends Task implements AntlibInterface, TaskContainer {
     }
 
     /**
-     * @return the nested Params
+     * @return the nested Attributes
      */
-    public List getParams() {
-        return params;
+    public List getAttributes() {
+        return attributes;
     }
 
     /**
@@ -153,16 +196,46 @@ public class MacroDef extends Task implements AntlibInterface, TaskContainer {
     }
 
     /**
-     * Add a param element.
+     * Check if a character is a valid character for an element or
+     * attribute name
+     * @param c the character to check
+     * @return true if the character is a letter or digit or '.' or '-'
+     *         attribute name
+     */
+    public static boolean isValidNameCharacter(char c) {
+        // ? is there an xml api for this ?
+        return Character.isLetterOrDigit(c) || c == '.' || c == '-';
+    }
+
+    /**
+     * Check if a string is a valid name for an element or
+     * attribute
+     * @param name the string to check
+     * @return true if the name consists of valid name characters
+     */
+    private static boolean isValidName(String name) {
+        if (name.length() == 0) {
+            return false;
+        }
+        for (int i = 0; i < name.length(); ++i) {
+            if (!isValidNameCharacter(name.charAt(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Add an attribute element.
      *
-     * @param param a param nested element.
+     * @param attribute an attribute nested element.
      */
-    public void addConfiguredParam(Param param) {
-        if (param.getName() == null) {
+    public void addConfiguredAttribute(Attribute attribute) {
+        if (attribute.getName() == null) {
             throw new BuildException(
-                "the param nested element needed a \"name\" attribute");
+                "the attribute nested element needed a \"name\" attribute");
         }
-        params.add(param);
+        attributes.add(attribute);
     }
 
     /**
@@ -207,20 +280,24 @@ public class MacroDef extends Task implements AntlibInterface, TaskContainer {
      * A nested element for the MacroDef task.
      *
      */
-    public static class Param {
+    public static class Attribute {
         private String name;
         private String defaultValue;
         /**
-         * The name of the parameter.
+         * The name of the attribute.
          *
-         * @param name the name of the parameter
+         * @param name the name of the attribute
          */
         public void setName(String name) {
+            if (!isValidName(name)) {
+                throw new BuildException(
+                    "Illegal name [" + name + "] for attribute");
+            }
             this.name = name;
         }
 
         /**
-         * @return the name of the parameter.
+         * @return the name of the attribute
          */
         public String getName() {
             return name;
@@ -257,6 +334,10 @@ public class MacroDef extends Task implements AntlibInterface, TaskContainer {
          * @param name the name of the element.
          */
         public void setName(String name) {
+            if (!isValidName(name)) {
+                throw new BuildException(
+                    "Illegal name [" + name + "] for attribute");
+            }
             this.name = name;
         }
 
@@ -316,5 +397,17 @@ public class MacroDef extends Task implements AntlibInterface, TaskContainer {
             ((MacroInstance) o).setTemplate(template);
             return o;
         }
+
+        /**
+         * Equality method for this definition
+         * This only checks for pointer equality.
+         *
+         * @param other another definition
+         * @param project the current project
+         * @return true if the definitions are the same
+         */
+        public boolean sameDefinition(AntTypeDefinition other, Project project) {
+            return this == other;
+        }
     }
 }
diff --git a/src/main/org/apache/tools/ant/taskdefs/MacroInstance.java b/src/main/org/apache/tools/ant/taskdefs/MacroInstance.java
index bda5484ba..027561e02 100644
--- a/src/main/org/apache/tools/ant/taskdefs/MacroInstance.java
+++ b/src/main/org/apache/tools/ant/taskdefs/MacroInstance.java
@@ -146,7 +146,7 @@ public class MacroInstance extends Task implements DynamicConfigurator {
         }
     }
 
-    private static String macroSubs(String s, Map macroMapping) {
+    private String macroSubsAnt(String s, Map macroMapping) {
         StringBuffer ret = new StringBuffer();
         StringBuffer macroName = new StringBuffer();
         boolean inMacro = false;
@@ -179,6 +179,59 @@ public class MacroInstance extends Task implements DynamicConfigurator {
         return ret.toString();
     }
 
+    private String macroSubsXPath(String s, Map macroMapping) {
+        StringBuffer ret = new StringBuffer();
+        StringBuffer macroName = new StringBuffer();
+        boolean inMacro = false;
+        for (int i = 0; i < s.length(); ++i) {
+            char c = s.charAt(i);
+            if (!inMacro) {
+                if (c == '@') {
+                    inMacro = true;
+                } else {
+                    ret.append(c);
+                }
+            } else {
+                if (MacroDef.isValidNameCharacter(c)) {
+                    macroName.append(c);
+                } else {
+                    inMacro = false;
+                    String name = macroName.toString();
+                    String value = (String) macroMapping.get(name);
+                    if (value == null) {
+                        ret.append("@" + name);
+                    } else {
+                        ret.append(value);
+                    }
+                    if (c == '@') {
+                        inMacro = true;
+                    } else {
+                        ret.append(c);
+                    }
+                    macroName = new StringBuffer();
+                }
+            }
+        }
+        if (inMacro) {
+            String name = macroName.toString();
+            String value = (String) macroMapping.get(name);
+            if (value == null) {
+                ret.append("@" + name);
+            } else {
+                ret.append(value);
+            }
+        }
+        return ret.toString();
+    }
+
+    private String macroSubs(String s, Map macroMapping) {
+        if (template.getAttributeStyle() == MacroDef.AttributeStyle.ANT) {
+            return macroSubsAnt(s, macroMapping);
+        } else {
+            return macroSubsXPath(s, macroMapping);
+        }
+    }
+
     private UnknownElement copy(UnknownElement ue) {
         UnknownElement ret = new UnknownElement(ue.getTag());
         ret.setNamespace(ue.getNamespace());
@@ -234,25 +287,26 @@ public class MacroInstance extends Task implements DynamicConfigurator {
 
     /**
      * Execute the templates instance.
-     * Copies the unknown element, substitutes the parameters,
+     * Copies the unknown element, substitutes the attributes,
      * and calls perform on the unknown element.
      *
      */
     public void execute() {
         localProperties = new Hashtable();
         Set copyKeys = new HashSet(map.keySet());
-        for (int i = 0; i < template.getParams().size(); ++i) {
-            MacroDef.Param param = (MacroDef.Param) template.getParams().get(i);
-            String value = (String) map.get(param.getName());
+        for (int i = 0; i < template.getAttributes().size(); ++i) {
+            MacroDef.Attribute attribute =
+                (MacroDef.Attribute) template.getAttributes().get(i);
+            String value = (String) map.get(attribute.getName());
             if (value == null) {
-                value = param.getDefault();
+                value = attribute.getDefault();
             }
             if (value == null) {
                 throw new BuildException(
-                    "required parameter " + param.getName() + " not set");
+                    "required attribute " + attribute.getName() + " not set");
             }
-            localProperties.put(param.getName(), value);
-            copyKeys.remove(param.getName());
+            localProperties.put(attribute.getName(), value);
+            copyKeys.remove(attribute.getName());
         }
         if (copyKeys.size() != 0) {
             throw new BuildException(
diff --git a/src/testcases/org/apache/tools/ant/taskdefs/MacroDefTest.java b/src/testcases/org/apache/tools/ant/taskdefs/MacroDefTest.java
index df1893fd5..e6b8987a2 100644
--- a/src/testcases/org/apache/tools/ant/taskdefs/MacroDefTest.java
+++ b/src/testcases/org/apache/tools/ant/taskdefs/MacroDefTest.java
@@ -85,5 +85,9 @@ public class MacroDefTest extends BuildFileTest {
     public void testNested() {
         expectLog("nested", "A nested element");
     }
+
+    public void testXPathStyle() {
+        expectLog("xpathstyle", "attribute is this is a testthis is a test");
+    }
 }
 
namethe name of the new attributeThe name of the new attribute Yes
default - the default value of the attribute. + The default value of the attribute. No
namethe name of the new attributeThe name of the new attribute Yes
optional - if true this nested element is optional. Default is + If true this nested element is optional. Default is false - i.e the nested element is required in the new task.