You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@velocity.apache.org by Tomoki Tsuchida <tt...@studioyk.dhs.org> on 2001/11/28 16:48:29 UTC

Question on recursion

Hello,

I've been working on velocity for a while now, and now I'm trying to flatten
tree structure in velocity and ran into trouble.  I have two java classes,
'categorygroup' and 'category', and I want to show all of the categories
belonging to category groups in a select list. A category belongs to a
categorygroup, and a categorygroup can belong to another categorygroup. So
the classes look like this:

public class category {
  public String getId() {..}
  public String getName() {..}
}

public class categorygroup {
  public String getName() {.. }
  public List /* of category */ getCategories() {..}
  public List /* of categorygroup */ getCategorygroups() {..}
}

.. and when I have a structure like this (brackets are categories):

+ [root category 1]
+ [root category 2]
+ category group 1
  - [cat under group 1]
  + category group 2
    - [cat under 2]
    - [another cat under 2]
+ category group 3
   - [cat under group 3]

.. I want to show it like this in the select list:

root category 1
root category 2
category group 1 > cat under group 1
category group 1 > category group 2 > cat under 2
category group 1 > category group 2 > another cat under 2
category group 3 > cat under group 3

I had to do this in java before and it's pretty easy with recursive
functions.  Now what I want to do is to dump the root categorygroup into the
context object and flatten the tree structure using velocimacro instead of
java.  And I came up with something like this:

#macro ( recurse $group $parentname )
  #foreach ( $category in $group.Category )
  <option value="$category.Id">$parentname$category.Name
  #end
  #foreach ( $childgroup in $group.Categorygroup )
  #recurse ( $childgroup "$parentname$childgroup.Name &gt; " )
  #end
#end

...

<select>
#recurse( $mygroup "" )
</select>

I looked at the XML tree example first and came up with the macro.  The
problem is, it doesn't work like the way I want it to.  If you run this
macro with the aforementioned data set it will render something like:

root category 1
root category 2
category group 1 > cat under group 1
category group 2 > category group 2 > cat under 2
category group 2 > category group 2 > another cat under 2
category group 2 > category group 2 > category group 3 > another cat under 2
category group 2 > category group 2 > category group 3 > cat under group 3

I think the problem is that everything is evaluated on a global scope, i.e.
'$childgroup' and '$parentname' gets overwritten every time the child
recursive function is called.  Is there any way in velocity to declare a
local-scope variable inside a macro?  I guess I should be able to rewrite
the same logic without using recursion, but I can't really think of how I'd
go about doing that either :-p  I could also do it easily within java, but
then it defeats the purpose of separating presentation from logic so I
really don't want to do it.

Thanks,
Tomoki



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Question on recursion

Posted by Tomoki Tsuchida <tt...@studioyk.dhs.org>.
Thanks for your help, I didn't know about velocimacro.context.localscope
parameter... I put it in my velocity.properties but it didn't make any
change however.  I'll be checking to see if I'm using the correct property
file and everything, but meanwhile, here's a simpler demonstration of the
problem:

[Recursion.vm]
#macro ( recurse $group $parent )
  #foreach ( $stuff in $group.Groups )
  $parent$stuff.Name<br>
  #recurse ( $stuff "$parent$stuff.Name &gt;" )
  #end
#end

<html>
<body>
#recurse ( $mygroup "" )
</body>
</html>

[in java]
  public class Group {
    private String name;
    public List groups = new ArrayList();
    public Group(String name) { this.name = name; }
    public List getGroups() { return this.groups; }
    public String getName() { return this.name; }
  }
..
    Group root = new Group("root");
    Group one = new Group("one");
    Group two = new Group("two");

    Group oneb = new Group("one one");
    Group onec = new Group("one two");
    Group oned = new Group("one three");

    Group onebb = new Group ("one one one");
    oneb.groups.add(onebb);

    one.groups.add(oneb);
    one.groups.add(onec);
    one.groups.add(oned);

    Group twob = new Group("two one");
    Group twoc = new Group("two two");
    two.groups.add(twob);
    two.groups.add(twoc);

    root.groups.add(one);
    root.groups.add(two);

    context.put("mygroup", root);

This will produce...

one
one one >one one
one one one >one one one >one one one
one two >one two
one three >one three
two
two one >two one
two two >two two

I guess another issue is the way velocity resolves variable by name at run
time (right?).  So "$parent$stuff.Name &gt;" gets resolved to "$stuff.Name
&gt; $stuff.Name &gt;" on the 2nd level, which is not what I want.  In the
xmlapp_example it isn't a problem because #recursion is called with just
"$index " (so it gets resolved to "$index $index $index " etc., and $index
starts out empty).  Does the local scope option really make velocity resolve
the variables before it calls another macro?

I'm using velocity 1.2-rc3.

Thanks,
Tomoki

----- Original Message -----
From: "Geir Magnusson Jr." <ge...@optonline.net>
To: <ve...@jakarta.apache.org>
Sent: Wednesday, November 28, 2001 11:14 AM
Subject: Re: Question on recursion


