ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Gus Heck <gus-ant...@cognition.olin.edu>
Subject Re: <macro> and XML NS hell ;-)
Date Wed, 03 Mar 2004 18:01:54 GMT
Hi Peter,

Thanks for the long reply! I have a few questions and a suggestion (inline).

Peter Reilly wrote:

> Sorry Gus,
> I meant to respond earlier but I am moving to a new computer
> and some things got lost.
>
> The main reason the example is confusing is that macrodef, despite
> it's name, does not do real textual  substition, it sees a Dom like tree
> of elements (a tree of UnknownElements with paired RuntimeConfigurables)
> and not the raw texual angley brackets.
>
> A simple example should make this clear. Assume first that namespaced
> xml does not support prefix free elements and there is a class A
>
> class A {
>   public void addFileSet(FileSet s) {}
> }
>
> and class B:
> class B {
>   public void addFileSet(FileSet s) {}
> }
>
> Now suppose that A is a type a in namespace antlib:net.a
> and B is a type b in namespace antlib:net.b.
> The following would be correct xml:
> <ant:project xmlns:a="antlib:net.a" xmlns:b="antlib:net.b"
>             xmnls:ant="antlib:org.apache.tools.ant">
>  <a:a>
>     <a:fileset dir="."/>
>  </a:a>
>
>  <b:b>
>     <b:fileset dir="."/>
>   </b:b>
>
> </ant:project>

This makes sense, and only requires that the program (ant) has either 
separate fileset implementations ot associate with <a:fileset> and 
<b:fileset> or has some way of knowing that both are equivalent to 
<ant:fileset>. All the name spaces are specified explicitly and so there 
is no confusion here.

>
> Now it is understandable that the following does not work:
>
>  <ant:macrodef name="c">
>     <ant:element name="files">
>     <ant:sequential>
>         <a:a>
>           <ant:files/>
>          </a:a>
>          <b:b>
>            <ant:files/>
>          </b:b>
>     </ant:sequential>
>  </ant:macrodef>
>
> as there is no set of xml dom elements that will be
> acceptable to a:a and b:a.
>
> XmlNs does have the concept of a default ns prefix and a not specified 
> ns prefix.
>
> First the default ns prefix.
> This is what Dominique tried to use.
>
>  <ant:macrodef name="c">
>     <ant:element name="files">
>     <ant:sequential>
>         <a xmlns="antlib:net.a">
>           <ant:files/>
>          </a>
>          <b xmlns="antlib:net.b">
>            <ant:files/>
>          </b>
>     </ant:sequential>
>  </ant:macrodef>
>
>  <ant:c>
>    <files xmlns="antlib:org.apache.tools.ant">
>       <fileset dir="."/>
>     </files>
>   </ant:c>
>
> This will fail as the fileset element is in the 
> "antlib:org.apache.tools.ant"
> namespace and not in the "antlib:net.a" or "antlib:net.b" namespaces.
>
> The not-specified ns prefix (I think) is proceeded by whatever the xml 
> processor
> program likes. Ant treats this like a default xml namespace.
> One solution to this (common) problem would be to allow the a's 
> addFileset method
> to be matched by both a's namespace fileset element and by ant's 
> default namespace,
> so the following would be correct xml:
>
> <a:a>
>  <ant:fileset dir="."/>  <!-- matches A.addFileSet() method -->
> </a:a>
>
> and
> <a:a>
>  <a:fileset dir="."/>  <!-- also matches A.addFileSet() method -->
> </a:a>
>
I assume you are refering to A.addFileSet(o.a.t.a.types.FileSet fs) above.

One could conceive of A.addFileSet(com.astuff.FileSet fs) too for custom 
fileset implementations. A might even have both methods. In this case it 
seems ant should match different methods. It seems that this should be 
theroetically possible but, the issue is what happens when ant runs into

<project xmlns:a="antlib:net.a">
<a:a>
  <fileset dir="."/>
<a:a/>
</project>

I think this has to be equivalent to your first example above and

<project>
<a xmlns="antlib:net.a">
  <fileset dir="."/>
<a/>
</project>

must be equivalent to your second example right?

