+ 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".
+
+
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");
+ }
}