Accessing data model maps that use a non-string key
Background
This article describes how to access data model maps (such as gScopeCounts
) that use non-string keys.
Details
Normally you can access a map value (e.g. rmcs counts) using something like response.resultPacket.rmcs["key"]
However this will only work if the key is a string type.
i.e. if you look at the XML you will see the rmcs
and gScopeCounts
maps from the data model.
<rmcs>
<entry>
<string>type:Publication</string>
<int>17</int>
</entry>
</rmcs>
<gScopeCounts>
<entry>
<int>1</int>
<int>76</int>
</entry>
</gScopeCounts>
For the gScopeCounts
field you will see that the key and value are both integers.
This is due to how Freemarker wraps Java objects within the template. See: http://fmpp.sourceforge.net/freemarker/app_faq.html#faq_question_14 for further information.
Example and workaround
The following freemarker macro is designed to return the gscope count given the gscope number. The gscope counts are a map, but with an integer key.
<#-- @begin Gscope facet item -->
<#---
Prints item containing a specified gscope facet and the corresponding count.
-->
<#macro gScopeFacetItem gParam facet="" category="">
<#if response?exists && response.facets?exists>
<#assign facetKey="f.${facet}|${gParam}"/>
<#assign gp=gParam?number>
<#if response.resultPacket.GScopeCounts[gp]?exists>
<input type="checkbox" name=${facetKey}" <#if question.inputParameterMap[facetKey]?exists> checked="checked"</#if> value="${category}"> ${category} (${response.resultPacket.GScopeCounts[gp?int]})
<#else>
<input type="checkbox" name="${facetKey}" disabled="disabled" value="${category}"> ${category} (0)
</#if>
</#if>
</#macro>
However when you use the square bracket notation e.g. response.resultPacket.GScopeCounts[gParam]
freemarker automatically converts the key supplied to a string meaning the check will fail.
The above code generates an error.
Expected number, sequence, or string. response.resultPacket.GScopeCounts evaluated instead to freemarker.template.SimpleHash on line 88, column 14 in conf/example/example.ftl.
Other versions of the <#if>
statement also fail:
<#if response.resultPacket.GScopeCounts[gp?int]?exists>
<#if response.resultPacket.GScopeCounts(gp)?exists>
<#if response.resultPacket.GScopeCounts(gp?int)?exists>
The following is a workaround, but it’s a bit messy:
<#-- @begin Gscope facet item -->
<#---
Prints item containing a specified gscope facet and the corresponding count.
-->
<#macro gScopeFacetItem gParam facet="" category="">
<#if response?exists && response.facets?exists>
<#assign facetKey="f.${facet}|${gParam}"/>
<#assign keys = response.resultPacket.GScopeCounts?keys>
<#assign vals = response.resultPacket.GScopeCounts?values>
<#if keys?seq_contains(gParam?number)>
<#list keys as key>
<#if key?number == gParam?number>
<input type="checkbox" name=${facetKey}" <#if question.inputParameterMap[facetKey]?exists> checked="checked"</#if> value="${category}"> ${category} (${vals[key_index]})
</#if>
</#list>
<#else>
<input type="checkbox" name="${facetKey}" disabled="disabled" value="${category}"> ${category} (0)
</#if>
</#if>
</#macro>