>
> On a side - issue, I think that this solution would help in the
> uptake of antlibs.
>
> ForExample,
> a a build file using ant-contrib with ant 1.5 would look like something
> like this:
>
> <project default="compile">
>  <taskdef resource="net/sf/antcontrib/antcontrib.properties"/>
>    <switch value="${foo}">
>    <case value="bar">
>      <echo message="The value of property foo is bar" />
>    </case>
>    <case value="baz">
>       <echo message="The value of property foo is baz" />
>    </case>
>    <default>
>      <echo message="The value of property foo is not sensible" />
>    </default>
>  </switch>
> </project>
>
> Using antlib:net.sf.antcontrib namespace in ant 1.6 results in 2/3 
> lines being changed, and one feels like an xml ns lawyer  :-( Using 
> the more relaxed rules only involves modifing a couple of lines
> and looks (IMO) a lot nicer:
>
> <project default="compile" xmlns:ac="antlib:net.sf.antcontrib">
>  <ac:switch value="${foo}">
>    <case value="bar">
>      <echo message="The value of property foo is bar" />
>    </case>
>    <case value="baz">
>       <echo message="The value of property foo is baz" />
>    </case>
>    <default>
>      <echo message="The value of property foo is not sensible" />
>    </default>
>  </ac:switch>
> </project>
>
What this xml says to me (and I suspect says to the parser) is that 
ac:switch is using ant:case elements. If the result is otherwise this 
doesn't seem to follow the principal of least supprise. (imho)

One could be explicit and only change 1/3 the lines by using:

<project default="compile" xmlns:ant="antlib:org.apache.tools.ant">
 <switch value="${foo}" xmlns="antlib:net.sf.antcontrib">
   <case value="bar">
     <ant:echo message="The value of property foo is bar" />
   </case>
   <case value="baz">
      <ant:echo message="The value of property foo is baz" />
   </case>
   <default>
     <ant:echo message="The value of property foo is not sensible" />
   </default>
 </ac:switch>
</project>

However, in real use switch probably does more than just echo on each 
line and so this is of limited help.

Unless I am confused, in your example ant would wind up looking for 
ant:case, and when it didn't find it it would have to poll the 
containing elements for their name spaces and search those name spaces 
or just search all available name spaces for a matching element. (the 
latter of which obviously runs into problems).

If we do take a shortcut I think it would be better to do it like this:

<project default="compile">
 <switch value="${foo}" xmlns="antlib:net.sf.antcontrib">
   <case value="bar">
     <echo message="The value of property foo is bar" />
   </case>
   <case value="baz">
      <echo message="The value of property foo is baz" />
   </case>
   <default>
     <echo message="The value of property foo is not sensible" />
   </default>
 </ac:switch>
</project>

This version means that ant looks for an echo element in the antcontrib 
name space. Upon not finding an ant contrib echo it only has to look in 
ant core for an alternate echo element  and if it doesn't have either an 
antcontrib echo or an ant echo, it should fail. Basically what we have 
here is the condition that all antlibs inherit (but may overide) ant 
core tasks.

I like that one better, what do you think?

Gus

> Peter
>
> Gus Heck wrote:
>
>> Gus Heck wrote:
>>
>>>
>>>> re given to the elements in the calling macro.
>>>>
>>>> In ant 1.6.0+, the namespace of elements discovered by reflection take
>>>> the namespace uri of type/task that contains the element (Note this 
>>>> is the
>>>> uri and not the localname).
>>>>
>>>> The enclosed patch will allow the namespace of nested elements to be
>>>> either the ant uri or the namespace of the containing type/task.
>>>>
>>> I am quite possibly confused but I thought xml namespaces required 
>>> that the namespace be
>>>
>>> 1. The namespace indicated by the specified prefix
>>>
>>> 2. If there is no prefix, then the current default namespace must be 
>>> used. (defined on some containing element, be it the top element or 
>>> some other containing element with an xmlns="some uri").
>>>
>>> If an unprefixed element is taking on a namespace not declared with 
>>> xmlns="some uri" (which is different from xmlns:foo="some uri") 
>>> aren't we blowing it in implementing namespaces correctly?
>>>
>>> -Gus
>>>
>> Was I wrong? Confused? or just ignored?
>>
>> -Gus
>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
>>> For additional commands, e-mail: dev-help@ant.apache.org
>>>
>>
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
>> For additional commands, e-mail: dev-help@ant.apache.org
>>
>>
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
> For additional commands, e-mail: dev-help@ant.apache.org
>



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org


Mime
View raw message