> Recursion works fine, but yes, you can step on yourself :)
>
> There is a switch to turn on localscope contexts in VMs.  See the dev
> guide..
>
> Should be something like
>
> velocimacro.context.localscope = true
>
> I'm a little surprised you are having problems - what version of Velocity?
> There is an example, examples/xmlapp_example that demonstrats VM
recursion,
> has the same thing, there it's passing in an $indent string that keeps
> changing...
>
>
> On 11/28/01 10:48 AM, "Tomoki Tsuchida" <tt...@studioyk.dhs.org> wrote:
>
> > Hello,
> >
> > I've been working on velocity for a while now, and now I'm trying to
flatten
> > tree structure in velocity and ran into trouble.  I have two java
classes,
> > 'categorygroup' and 'category', and I want to show all of the categories
> > belonging to category groups in a select list. A category belongs to a
> > categorygroup, and a categorygroup can belong to another categorygroup.
So
> > the classes look like this:
> >
> > public class category {
> > public String getId() {..}
> > public String getName() {..}
> > }
> >
> > public class categorygroup {
> > public String getName() {.. }
> > public List /* of category */ getCategories() {..}
> > public List /* of categorygroup */ getCategorygroups() {..}
> > }
> >
> > .. and when I have a structure like this (brackets are categories):
> >
> > + [root category 1]
> > + [root category 2]
> > + category group 1
> > - [cat under group 1]
> > + category group 2
> >   - [cat under 2]
> >   - [another cat under 2]
> > + category group 3
> >  - [cat under group 3]
> >
> > .. I want to show it like this in the select list:
> >
> > root category 1
> > root category 2
> > category group 1 > cat under group 1
> > category group 1 > category group 2 > cat under 2
> > category group 1 > category group 2 > another cat under 2
> > category group 3 > cat under group 3
> >
> > I had to do this in java before and it's pretty easy with recursive
> > functions.  Now what I want to do is to dump the root categorygroup into
the
> > context object and flatten the tree structure using velocimacro instead
of
> > java.  And I came up with something like this:
> >
> > #macro ( recurse $group $parentname )
> > #foreach ( $category in $group.Category )
> > <option value="$category.Id">$parentname$category.Name
> > #end
> > #foreach ( $childgroup in $group.Categorygroup )
> > #recurse ( $childgroup "$parentname$childgroup.Name &gt; " )
> > #end
> > #end
> >
> > ...
> >
> > <select>
> > #recurse( $mygroup "" )
> > </select>
> >
> > I looked at the XML tree example first and came up with the macro.  The
> > problem is, it doesn't work like the way I want it to.  If you run this
> > macro with the aforementioned data set it will render something like:
> >
> > root category 1
> > root category 2
> > category group 1 > cat under group 1
> > category group 2 > category group 2 > cat under 2
> > category group 2 > category group 2 > another cat under 2
> > category group 2 > category group 2 > category group 3 > another cat
under 2
> > category group 2 > category group 2 > category group 3 > cat under group
3
> >
> > I think the problem is that everything is evaluated on a global scope,
i.e.
> > '$childgroup' and '$parentname' gets overwritten every time the child
> > recursive function is called.  Is there any way in velocity to declare a
> > local-scope variable inside a macro?  I guess I should be able to
rewrite
> > the same logic without using recursion, but I can't really think of how
I'd
> > go about doing that either :-p  I could also do it easily within java,
but
> > then it defeats the purpose of separating presentation from logic so I
> > really don't want to do it.
> >
> > Thanks,
> > Tomoki
> >
> >
> >
> > --
> > To unsubscribe, e-mail:
> > <ma...@jakarta.apache.org>
> > For additional commands, e-mail:
> > <ma...@jakarta.apache.org>
> >
>
> --
> Geir Magnusson Jr.     geirm@optonline.net
> System and Software Consulting
> "Whoever would overthrow the liberty of a nation must begin by subduing
the
> freeness of speech." - Benjamin Franklin
>
>
>
> --
> To unsubscribe, e-mail:
<ma...@jakarta.apache.org>
> For additional commands, e-mail:
<ma...@jakarta.apache.org>
>
>


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Question on recursion

Posted by Tomoki Tsuchida <tt...@studioyk.dhs.org>.
It finally works for me :-D  I think it may have been the local context
after all, but I wouldn't have figured that out myself... Thanks a lot for
your help :) Now I'm fully diving into my project with Velocity.

Thanks,
Tomoki

----- Original Message -----
From: "Geir Magnusson Jr." <ge...@optonline.net>
To: <ve...@jakarta.apache.org>
Sent: Wednesday, November 28, 2001 4:11 PM
Subject: Re: Question on recursion


