Freemarker遍历哈希映射键


87

Freemarker有两种集合数据类型,即列表和哈希图。有没有一种方法可以像对列表一样遍历哈希图键?

因此,如果我有一个带有数据的变量,则可以说:

user : {
  name : "user"
  email : "looser@everything.com"
  homepage : "http://nosuchpage.org"
}

我想用其值打印所有用户的属性。这是无效的,但目标很明确:

<#list user.props() as prop>
  ${prop} = ${user.get(prop)}
</#list>

Answers:


106

编辑:不要在FreeMarker 2.3.25及更高版本中使用此解决方案,尤其不要使用.get(prop)。查看其他答案。

您使用内置的按键功能,例如,这应该可以工作:

<#list user?keys as prop>
    ${prop} = ${user.get(prop)}
</#list>  

4
语法在最新版本中有所不同,如我在答案中发布的链接所示。我意识到这是一个老问题,但是在Google上排名很高。
Nick Spacek

26
只是一个注释-您可以${user[prop]}用作速记
Bozho

这是性能泄漏:对于每个键,它都需要检索值。遍历entrySet()并没有这个问题。
Geoffrey De Smet

4
应该是$ {user [prop]}
dns 2013年

默认情况下,默认配置user[prop]可以正常prop使用String(否则您user?api.get(prop)当前需要),但是请注意,某些框架(例如Struts,我相信)使用了现在不建议使用的设置,其中方法名称与Map键混合,因此,如果巧合props了如果是userJava对象中的方法名称,则将得到该方法,而不是您的意思。这也是为什么他们总是使用旧式设置的原因user.get(prop)
ddekany

52

仅供参考,看来检索值的语法已根据以下内容进行了更改:

http://freemarker.sourceforge.net/docs/ref_builtins_hash.html

<#assign h = {"name":"mouse", "price":50}>
<#assign keys = h?keys>
<#list keys as key>${key} = ${h[key]}; </#list>

2
这种语法有何不同?
Parker

1
好的答案;-)注意,在打印值时,可能必须检查是否为空,<#if h [key] ??> $ {key} = $ {h [key]}; </#if>
布莱德·帕克斯 Brad Parks)

1
语法没有改变。双方[key].get(key)自古存在。.get(key)FTL没有什么特别的,它只是调用该公共Java方法。但是,只有将FreeMarker配置为公开Map方法时,才能使用它。
ddekany 2014年

迭代时,我得到方法(getClass,hashCode,equals,get,toString,class)...但是,我没有看到任何类似'id'的属性,这是我想要获得的列表。有什么建议如何从该哈希中获取该非方法属性的列表?我需要知道那些属性名称。:|
MaxRocket

46

从2.3.25开始,请按以下步骤操作:

<#list user as propName, propValue>
  ${propName} = ${propValue}
</#list>

请注意,这也适用于非字符串键(与map[key],必须像map?api.get(key)当时那样编写)。

在2.3.25之前,标准解决方案是:

<#list user?keys as prop>
  ${prop} = ${user[prop]}
</#list>

但是,某些真正古老的FreeMarker集成使用一种奇怪的配置,其中公共Map方法(如getClass)作为键出现。发生这种情况的原因是,他们使用的是保留属性的纯BeansWrapper(而不是DefaultObjectWrapper)。您应该避免这种设置,因为它会将方法与实际条目混合在一起。但是,如果你碰上这样倒霉的设置,为了躲避情况的方法是使用公开的Java方法,如,等,并没有使用模板语言结构,如或simpleMapWrapperfalseMapuser.entrySet()user.get(key)?keysuser[key]


这很完美。但是,我在springsource IDE中看到错误。任何想法如何解决?谢谢
harshavmb

@harshavmb什么错误?它是否使用了旧版本的FreeMarker附带的过时的FreeMarker插件?
ddekany

不要这样 从jboss工具下载了最新的。我将在其他机器上尝试并让您知道。
harshavmb

@harshavmb如果输入类似内容${x?nosuchthing}并将其悬停在上面,显示的错误消息将告诉您它使用的FreeMarker版本。应该是2.3.25-incubating
ddekany

奇怪,我只是在Mac中尝试过,无法复制该问题。问题似乎只与我的虚拟机有关。我来看看jar版本。但是,这只是编辑器中的错误,但是代码已正确执行。
harshavmb

12

如果使用BeansWrapper与Expose.SAFE或Expose.ALL,的曝光电平,那么条目组可以采用迭代的标准的Java的方法:

例如,以下内容将在Freemarker中运行(至少从2.3.19版开始):

<#list map.entrySet() as entry>  
  <input type="hidden" name="${entry.key}" value="${entry.value}" />
</#list>

例如,在Struts2中,使用了BeanWrapper的扩展,其暴露级别默认为允许这种迭代方式。


3
您实际尝试过吗?因为我InvalidReferenceException在尝试的同时得到了一份map?keys工作。
kdgregory 2012年

4
这仅在freemarker.ext.beans.BeansWrapper用作对象包装器时有效。否则,Maps将自动包装到SimpleHash不支持的对象中#entrySet()。(见freemarker.sourceforge.net/docs/api/freemarker/template/...
Koraktor

您是正确的,我已经更新了我的答案以反映您的评论。好期待!
2012年

1
如果将Spring Freemarker解析器与BeanWrapper结合使用,则上述内容对于在FTL中创建的哈希不能很好地起作用。Ftl文件中声明的哈希不会包装,并且仍然只是使用?keys可迭代的哈希。
2012年

1
不要使用纯BeansWrapper,至少不会与它的默认值,这里simpleMapWrapperfalse。由于将键与方法名称混合在一起,因此非常混乱。如果需要调用entrySet(),只需继续使用“干净的”对象包装器(如默认的包装器),并map?api.entrySet()在需要访问Java API而不是键的情况下编写。
ddekany

2

迭代对象

如果您的地图键是一个对象而不是字符串,则可以使用Freemarker对其进行迭代。

1)将地图转换为控制器中的列表:

List<Map.Entry<myObjectKey, myObjectValue>> convertedMap  = new ArrayList(originalMap.entrySet());

2)迭代Freemarker模板中的映射,访问Key中的对象和Value中的对象:

<#list convertedMap as item>
    <#assign myObjectKey = item.getKey()/>
    <#assign myObjectValue = item.getValue()/>
    [...]
</#list>

1

为了完整起见,值得一提的是,自最近以来,Freemarker中对空集合进行了不错的处理。

因此,迭代地图的最便捷方法是:

<#list tags>
<ul class="posts">
    <#items as tagName, tagCount>
        <li>{$tagName} (${tagCount})</li>
    </#items>
</ul>
<#else>
    <p>No tags found.</p>
</#list>

没有更多的<#if ...>包装器。


最佳答案。谢谢。
egemen

0

您可以使用单引号来访问您在Java程序中设置的密钥。

如果您这样设置Java地图

Map<String,Object> hash = new HashMap<String,Object>();
hash.put("firstname", "a");
hash.put("lastname", "b");

Map<String,Object> map = new HashMap<String,Object>();
map.put("hash", hash);

然后,您可以像这样在Freemarker中访问“哈希”的成员-

${hash['firstname']}
${hash['lastname']}

输出:

a
b

该页面显示了如何处理单个键,但问题询问如何进行迭代
Lambart
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.