Freemarker 迭代 hashmap 键
Posted
技术标签:
【中文标题】Freemarker 迭代 hashmap 键【英文标题】:Freemarker iterating over hashmap keys 【发布时间】:2010-12-02 15:17:51 【问题描述】:Freemarker 有两种集合数据类型,列表和哈希图 有没有办法像处理列表一样迭代 hashmap 键?
所以,如果我有一个带有数据的 var,可以说:
user :
name : "user"
email : "looser@everything.com"
homepage : "http://nosuchpage.org"
我想打印用户的所有属性及其值。 这是无效的,但目标很明确:
<#list user.props() as prop>
$prop = $user.get(prop)
</#list>
【问题讨论】:
【参考方案1】:编辑:不要将此解决方案与 FreeMarker 2.3.25 及更高版本一起使用,尤其是 .get(prop)
。查看其他答案。
您使用内置的keys 函数,例如这应该工作:
<#list user?keys as prop>
$prop = $user.get(prop)
</#list>
【讨论】:
语法在最新版本中有所不同,如我在答案中发布的链接所示。我知道这是一个老问题,但它在 Google 上排名很高。 只是一个注释 - 您可以使用$user[prop]
作为速记
这是一个性能泄漏:对于每个键,它都需要检索值。遍历 entrySet() 没有这个问题。
应该是 $user[prop]
使用配置默认值user[prop]
的工作原理是prop
是String
(否则您目前需要user?api.get(prop)
),但请注意,某些框架(我相信像Struts)使用一个现在已弃用的设置,其中方法名称与 Map
键混合,因此如果 props
的值恰好是 user
Java 对象中的方法名称,那么您将获得方法而不是您的意思。这也是为什么在那些旧设置中他们总是使用user.get(prop)
。【参考方案2】:
仅供参考,检索值的语法似乎已根据以下内容更改:
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>
【讨论】:
这个语法有何不同? 好答案 ;-) 请注意,在打印您的值时,您可能需要检查空值, $key = $h[key ]; #if> 语法没有改变。[key]
和 .get(key)
自古就存在。 .get(key)
对 FTL 没有什么特别之处,它只是调用公共 Java 方法。但只有在 FreeMarker 配置为公开 Map
方法时才能使用它。
迭代时,我得到了方法(getClass、hashCode、equals、get、toString、class)......但是,我没有看到像“id”这样的任何属性,这就是我想得到一份清单。任何建议如何从该哈希中获取非方法属性列表?我需要知道这些属性名称。 :|【参考方案3】:
从 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
),其simpleMapWrapper
属性保留在false
上。您应该避免这样的设置,因为它将方法与真正的 Map
条目混合在一起。但是如果你遇到这种不幸的设置,逃避这种情况的方法是使用暴露的Java方法,例如user.entrySet()
,user.get(key)
等,而不是使用模板语言结构,例如?keys
或user[key]
.
【讨论】:
这非常有效。但是,我在 springsource IDE 中看到了错误。知道如何修复它吗?谢谢 @harshavmb 什么错误?它是否使用过时的 FreeMarker 插件,该插件带有旧的 FreeMarker 版本? 不这么认为。已经从 jboss tools 下载了最新的一个。我会在其他机器上试一试,然后告诉你。 @harshavmb 如果您输入$x?nosuchthing
之类的内容并将鼠标悬停在它上面,显示的错误消息将告诉您它使用的是哪个 FreeMarker 版本。应该是2.3.25-incubating
。
奇怪,我刚在 Mac 上试过,无法复制问题。问题似乎只与我的虚拟机有关。我会看看jar版本。但是,这只是编辑器中的错误,但代码执行正确。【参考方案4】:
如果使用暴露级别为 Expose.SAFE 或 Expose.ALL 的BeansWrapper,则可以采用迭代条目集的标准 Java 方法:
例如,以下内容适用于 Freemarker(至少从 2.3.19 版开始):
<#list map.entrySet() as entry>
<input type="hidden" name="$entry.key" value="$entry.value" />
</#list>
例如,在 Struts2 中,an extension of the BeanWrapper 与默认的曝光级别一起使用以允许这种迭代方式。
【讨论】:
你真的试过这个吗?因为我在尝试时得到了InvalidReferenceException
,而map?keys
有效。
这仅在使用 freemarker.ext.beans.BeansWrapper
作为对象包装器时有效。否则Map
s 将自动包装到不支持#entrySet()
的SimpleHash
对象中。 (见freemarker.sourceforge.net/docs/api/freemarker/template/…)
你是对的,我已经更新了我的答案以反映你的评论。好看!
如果您将 Spring Freemarker 解析器与 BeanWrapper 一起使用,则上述内容对于在 FTL 中创建的散列效果不佳。在 Ftl 文件中声明的散列没有被包装,仍然只是一个使用 ?keys 可迭代的散列。
不要使用纯BeansWrapper
,至少不要使用其默认值,其中simpleMapWrapper
是false
。它变得非常混乱,因为它将键与方法名称混合在一起。如果您需要调用entrySet()
,只需继续使用“干净”的对象包装器,就像默认的一样,如果您需要访问Java API 而不是键,请编写map?api.entrySet()
。【参考方案5】:
迭代对象
如果您的地图键是一个对象而不是字符串,您可以使用 Freemarker 对其进行迭代。
1) 将地图转换为控制器中的列表:
List<Map.Entry<myObjectKey, myObjectValue>> convertedMap = new ArrayList(originalMap.entrySet());
2)在Freemarker模板中迭代map,访问Key中的对象和Value中的对象:
<#list convertedMap as item>
<#assign myObjectKey = item.getKey()/>
<#assign myObjectValue = item.getValue()/>
[...]
</#list>
【讨论】:
【参考方案6】:为了完整起见,值得一提的是,自最近以来,Freemarker 中的空集合处理得很好。
所以迭代地图最方便的方法是:
<#list tags>
<ul class="posts">
<#items as tagName, tagCount>
<li>$tagName ($tagCount)</li>
</#items>
</ul>
<#else>
<p>No tags found.</p>
</#list>
不再有 <#if ...>
包装器。
【讨论】:
最佳答案。谢谢。【参考方案7】:您可以使用单引号来访问您在 Java 程序中设置的密钥。 如果你像这样在 Java 中设置 Map
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' 的成员 -
$hash['firstname']
$hash['lastname']
输出:
a
b
【讨论】:
显示如何处理单个键,但问题是如何迭代以上是关于Freemarker 迭代 hashmap 键的主要内容,如果未能解决你的问题,请参考以下文章
在 Freemarker 中通过 Enum 键访问 Map 元素