> You win the "Lousy User Support From Me" award.  Sorry.  The prize seems
to
> be more lousy support from me...
>
> Here's my VM :
>
> #macro ( recurse $group $parent )
>   #foreach ( $stuff in $group.Groups )
>     #set( $foo = "$parent$stuff.Name > ")
>     $foo
>     #recurse ( $stuff $foo )
>   #end
> #end
>
> Turn on localcontext, and you should be golden...
>
> Heres what I get...
>
> <html>
> <body>
>       one >
>           one > one one >
>           one > one one > one one one >
>               one > one two >
>             one > one three >
>               two >
>           two > two one >
>             two > two two >
>           </body>
> </html>
>
> Apologies again :)
>
> Geir
>
>
> On 11/28/01 3:46 PM, "Tomoki Tsuchida" <tt...@studioyk.dhs.org> wrote:
>
> > Thanks for your help again.  Well I thought about it too, so I tried:
> >
> > #macro ( recurse $group $parent )
> > #foreach ( $stuff in $group.Groups )
> > $parent$stuff.Name<br>
> > #set($title = "$parent$stuff.Name &gt; ")
> > #recurse ( $stuff $title )
> > #end
> > #end
> >
> > What this produces is:
> >
> > one
> > one > one one
> > one > one one > one one one
> > one > one one > one one one > one two
> > one > one one > one one one > one two > one three
> > two
> > two > two one
> > two > two one > two two
> >
> > So, in this case the problem is that $title doesn't have a local scope,
i.e.
> > every time #recurse is called inside #foreach it modifies the $title of
the
> > caller too.  I need to think more about why it *doesn't* do it for the
root
> > groups ('two' is on the same level as 'one'), but anyhow the problem
isn't
> > really that obvious...
> >
> > ----- Original Message -----
> > From: "Geir Magnusson Jr." <ge...@optonline.net>
> > To: <ve...@jakarta.apache.org>
> > Sent: Wednesday, November 28, 2001 2:58 PM
> > Subject: Re: Question on recursion
> >
> >
> >> Sorry about the 'red herring' there.
> >>
> >> Forget the localscope.  You don't need it.
> >>
> >> I think that the problem, as you touched on it, is that you are passing
in
> >> the whole "" string literal, and it is getting evaluated inside the VM.
> >>
> >> So do this
> >>
> >>  #set($title = "$parent$stuff.Name &gt; ")
> >>  #recurse( $stuff $title)
> >>
> >> And it should work as desired.
> >>
> >> Sorry again.
> >>
> >> Geir
> >>
> >>
> >>
> >> On 11/28/01 2:44 PM, "Tomoki Tsuchida" <tt...@studioyk.dhs.org>
wrote:
> >>
> >>> Thanks for your help, I didn't know about
velocimacro.context.localscope
> >>> parameter... I put it in my velocity.properties but it didn't make any
> >>> change however.  I'll be checking to see if I'm using the correct
> > property
> >>> file and everything, but meanwhile, here's a simpler demonstration of
> > the
> >>> problem:
> >>>
> >>> [Recursion.vm]
> >>> #macro ( recurse $group $parent )
> >>> #foreach ( $stuff in $group.Groups )
> >>> $parent$stuff.Name<br>
> >>> #recurse ( $stuff "$parent$stuff.Name &gt;" )
> >>> #end
> >>> #end
> >>>
> >>> <html>
> >>> <body>
> >>> #recurse ( $mygroup "" )
> >>> </body>
> >>> </html>
> >>>
> >>> [in java]
> >>> public class Group {
> >>>   private String name;
> >>>   public List groups = new ArrayList();
> >>>   public Group(String name) { this.name = name; }
> >>>   public List getGroups() { return this.groups; }
> >>>   public String getName() { return this.name; }
> >>> }
> >>> ..
> >>>   Group root = new Group("root");
> >>>   Group one = new Group("one");
> >>>   Group two = new Group("two");
> >>>
> >>>   Group oneb = new Group("one one");
> >>>   Group onec = new Group("one two");
> >>>   Group oned = new Group("one three");
> >>>
> >>>   Group onebb = new Group ("one one one");
> >>>   oneb.groups.add(onebb);
> >>>
> >>>   one.groups.add(oneb);
> >>>   one.groups.add(onec);
> >>>   one.groups.add(oned);
> >>>
> >>>   Group twob = new Group("two one");
> >>>   Group twoc = new Group("two two");
> >>>   two.groups.add(twob);
> >>>   two.groups.add(twoc);
> >>>
> >>>   root.groups.add(one);
> >>>   root.groups.add(two);
> >>>
> >>>   context.put("mygroup", root);
> >>>
> >>> This will produce...
> >>>
> >>> one
> >>> one one >one one
> >>> one one one >one one one >one one one
> >>> one two >one two
> >>> one three >one three
> >>> two
> >>> two one >two one
> >>> two two >two two
> >>>
> >>> I guess another issue is the way velocity resolves variable by name at
> > run
> >>> time (right?).  So "$parent$stuff.Name &gt;" gets resolved to
> > "$stuff.Name
> >>> &gt; $stuff.Name &gt;" on the 2nd level, which is not what I want.  In
> > the
> >>> xmlapp_example it isn't a problem because #recursion is called with
just
> >>> "$index " (so it gets resolved to "$index $index $index " etc., and
> > $index
> >>> starts out empty).  Does the local scope option really make velocity
> > resolve
> >>> the variables before it calls another macro?
> >>>
> >>> I'm using velocity 1.2-rc3.
> >>>
> >>> Thanks,
> >>> Tomoki
> >>>
> >
> >
> >
> > --
> > To unsubscribe, e-mail:
> > <ma...@jakarta.apache.org>
> > For additional commands, e-mail:
> > <ma...@jakarta.apache.org>
> >
>
> --
> Geir Magnusson Jr.                                     geirm@optonline.net
> System and Software Consulting
> "They that can give up essential liberty to obtain a little temporary
safety
> deserve neither liberty nor safety." - Benjamin Franklin
>
>
>
> --
> To unsubscribe, e-mail:
<ma...@jakarta.apache.org>
> For additional commands, e-mail:
<ma...@jakarta.apache.org>
>
>


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Quiet variables fail in "nested" directives?

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
On 12/6/01 10:10 PM, "Dan Bradley" <ja...@hotmail.com> wrote:

> I'm having trouble getting quiet variables to work in an unusual situation,
> and I'm not sure if there's a way to do what I want to do, whether it's a
> bug, or a feature.
> 
> Given one macro where the result is used as an argument in the call to
> another, in the following fashion, as described at
> http://jakarta.apache.org/velocity/user-guide.html#Velocimacro%20Miscellany:
> 
> #macro (tablerow $arg)
> <tr><td>$arg</td></tr>
> #end
> 
> #macro (txtinput $name $value)
> <input type="text" name="$name" value="$value">
> #end
> 
> <table>
> #tablerow("#txtinput ('email', $!email)")
> </table>
> 
> If $email is in the context the HTML is generated as expected and desired,
> i.e.:
> <tr><td><input type="text" name="email" value="me@somewhere.com"></td></tr>
> 
> However, if $email is not in the context, the variable does not fail quietly
> creating value="", the desired result, but instead is passed through as
> value="$!email", so I end up with:
> <tr><td><input type="text" name="email" value="$!email"></td></tr>

Heh.  This is an interesting one.

I think I know what it is, and will take a look.  However, I think that
passing $!email and expecting it to work this way is incorrect.  It's
accepted by Velocity, but shouldn't be.

What's the correct behavior?

Note that $!email doesn't require it to 'fail' quietly, but actually render
itself quietly - i.e. If no value in the context, don't render.

But being a VM arg is subtly different.  I describe VMs as 'passing by
name', so I guess that the worst it should do is render as $email...  ?

Another way - does the 'quietness' of the arg trump the way the #macro() was
designed to render things?  I think not, but am interested in what others
think.

What I think you should do is put the quiet reference in the VM :

#macro( txtinput $name $value )
  <input type="text" name="$name" value='$!value'>
#end


Does that help (for now) ?


> 
> I have tried various combinations of $email, $!email, $!{email}, in single
> quotes and without, all to no avail. The reason I want to do this is so that
> the input fields in a form page will be blank if no information has been
> submitted yet, but filled in if it has been submitted, without creating two
> different versions of the page or doing an if/else check on each field.
> 
> Any ideas if there's an alternate way to do what I want to do, or if this is
> in fact a bug? I suspect that it's the result of an intentional design
> decision, but I don't quite understand what's going on under the hood well
> enough to figure out how to make it work.

