What requirements does Ant place on attribute names?

I can get my scriptdef to run but only if I use certain names for my attributes. Apparently names like "property" and "prop1", "prop2", etc. are ok, but most other names (including "propN") are not ok. Which ones are OK and why?

This works (using attribute name prop2):

<project name="Ant Is Weird">
  <property name="hostname" value="abc-de-fghijk0.lmn.opqr.stu"/>

  <scriptdef name="hostSubstring" language="javascript">
    <attribute name="text" />
    <attribute name="prop1" />
    <attribute name="prop2" />
    <![CDATA[
      var hn = attributes.get("text");
      project.setProperty(attributes.get("prop1"), hn.replace(/[^0-9]/g,""));
      project.setProperty(attributes.get("prop2"), hn.replace(/[^0-9]/g,""));
      ]]>
  </scriptdef>

  <target name="test" description="helps me learn about scriptdef">
    <echo message="hostname is ${hostname}"/>
    <hostSubstring text="${hostname}" prop1="firstProp" prop2="secondProp"/>
    <echo message="firstProp is ${firstProp}" />
    <echo message="secondProp is ${secondProp}" />
  </target>
</project>

output:

$ ant test
Buildfile: /apps/antTest/build.xml

test:
     [echo] hostname is abc-de-fghijk0.lmn.opqr.stu
     [echo] firstProp is 0
     [echo] secondProp is 0

BUILD SUCCESSFUL
Total time: 0 seconds

But this fails (using attribute name propN):

<project name="Ant Is Weird">
  <property name="hostname" value="abc-de-fghijk0.lmn.opqr.stu"/>

  <scriptdef name="hostSubstring" language="javascript">
    <attribute name="text" />
    <attribute name="prop1" />
    <attribute name="propN" />
    <![CDATA[
      var hn = attributes.get("text");
      project.setProperty(attributes.get("prop1"), hn.replace(/[^0-9]/g,""));
      project.setProperty(attributes.get("propN"), hn.replace(/[^0-9]/g,""));
      ]]>
  </scriptdef>

  <target name="test" description="helps me learn about scriptdef">
    <echo message="hostname is ${hostname}"/>
    <hostSubstring text="${hostname}" prop1="firstProp" propN="secondProp"/>
    <echo message="firstProp is ${firstProp}" />
    <echo message="secondProp is ${secondProp}" />
  </target>
</project>

output:

$ ant test
Buildfile: /apps/antTest/build.xml

test:
     [echo] hostname is abc-de-fghijk0.lmn.opqr.stu

BUILD FAILED
/apps/antTest/build.xml:17: java.lang.NullPointerException
        at java.util.Hashtable.containsKey(Hashtable.java:335)
        at org.apache.tools.ant.PropertyHelper.setProperty(PropertyHelper.java:640)
        at org.apache.tools.ant.Project.setProperty(Project.java:538)
        at jdk.nashorn.internal.scripts.Script$\^eval\_.:program(<eval>:8)
        at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:637)
        at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:494)
        at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:393)
        at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:446)
        at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:403)
        at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:399)
        at jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:155)
        at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.apache.tools.ant.util.ReflectUtil.invoke(ReflectUtil.java:108)
        at org.apache.tools.ant.util.ReflectWrapper.invoke(ReflectWrapper.java:81)
        at org.apache.tools.ant.util.optional.JavaxScriptRunner.evaluateScript(JavaxScriptRunner.java:103)
        at org.apache.tools.ant.util.optional.JavaxScriptRunner.executeScript(JavaxScriptRunner.java:67)
        at org.apache.tools.ant.taskdefs.optional.script.ScriptDef.executeScript(ScriptDef.java:350)
        at org.apache.tools.ant.taskdefs.optional.script.ScriptDefBase.execute(ScriptDefBase.java:50)
        at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
        at org.apache.tools.ant.Task.perform(Task.java:348)
        at org.apache.tools.ant.Target.execute(Target.java:390)
        at org.apache.tools.ant.Target.performTasks(Target.java:411)
        at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1399)
        at org.apache.tools.ant.Project.executeTarget(Project.java:1368)
        at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
        at org.apache.tools.ant.Project.executeTargets(Project.java:1251)
        at org.apache.tools.ant.Main.runBuild(Main.java:809)
        at org.apache.tools.ant.Main.startAnt(Main.java:217)
        at org.apache.tools.ant.launch.Launcher.run(Launcher.java:280)
        at org.apache.tools.ant.launch.Launcher.main(Launcher.java:109)

Total time: 0 seconds

In case it matters:

$ cat /etc/redhat-release
Red Hat Enterprise Linux Server release 6.8 (Santiago)
$ ant -version
Apache Ant(TM) version 1.8.2 compiled on December 20 2010
Jon Skeet
people
quotationmark

The attributes are lower-cased automatically. I found this out by putting

self.log(attributes);

into the script.

So if you change your script to use propn instead of propN it works:

project.setProperty(attributes.get("propn"), hn.replace(/[^0-9]/g,""));

This is documented in the Scriptdef task documentation:

Note: Ant will turn all attribute and element names into all lowercase names, so even if you use name="SomeAttribute", you'll have to use "someattribute" to retrieve the attribute's value from the attributes collection.

people

See more on this question at Stackoverflow