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] 的工作原理是propString(否则您目前需要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)等,而不是使用模板语言结构,例如?keysuser[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 作为对象包装器时有效。否则Maps 将自动包装到不支持#entrySet()SimpleHash 对象中。 (见freemarker.sourceforge.net/docs/api/freemarker/template/…) 你是对的,我已经更新了我的答案以反映你的评论。好看! 如果您将 Spring Freemarker 解析器与 BeanWrapper 一起使用,则上述内容对于在 FTL 中创建的散列效果不佳。在 Ftl 文件中声明的散列没有被包装,仍然只是一个使用 ?keys 可迭代的散列。 不要使用纯BeansWrapper,至少不要使用其默认值,其中simpleMapWrapperfalse。它变得非常混乱,因为它将键与方法名称混合在一起。如果您需要调用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>

不再有 &lt;#if ...&gt; 包装器。

【讨论】:

最佳答案。谢谢。【参考方案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 元素

如何使用带有 hashmap 变量的 freemarker 列表

在迭代期间更改 HashMap 键

HashMap:以随机顺序迭代键值对

如何在迭代时从 HashMap 中删除键? [复制]

递归或迭代地从 HashMap 中检索键值组合