It is intentional, the pass by name thing.  However, if we can decide on the
appropos behavior for this 'edge case', then we can fix it.

-- 
Geir Magnusson Jr.                       geirm@optonline.net
System and Software Consulting
You're going to end up getting pissed at your software
anyway, so you might as well not pay for it. Try Open Source.



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Quiet variables fail in "nested" directives?

Posted by Dan Bradley <ja...@hotmail.com>.
I'm having trouble getting quiet variables to work in an unusual situation,
and I'm not sure if there's a way to do what I want to do, whether it's a
bug, or a feature.

Given one macro where the result is used as an argument in the call to
another, in the following fashion, as described at
http://jakarta.apache.org/velocity/user-guide.html#Velocimacro%20Miscellany:

#macro (tablerow $arg)
<tr><td>$arg</td></tr>
#end

#macro (txtinput $name $value)
<input type="text" name="$name" value="$value">
#end

<table>
#tablerow("#txtinput ('email', $!email)")
</table>

If $email is in the context the HTML is generated as expected and desired,
i.e.:
<tr><td><input type="text" name="email" value="me@somewhere.com"></td></tr>

However, if $email is not in the context, the variable does not fail quietly
creating value="", the desired result, but instead is passed through as
value="$!email", so I end up with:
<tr><td><input type="text" name="email" value="$!email"></td></tr>

I have tried various combinations of $email, $!email, $!{email}, in single
quotes and without, all to no avail. The reason I want to do this is so that
the input fields in a form page will be blank if no information has been
submitted yet, but filled in if it has been submitted, without creating two
different versions of the page or doing an if/else check on each field.

Any ideas if there's an alternate way to do what I want to do, or if this is
in fact a bug? I suspect that it's the result of an intentional design
decision, but I don't quite understand what's going on under the hood well
enough to figure out how to make it work.

Thanks,

Dan Bradley
jackbang@hotmail.com

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Question on recursion

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
You win the "Lousy User Support From Me" award.  Sorry.  The prize seems to
be more lousy support from me...

Here's my VM :

#macro ( recurse $group $parent )
  #foreach ( $stuff in $group.Groups )
    #set( $foo = "$parent$stuff.Name > ")
    $foo
    #recurse ( $stuff $foo )
  #end
#end

Turn on localcontext, and you should be golden...

Heres what I get...

<html>
<body>
      one > 
          one > one one >
          one > one one > one one one >
              one > one two >
            one > one three >
              two >
          two > two one >
            two > two two >
          </body>
</html>

Apologies again :)

Geir


On 11/28/01 3:46 PM, "Tomoki Tsuchida" <tt...@studioyk.dhs.org> wrote:

> Thanks for your help again.  Well I thought about it too, so I tried:
> 
> #macro ( recurse $group $parent )
> #foreach ( $stuff in $group.Groups )
> $parent$stuff.Name<br>
> #set($title = "$parent$stuff.Name &gt; ")
> #recurse ( $stuff $title )
> #end
> #end
> 
> What this produces is:
> 
> one
> one > one one
> one > one one > one one one
> one > one one > one one one > one two
> one > one one > one one one > one two > one three
> two
> two > two one
> two > two one > two two
> 
> So, in this case the problem is that $title doesn't have a local scope, i.e.
> every time #recurse is called inside #foreach it modifies the $title of the
> caller too.  I need to think more about why it *doesn't* do it for the root
> groups ('two' is on the same level as 'one'), but anyhow the problem isn't
> really that obvious...
> 
> ----- Original Message -----
> From: "Geir Magnusson Jr." <ge...@optonline.net>
> To: <ve...@jakarta.apache.org>
> Sent: Wednesday, November 28, 2001 2:58 PM
> Subject: Re: Question on recursion
> 
> 
>> Sorry about the 'red herring' there.
>> 
>> Forget the localscope.  You don't need it.
>> 
>> I think that the problem, as you touched on it, is that you are passing in
>> the whole "" string literal, and it is getting evaluated inside the VM.
>> 
>> So do this
>> 
>>  #set($title = "$parent$stuff.Name &gt; ")
>>  #recurse( $stuff $title)
>> 
>> And it should work as desired.
>> 
>> Sorry again.
>> 
>> Geir
>> 
>> 
>> 
>> On 11/28/01 2:44 PM, "Tomoki Tsuchida" <tt...@studioyk.dhs.org> wrote:
>> 
>>> Thanks for your help, I didn't know about velocimacro.context.localscope
>>> parameter... I put it in my velocity.properties but it didn't make any
>>> change however.  I'll be checking to see if I'm using the correct
> property
>>> file and everything, but meanwhile, here's a simpler demonstration of
> the
>>> problem:
>>> 
>>> [Recursion.vm]
>>> #macro ( recurse $group $parent )
>>> #foreach ( $stuff in $group.Groups )
>>> $parent$stuff.Name<br>
>>> #recurse ( $stuff "$parent$stuff.Name &gt;" )
>>> #end
>>> #end
>>> 
>>> <html>
>>> <body>
>>> #recurse ( $mygroup "" )
>>> </body>
>>> </html>
>>> 
>>> [in java]
>>> public class Group {
>>>   private String name;
>>>   public List groups = new ArrayList();
>>>   public Group(String name) { this.name = name; }
>>>   public List getGroups() { return this.groups; }
>>>   public String getName() { return this.name; }
>>> }
>>> ..
>>>   Group root = new Group("root");
>>>   Group one = new Group("one");
>>>   Group two = new Group("two");
>>> 
>>>   Group oneb = new Group("one one");
>>>   Group onec = new Group("one two");
>>>   Group oned = new Group("one three");
>>> 
>>>   Group onebb = new Group ("one one one");
>>>   oneb.groups.add(onebb);
>>> 
>>>   one.groups.add(oneb);
>>>   one.groups.add(onec);
>>>   one.groups.add(oned);
>>> 
>>>   Group twob = new Group("two one");
>>>   Group twoc = new Group("two two");
>>>   two.groups.add(twob);
>>>   two.groups.add(twoc);
>>> 
>>>   root.groups.add(one);
>>>   root.groups.add(two);
>>> 
>>>   context.put("mygroup", root);
>>> 
>>> This will produce...
>>> 
>>> one
>>> one one >one one
>>> one one one >one one one >one one one
>>> one two >one two
>>> one three >one three
>>> two
>>> two one >two one
>>> two two >two two
>>> 
>>> I guess another issue is the way velocity resolves variable by name at
> run
>>> time (right?).  So "$parent$stuff.Name &gt;" gets resolved to
> "$stuff.Name
>>> &gt; $stuff.Name &gt;" on the 2nd level, which is not what I want.  In
> the
>>> xmlapp_example it isn't a problem because #recursion is called with just
>>> "$index " (so it gets resolved to "$index $index $index " etc., and
> $index
>>> starts out empty).  Does the local scope option really make velocity
> resolve
>>> the variables before it calls another macro?
>>> 
>>> I'm using velocity 1.2-rc3.
>>> 
>>> Thanks,
>>> Tomoki
>>> 
> 
> 
> 
> --
> To unsubscribe, e-mail:
> <ma...@jakarta.apache.org>
> For additional commands, e-mail:
> <ma...@jakarta.apache.org>
> 

