Re: Dynamic list

Daniel Dekany <[email protected]>
Newsgroups gmane.comp.web.freemarker.user
Message-ID <[email protected]>
Wednesday, February 25, 2009, 4:48:56 PM, Kirill wrote:
> Hi Daniel,
>
> Here is the scenario. Let's say I have this XML as an input (data- 
> model):
> <root>
>         <parent1>
>                 <child1>text</child1>
>                 <child1>text</child1>
>         </parent1>
>         <parent2>text</parent2>
>         <parent2>text</parent2>
>         <parent2>text</parent2>
> </root>
>
> Based on the template I use and more specifically, this part  
> (simplified):
>
> <#macro @element>
>     <#-- this emits an opening tag -->
>     <${.node?node_name} <#if!.node?children?has_content>/</#if>>
>
>     <#-- this emits variable name, with proper formatting -->
>     <#if .node?children?size = 1>
>         ${r"${"}${.node?node_name}${r"}"}
>     </#if>
>
>     <#if .node?children?size &gt; 0>
>         <#recurse>
>     </#if>
>
>     <#-- this emits closing tag -->
>     <#if .node?children?has_content>
>     </${.node?node_name}>
>     </#if>
> </#macro>
>
>
> The output will be this:
>
> <root>
>         <parent1>
>                 <child1>${child1}</child1>
>                 <child1>${child1}</child1>
>         </parent1>
>         <parent2>${child2}</parent2>
>         <parent2>${child2}</parent2>
>         <parent2>${child2}</parent2>
> </root>
>                 
> What I'd like to achieve is this:
>
> <root>
>         <parent1>
>                 <#list child1 as childItem1>
>                         <child1>${childItem1}</child1>
>                 </#list>
>         </parent1>
>         <#list parent2 as parentItem2>
>                 <parent2>${parentItem2}
>         </#list>
> </root>
>
> So, basically, instead of outputting tags with the same name, create a
> list of such items.
>
> In this particular case, Freemarker has to detect if there is more  
> than one element with a same name,
> and if there is - create a list of those elements.
>
> I've managed to find a workaround, with a simple test variable, and by
> appending [0], [1], etc to variable names.
> But <#list> should look a lot better though, and easier to understand
> for template users.

Ugh... not exactly an MVC application of the template language. I
prefer pushing much more "cooked" data-models to templates, otherwise
they cease to be templates (template: a program that looks similarly
to its own output). Anyway, if you want to do everything in the
template, I think that to do this with #list, you had to know the list
of all element *names* that will occur as a child. I mean, regardless
of how many times a certain kind of child occurs, that list would
contain its name only once. Let's say you write a function for this,
"allChildNames". Then you could do something like this:

<#list allChildNames(.node) as childName>
  <#list .node[childName] as child>
     ${child}
  </#list>
</#list>

The allChildNames can be easily implemented even in pure FTL, using
the trick:

  <#if names?contains(newName)>
    <#assign names = names + [newName]>
  </#if>

but for bigger XML-s that will *quickly* become slow, so then you
better implement it in Java (see
freemarker.template.TemplateMethodModelEx), using a HashSet or
something.


> Thanks again for your input.
>
> Cheers,
> Kirill

-- 
Best regards,
 Daniel Dekany


------------------------------------------------------------------------------
Open Source Business Conference (OSBC), March 24-25, 2009, San Francisco, CA
-OSBC tackles the biggest issue in open source: Open Sourcing the Enterprise
-Strategies to boost innovation and cut costs with open source participation
-Receive a $600 discount off the registration fee with the source code: SFAD
http://p.sf.net/sfu/XcvMzF8H
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.