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 > 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