-- 
Geir Magnusson Jr.                                     geirm@optonline.net
System and Software Consulting
"They that can give up essential liberty to obtain a little temporary safety
deserve neither liberty nor safety." - Benjamin Franklin



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Question on recursion

Posted by Tomoki Tsuchida <tt...@studioyk.dhs.org>.
Thanks for your help again.  Well I thought about it too, so I tried:

#macro ( recurse $group $parent )
  #foreach ( $stuff in $group.Groups )
  $parent$stuff.Name<br>
  #set($title = "$parent$stuff.Name &gt; ")
  #recurse ( $stuff $title )
  #end
#end

What this produces is:

one
one > one one
one > one one > one one one
one > one one > one one one > one two
one > one one > one one one > one two > one three
two
two > two one
two > two one > two two

So, in this case the problem is that $title doesn't have a local scope, i.e.
every time #recurse is called inside #foreach it modifies the $title of the
caller too.  I need to think more about why it *doesn't* do it for the root
groups ('two' is on the same level as 'one'), but anyhow the problem isn't
really that obvious...

----- Original Message -----
From: "Geir Magnusson Jr." <ge...@optonline.net>
To: <ve...@jakarta.apache.org>
Sent: Wednesday, November 28, 2001 2:58 PM
Subject: Re: Question on recursion


> Sorry about the 'red herring' there.
>
> Forget the localscope.  You don't need it.
>
> I think that the problem, as you touched on it, is that you are passing in
> the whole "" string literal, and it is getting evaluated inside the VM.
>
> So do this
>
>  #set($title = "$parent$stuff.Name &gt; ")
>  #recurse( $stuff $title)
>
> And it should work as desired.
>
> Sorry again.
>
> Geir
>
>
>
> On 11/28/01 2:44 PM, "Tomoki Tsuchida" <tt...@studioyk.dhs.org> wrote:
>
> > Thanks for your help, I didn't know about velocimacro.context.localscope
> > parameter... I put it in my velocity.properties but it didn't make any
> > change however.  I'll be checking to see if I'm using the correct
property
> > file and everything, but meanwhile, here's a simpler demonstration of
the
> > problem:
> >
> > [Recursion.vm]
> > #macro ( recurse $group $parent )
> > #foreach ( $stuff in $group.Groups )
> > $parent$stuff.Name<br>
> > #recurse ( $stuff "$parent$stuff.Name &gt;" )
> > #end
> > #end
> >
> > <html>
> > <body>
> > #recurse ( $mygroup "" )
> > </body>
> > </html>
> >
> > [in java]
> > public class Group {
> >   private String name;
> >   public List groups = new ArrayList();
> >   public Group(String name) { this.name = name; }
> >   public List getGroups() { return this.groups; }
> >   public String getName() { return this.name; }
> > }
> > ..
> >   Group root = new Group("root");
> >   Group one = new Group("one");
> >   Group two = new Group("two");
> >
> >   Group oneb = new Group("one one");
> >   Group onec = new Group("one two");
> >   Group oned = new Group("one three");
> >
> >   Group onebb = new Group ("one one one");
> >   oneb.groups.add(onebb);
> >
> >   one.groups.add(oneb);
> >   one.groups.add(onec);
> >   one.groups.add(oned);
> >
> >   Group twob = new Group("two one");
> >   Group twoc = new Group("two two");
> >   two.groups.add(twob);
> >   two.groups.add(twoc);
> >
> >   root.groups.add(one);
> >   root.groups.add(two);
> >
> >   context.put("mygroup", root);
> >
> > This will produce...
> >
> > one
> > one one >one one
> > one one one >one one one >one one one
> > one two >one two
> > one three >one three
> > two
> > two one >two one
> > two two >two two
> >
> > I guess another issue is the way velocity resolves variable by name at
run
> > time (right?).  So "$parent$stuff.Name &gt;" gets resolved to
"$stuff.Name
> > &gt; $stuff.Name &gt;" on the 2nd level, which is not what I want.  In
the
> > xmlapp_example it isn't a problem because #recursion is called with just
> > "$index " (so it gets resolved to "$index $index $index " etc., and
$index
> > starts out empty).  Does the local scope option really make velocity
resolve
> > the variables before it calls another macro?
> >
> > I'm using velocity 1.2-rc3.
> >
> > Thanks,
> > Tomoki
> >



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Alignment

Posted by Pavel Babachanakh <Pa...@uib.cherkassy.net>.
Hello all!!!

I have tried to use Velocity Template Engine (version 1.2 rc3).
It's wonderful. But I have a problem and I don't
understand how to resolve it. I will try to explain it with an
example. I wanted to print some text in 2 columns. For this I
wrote the following template:

#set( $list = ["1","12","123","1234"] )

    First        Second
#foreach( $l in $list)
    $l           $l
#end


I got the following output:

    First        Second
    1           1
    12           12
    123           123
    1234           1234

But I want a different output:

    First        Second
    1            1
    12          12
    123        123
    1234      1234

How I can get the output I want?

Thank you for your time.

Sincerely,
Pavel Babachanakh
paul@uib.cherkassy.net



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Question on recursion

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
Sorry about the 'red herring' there.

Forget the localscope.  You don't need it.

I think that the problem, as you touched on it, is that you are passing in
the whole "" string literal, and it is getting evaluated inside the VM.

So do this

 #set($title = "$parent$stuff.Name &gt; ")
 #recurse( $stuff $title)

And it should work as desired.

Sorry again.

Geir



On 11/28/01 2:44 PM, "Tomoki Tsuchida" <tt...@studioyk.dhs.org> wrote:

> Thanks for your help, I didn't know about velocimacro.context.localscope
> parameter... I put it in my velocity.properties but it didn't make any
> change however.  I'll be checking to see if I'm using the correct property
> file and everything, but meanwhile, here's a simpler demonstration of the
> problem:
> 
> [Recursion.vm]
> #macro ( recurse $group $parent )
> #foreach ( $stuff in $group.Groups )
> $parent$stuff.Name<br>
> #recurse ( $stuff "$parent$stuff.Name &gt;" )
> #end
> #end
> 
> <html>
> <body>
> #recurse ( $mygroup "" )
> </body>
> </html>
> 
> [in java]
> public class Group {
>   private String name;
>   public List groups = new ArrayList();
>   public Group(String name) { this.name = name; }
>   public List getGroups() { return this.groups; }
>   public String getName() { return this.name; }
> }
> ..
>   Group root = new Group("root");
>   Group one = new Group("one");
>   Group two = new Group("two");
> 
>   Group oneb = new Group("one one");
>   Group onec = new Group("one two");
>   Group oned = new Group("one three");
> 
>   Group onebb = new Group ("one one one");
>   oneb.groups.add(onebb);
> 
>   one.groups.add(oneb);
>   one.groups.add(onec);
>   one.groups.add(oned);
> 
>   Group twob = new Group("two one");
>   Group twoc = new Group("two two");
>   two.groups.add(twob);
>   two.groups.add(twoc);
> 
>   root.groups.add(one);
>   root.groups.add(two);
> 
>   context.put("mygroup", root);
> 
> This will produce...
> 
> one
> one one >one one
> one one one >one one one >one one one
> one two >one two
> one three >one three
> two
> two one >two one
> two two >two two
> 
> I guess another issue is the way velocity resolves variable by name at run
> time (right?).  So "$parent$stuff.Name &gt;" gets resolved to "$stuff.Name
> &gt; $stuff.Name &gt;" on the 2nd level, which is not what I want.  In the
> xmlapp_example it isn't a problem because #recursion is called with just
> "$index " (so it gets resolved to "$index $index $index " etc., and $index
> starts out empty).  Does the local scope option really make velocity resolve
> the variables before it calls another macro?
> 
> I'm using velocity 1.2-rc3.
> 
> Thanks,
> Tomoki
> 
> ----- Original Message -----
> From: "Geir Magnusson Jr." <ge...@optonline.net>
> To: <ve...@jakarta.apache.org>
> Sent: Wednesday, November 28, 2001 11:14 AM
> Subject: Re: Question on recursion
> 
> 
>> Recursion works fine, but yes, you can step on yourself :)
>> 
>> There is a switch to turn on localscope contexts in VMs.  See the dev
>> guide..
>> 
>> Should be something like
>> 
>> velocimacro.context.localscope = true
>> 
>> I'm a little surprised you are having problems - what version of Velocity?
>> There is an example, examples/xmlapp_example that demonstrats VM
> recursion,
>> has the same thing, there it's passing in an $indent string that keeps
>> changing...
>> 
>> 
>> On 11/28/01 10:48 AM, "Tomoki Tsuchida" <tt...@studioyk.dhs.org> wrote:
>> 
>>> Hello,
>>> 
>>> I've been working on velocity for a while now, and now I'm trying to
> flatten
>>> tree structure in velocity and ran into trouble.  I have two java
> classes,
>>> 'categorygroup' and 'category', and I want to show all of the categories
>>> belonging to category groups in a select list. A category belongs to a
>>> categorygroup, and a categorygroup can belong to another categorygroup.
> So
>>> the classes look like this:
>>> 
>>> public class category {
>>> public String getId() {..}
>>> public String getName() {..}
>>> }
>>> 
>>> public class categorygroup {
>>> public String getName() {.. }
>>> public List /* of category */ getCategories() {..}
>>> public List /* of categorygroup */ getCategorygroups() {..}
>>> }
>>> 
>>> .. and when I have a structure like this (brackets are categories):
>>> 
>>> + [root category 1]
>>> + [root category 2]
>>> + category group 1
>>> - [cat under group 1]
>>> + category group 2
>>>   - [cat under 2]
>>>   - [another cat under 2]
>>> + category group 3
>>>  - [cat under group 3]
>>> 
>>> .. I want to show it like this in the select list:
>>> 
>>> root category 1
>>> root category 2
>>> category group 1 > cat under group 1
>>> category group 1 > category group 2 > cat under 2
>>> category group 1 > category group 2 > another cat under 2
>>> category group 3 > cat under group 3
>>> 
>>> I had to do this in java before and it's pretty easy with recursive
>>> functions.  Now what I want to do is to dump the root categorygroup into
> the
>>> context object and flatten the tree structure using velocimacro instead
> of
>>> java.  And I came up with something like this:
>>> 
>>> #macro ( recurse $group $parentname )
>>> #foreach ( $category in $group.Category )
>>> <option value="$category.Id">$parentname$category.Name
>>> #end
>>> #foreach ( $childgroup in $group.Categorygroup )
>>> #recurse ( $childgroup "$parentname$childgroup.Name &gt; " )
>>> #end
>>> #end
>>> 
>>> ...
>>> 
>>> <select>
>>> #recurse( $mygroup "" )
>>> </select>
>>> 
>>> I looked at the XML tree example first and came up with the macro.  The
>>> problem is, it doesn't work like the way I want it to.  If you run this
>>> macro with the aforementioned data set it will render something like:
>>> 
>>> root category 1
>>> root category 2
>>> category group 1 > cat under group 1
>>> category group 2 > category group 2 > cat under 2
>>> category group 2 > category group 2 > another cat under 2
>>> category group 2 > category group 2 > category group 3 > another cat
> under 2
>>> category group 2 > category group 2 > category group 3 > cat under group
> 3
>>> 
>>> I think the problem is that everything is evaluated on a global scope,
> i.e.
>>> '$childgroup' and '$parentname' gets overwritten every time the child
>>> recursive function is called.  Is there any way in velocity to declare a
>>> local-scope variable inside a macro?  I guess I should be able to
> rewrite
>>> the same logic without using recursion, but I can't really think of how
> I'd
>>> go about doing that either :-p  I could also do it easily within java,
> but
>>> then it defeats the purpose of separating presentation from logic so I
>>> really don't want to do it.
>>> 
>>> Thanks,
>>> Tomoki
>>> 
>>> 
>>> 
>>> --
>>> To unsubscribe, e-mail:
>>> <ma...@jakarta.apache.org>
>>> For additional commands, e-mail:
>>> <ma...@jakarta.apache.org>
>>> 
>> 
>> --
>> Geir Magnusson Jr.     geirm@optonline.net
>> System and Software Consulting
>> "Whoever would overthrow the liberty of a nation must begin by subduing
> the
>> freeness of speech." - Benjamin Franklin
>> 
>> 
>> 
>> --
>> To unsubscribe, e-mail:
> <ma...@jakarta.apache.org>
>> For additional commands, e-mail:
> <ma...@jakarta.apache.org>
>> 
>> 
> 
> 
> --
> To unsubscribe, e-mail:
> <ma...@jakarta.apache.org>
> For additional commands, e-mail:
> <ma...@jakarta.apache.org>
> 

-- 
Geir Magnusson Jr.                                     geirm@optonline.net
System and Software Consulting
"He who throws mud only loses ground." - Fat Albert


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Question on recursion

Posted by Tomoki Tsuchida <tt...@studioyk.dhs.org>.
Thanks for your help, I didn't know about velocimacro.context.localscope
parameter... I put it in my velocity.properties but it didn't make any
change however.  I'll be checking to see if I'm using the correct property
file and everything, but meanwhile, here's a simpler demonstration of the
problem:

[Recursion.vm]
#macro ( recurse $group $parent )
  #foreach ( $stuff in $group.Groups )
  $parent$stuff.Name<br>
  #recurse ( $stuff "$parent$stuff.Name &gt;" )
  #end
#end

<html>
<body>
#recurse ( $mygroup "" )
</body>
</html>

[in java]
  public class Group {
    private String name;
    public List groups = new ArrayList();
    public Group(String name) { this.name = name; }
    public List getGroups() { return this.groups; }
    public String getName() { return this.name; }
  }
..
    Group root = new Group("root");
    Group one = new Group("one");
    Group two = new Group("two");

    Group oneb = new Group("one one");
    Group onec = new Group("one two");
    Group oned = new Group("one three");

    Group onebb = new Group ("one one one");
    oneb.groups.add(onebb);

    one.groups.add(oneb);
    one.groups.add(onec);
    one.groups.add(oned);

    Group twob = new Group("two one");
    Group twoc = new Group("two two");
    two.groups.add(twob);
    two.groups.add(twoc);

    root.groups.add(one);
    root.groups.add(two);

    context.put("mygroup", root);

This will produce...

one
one one >one one
one one one >one one one >one one one
one two >one two
one three >one three
two
two one >two one
two two >two two

I guess another issue is the way velocity resolves variable by name at run
time (right?).  So "$parent$stuff.Name &gt;" gets resolved to "$stuff.Name
&gt; $stuff.Name &gt;" on the 2nd level, which is not what I want.  In the
xmlapp_example it isn't a problem because #recursion is called with just
"$index " (so it gets resolved to "$index $index $index " etc., and $index
starts out empty).  Does the local scope option really make velocity resolve
the variables before it calls another macro?

I'm using velocity 1.2-rc3.

Thanks,
Tomoki

----- Original Message -----
From: "Geir Magnusson Jr." <ge...@optonline.net>
To: <ve...@jakarta.apache.org>
Sent: Wednesday, November 28, 2001 11:14 AM
Subject: Re: Question on recursion


> Recursion works fine, but yes, you can step on yourself :)
>
> There is a switch to turn on localscope contexts in VMs.  See the dev
> guide..
>
> Should be something like
>
> velocimacro.context.localscope = true
>
> I'm a little surprised you are having problems - what version of Velocity?
> There is an example, examples/xmlapp_example that demonstrats VM
recursion,
> has the same thing, there it's passing in an $indent string that keeps
> changing...
>
>
> On 11/28/01 10:48 AM, "Tomoki Tsuchida" <tt...@studioyk.dhs.org> wrote:
>
> > Hello,
> >
> > I've been working on velocity for a while now, and now I'm trying to
flatten
> > tree structure in velocity and ran into trouble.  I have two java
classes,
> > 'categorygroup' and 'category', and I want to show all of the categories
> > belonging to category groups in a select list. A category belongs to a
> > categorygroup, and a categorygroup can belong to another categorygroup.
So
> > the classes look like this:
> >
> > public class category {
> > public String getId() {..}
> > public String getName() {..}
> > }
> >
> > public class categorygroup {
> > public String getName() {.. }
> > public List /* of category */ getCategories() {..}
> > public List /* of categorygroup */ getCategorygroups() {..}
> > }
> >
> > .. and when I have a structure like this (brackets are categories):
> >
> > + [root category 1]
> > + [root category 2]
> > + category group 1
> > - [cat under group 1]
> > + category group 2
> >   - [cat under 2]
> >   - [another cat under 2]
> > + category group 3
> >  - [cat under group 3]
> >
> > .. I want to show it like this in the select list:
> >
> > root category 1
> > root category 2
> > category group 1 > cat under group 1
> > category group 1 > category group 2 > cat under 2
> > category group 1 > category group 2 > another cat under 2
> > category group 3 > cat under group 3
> >
> > I had to do this in java before and it's pretty easy with recursive
> > functions.  Now what I want to do is to dump the root categorygroup into
the
> > context object and flatten the tree structure using velocimacro instead
of
> > java.  And I came up with something like this:
> >
> > #macro ( recurse $group $parentname )
> > #foreach ( $category in $group.Category )
> > <option value="$category.Id">$parentname$category.Name
> > #end
> > #foreach ( $childgroup in $group.Categorygroup )
> > #recurse ( $childgroup "$parentname$childgroup.Name &gt; " )
> > #end
> > #end
> >
> > ...
> >
> > <select>
> > #recurse( $mygroup "" )
> > </select>
> >
> > I looked at the XML tree example first and came up with the macro.  The
> > problem is, it doesn't work like the way I want it to.  If you run this
> > macro with the aforementioned data set it will render something like:
> >
> > root category 1
> > root category 2
> > category group 1 > cat under group 1
> > category group 2 > category group 2 > cat under 2
> > category group 2 > category group 2 > another cat under 2
> > category group 2 > category group 2 > category group 3 > another cat
under 2
> > category group 2 > category group 2 > category group 3 > cat under group
3
> >
> > I think the problem is that everything is evaluated on a global scope,
i.e.
> > '$childgroup' and '$parentname' gets overwritten every time the child
> > recursive function is called.  Is there any way in velocity to declare a
> > local-scope variable inside a macro?  I guess I should be able to
rewrite
> > the same logic without using recursion, but I can't really think of how
I'd
> > go about doing that either :-p  I could also do it easily within java,
but
> > then it defeats the purpose of separating presentation from logic so I
> > really don't want to do it.
> >
> > Thanks,
> > Tomoki
> >
> >
> >
> > --
> > To unsubscribe, e-mail:
> > <ma...@jakarta.apache.org>
> > For additional commands, e-mail:
> > <ma...@jakarta.apache.org>
> >
>
> --
> Geir Magnusson Jr.     geirm@optonline.net
> System and Software Consulting
> "Whoever would overthrow the liberty of a nation must begin by subduing
the
> freeness of speech." - Benjamin Franklin
>
>
>
> --
> To unsubscribe, e-mail:
<ma...@jakarta.apache.org>
> For additional commands, e-mail:
<ma...@jakarta.apache.org>
>
>


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: Question on recursion

Posted by "Geir Magnusson Jr." <ge...@optonline.net>.
Recursion works fine, but yes, you can step on yourself :)

There is a switch to turn on localscope contexts in VMs.  See the dev
guide..

Should be something like

velocimacro.context.localscope = true

I'm a little surprised you are having problems - what version of Velocity?
There is an example, examples/xmlapp_example that demonstrats VM recursion,
has the same thing, there it's passing in an $indent string that keeps
changing...


On 11/28/01 10:48 AM, "Tomoki Tsuchida" <tt...@studioyk.dhs.org> wrote:

> Hello,
> 
> I've been working on velocity for a while now, and now I'm trying to flatten
> tree structure in velocity and ran into trouble.  I have two java classes,
> 'categorygroup' and 'category', and I want to show all of the categories
> belonging to category groups in a select list. A category belongs to a
> categorygroup, and a categorygroup can belong to another categorygroup. So
> the classes look like this:
> 
> public class category {
> public String getId() {..}
> public String getName() {..}
> }
> 
> public class categorygroup {
> public String getName() {.. }
> public List /* of category */ getCategories() {..}
> public List /* of categorygroup */ getCategorygroups() {..}
> }
> 
> .. and when I have a structure like this (brackets are categories):
> 
> + [root category 1]
> + [root category 2]
> + category group 1
> - [cat under group 1]
> + category group 2
>   - [cat under 2]
>   - [another cat under 2]
> + category group 3
>  - [cat under group 3]
> 
> .. I want to show it like this in the select list:
> 
> root category 1
> root category 2
> category group 1 > cat under group 1
> category group 1 > category group 2 > cat under 2
> category group 1 > category group 2 > another cat under 2
> category group 3 > cat under group 3
> 
> I had to do this in java before and it's pretty easy with recursive
> functions.  Now what I want to do is to dump the root categorygroup into the
> context object and flatten the tree structure using velocimacro instead of
> java.  And I came up with something like this:
> 
> #macro ( recurse $group $parentname )
> #foreach ( $category in $group.Category )
> <option value="$category.Id">$parentname$category.Name
> #end
> #foreach ( $childgroup in $group.Categorygroup )
> #recurse ( $childgroup "$parentname$childgroup.Name &gt; " )
> #end
> #end
> 
> ...
> 
> <select>
> #recurse( $mygroup "" )
> </select>
> 
> I looked at the XML tree example first and came up with the macro.  The
> problem is, it doesn't work like the way I want it to.  If you run this
> macro with the aforementioned data set it will render something like:
> 
> root category 1
> root category 2
> category group 1 > cat under group 1
> category group 2 > category group 2 > cat under 2
> category group 2 > category group 2 > another cat under 2
> category group 2 > category group 2 > category group 3 > another cat under 2
> category group 2 > category group 2 > category group 3 > cat under group 3
> 
> I think the problem is that everything is evaluated on a global scope, i.e.
> '$childgroup' and '$parentname' gets overwritten every time the child
> recursive function is called.  Is there any way in velocity to declare a
> local-scope variable inside a macro?  I guess I should be able to rewrite
> the same logic without using recursion, but I can't really think of how I'd
> go about doing that either :-p  I could also do it easily within java, but
> then it defeats the purpose of separating presentation from logic so I
> really don't want to do it.
> 
> Thanks,
> Tomoki
> 
> 
> 
> --
> To unsubscribe, e-mail:
> <ma...@jakarta.apache.org>
> For additional commands, e-mail:
> <ma...@jakarta.apache.org>
> 

-- 
Geir Magnusson Jr.     geirm@optonline.net
System and Software Consulting
"Whoever would overthrow the liberty of a nation must begin by subduing the
freeness of speech." - Benjamin Franklin



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>