हैशमैप कुंजियों पर चलने वाले फ़्रीमार्कर


87

फ़्रीमार्कर के पास दो संग्रह डेटाटाइप्स, सूचियाँ और हैशमैप है क्या हैशमैप कुंजियों पर पुनरावृति करने का एक तरीका है जैसे हम सूचियों के साथ करते हैं?

इसलिए अगर मेरे पास डेटा के साथ एक संस्करण है, तो हम कहते हैं:

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

मैं उपयोगकर्ता के सभी गुणों को उनके मूल्य के साथ प्रिंट करना चाहूंगा। यह अमान्य है, लेकिन लक्ष्य स्पष्ट है:

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

जवाबों:


106

संपादित करें: FreeMarker 2.3.25 और इसके साथ इस समाधान का उपयोग न करें, विशेष रूप से नहीं .get(prop)। अन्य उत्तर देखें।

आप अंतर्निहित कुंजी फ़ंक्शन का उपयोग करते हैं, उदाहरण के लिए यह काम करना चाहिए:

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

4
नवीनतम संस्करण में वाक्यविन्यास अलग है, जैसा कि मैंने अपने उत्तर में पोस्ट किए गए लिंक में चित्रित किया है। मुझे लगता है कि यह एक पुराना सवाल है, लेकिन यह Google पर उच्च रैंक आता है।
निक स्पेसक

26
सिर्फ एक नोट - आप ${user[prop]}एक शॉर्टहैंड के रूप में उपयोग कर सकते हैं
Bozho

यह एक प्रदर्शन रिसाव है: प्रत्येक कुंजी के लिए, इसे मूल्य को पुनः प्राप्त करना होगा। एंट्रीसेट () पर ओवररेट करने से वह समस्या नहीं होती है।
ज्योफ्री डी स्मेट

4
$ {उपयोगकर्ता [प्रोप]} होना चाहिए
DNS

कॉन्फ़िगरेशन के साथ डिफ़ॉल्ट user[prop]काम करता है जहाँ तक propएक है String(अन्यथा आपको user?api.get(prop)वर्तमान में आवश्यकता है), लेकिन खबरदार, कुछ चौखटे (जैसे स्ट्रट्स, मुझे विश्वास है) अब एक पदावनत सेटअप का उपयोग करते हैं जहां विधि नाम Mapकुंजियों के साथ मिलाया जाता है, और इसलिए यदि propsऐसा होता है userजावा ऑब्जेक्ट में एक विधि का नाम हो , आपको जो भी मतलब था, उसके बजाय आप विधि प्राप्त करें। यही कारण है कि उन विरासत सेटअप में वे हमेशा उपयोग करते हैं user.get(prop)
ddekany

52

FYI करें, ऐसा लगता है कि मानों को पुनः प्राप्त करने के लिए वाक्यविन्यास के अनुसार बदल गया है:

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
यह वाक्य रचना अलग कैसे है?
पार्कर

1
अच्छा जवाब;; ध्यान दें कि आपको अपने मूल्य को प्रिंट करते समय अशक्त के लिए एक चेक करना पड़ सकता है, <#if h [कुंजी] ??> $ {कुंजी} = $ {h [कुंजी]}; </ # अगर>
ब्रैड पार्क्स

1
वाक्यविन्यास नहीं बदला गया था। दोनों [key]और .get(key)प्राचीन काल से ही मौजूद है। .get(key)FTL के लिए कोई विशेष नहीं है, यह सिर्फ उस सार्वजनिक जावा विधि को बुला रहा है। लेकिन आप इसका उपयोग केवल तभी कर सकते हैं जब Mapविधियों को उजागर करने के लिए FreeMarker को कॉन्फ़िगर किया गया था ।
ddekany 18

पुनरावृति करते समय, मुझे विधियाँ मिलती हैं (getClass, hashCode, equals, get, toString, class) ... हालाँकि, मैं 'id' जैसी किसी भी गुण को नहीं देख रहा हूँ, जिसे मैं एक सूची प्राप्त करना चाहता हूँ। कोई सुझाव है कि उस हैश से गैर-विधि गुणों की सूची कैसे प्राप्त करें? मुझे उन संपत्ति के नामों को जानने की जरूरत है। : |
मैक्सक्रॉफ्ट

47

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>

हालांकि, कुछ वास्तव में पुराने फ्रीमर्कर एकीकरण एक अजीब कॉन्फ़िगरेशन का उपयोग करते हैं, जहां सार्वजनिक Mapतरीके (जैसे getClass) कुंजी के रूप में दिखाई देते हैं। ऐसा तब होता है जब वे एक शुद्ध BeansWrapper(के बजाय DefaultObjectWrapper) का उपयोग कर रहे होते हैं जिनकी simpleMapWrapperसंपत्ति बची हुई थी false। आपको इस तरह के सेटअप से बचना चाहिए, क्योंकि यह वास्तविक Mapप्रविष्टियों के साथ तरीकों को मिलाता है । लेकिन अगर आप इस तरह की दुर्भाग्यपूर्ण सेटअप में चलाने, जिस तरह से स्थिति से बचने के लिए इस तरह के रूप उजागर जावा तरीकों का उपयोग कर रहा है, user.entrySet(), user.get(key), आदि, और नहीं की तरह टेम्पलेट भाषा निर्माणों का उपयोग कर ?keysया user[key]


यह पूरी तरह से काम करता है। लेकिन, मुझे स्प्रिंग्ससोर्स IDE में त्रुटियाँ दिखाई दे रही हैं। किसी भी विचार यह कैसे तय करने के लिए? धन्यवाद
harshvmb

@harshvmb क्या त्रुटियां हैं? क्या यह शायद एक पुराने FreeMarker प्लगइन का उपयोग करता है, जो एक पुराने FreeMarker संस्करण के साथ आता है?
ddekany

ऐसा मत सोचो। Jboss टूल से नवीनतम एक डाउनलोड किया है। मैं अन्य मशीन पर कोशिश करूँगा और आपको बता दूँगा।
हरशवम्ब

@harshavmb यदि आप कुछ दर्ज करते हैं ${x?nosuchthing}और आप उस पर मंडराते हैं, तो दिखाया गया त्रुटि संदेश बताएगा कि यह किस FreeMarker संस्करण का उपयोग करता है। यह होना चाहिए 2.3.25-incubating
ddekany

अजीब है, मैं सिर्फ मैक में कोशिश की और इस मुद्दे को दोहराने नहीं कर सका। मुद्दा केवल मेरे vm के साथ लगता है। मैं जार संस्करण पर एक नजर डालूंगा। हालांकि, यह संपादक में सिर्फ एक त्रुटि है, लेकिन कोड सही तरीके से निष्पादित किया गया था।
हरशवम्ब

12

यदि एक्सपोज़.एफ़े या एक्सपोज़.एलएल के एक्सपोज़र स्तर के साथ बीन्सवॉपर का उपयोग किया जाता है, तो प्रवेश सेट को पुनरावृत्त करने के मानक जावा दृष्टिकोण को नियोजित किया जा सकता है:

उदाहरण के लिए, निम्नलिखित फ़्रीगमर में काम करेगा (कम से कम संस्करण 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

4
यह केवल freemarker.ext.beans.BeansWrapperऑब्जेक्ट रैपर के रूप में उपयोग करते समय काम करता है । अन्यथा Maps स्वचालित रूप से एक ऐसी SimpleHashवस्तु में लिपट जाएगा जो समर्थन नहीं करती है #entrySet()। (देखें freemarker.sourceforge.net/docs/api/fremarker/template/… )
कोराटोर

आप सही हैं, और मैंने आपकी टिप्पणी को दर्शाने के लिए अपना उत्तर अपडेट कर दिया है। अच्छा लग रहा है!
रीस

1
उपरोक्त एफटीएल के अंदर बनाए गए हैश के लिए अच्छी तरह से काम नहीं करेगा विशेष रूप से यदि आप बीनव्रेपर के साथ स्प्रिंग फ्रीडमर रिज़ॉल्वर का उपयोग कर रहे हैं। Ftl फ़ाइल के अंदर घोषित हैश लिपटे नहीं है और अभी भी सिर्फ एक हैश उपयोग करने योग्य है?
skipy

1
शुद्ध का उपयोग न करें BeansWrapper, कम से कम इसकी चूक के साथ नहीं, जहां simpleMapWrapperहै false। यह बहुत भ्रमित हो जाता है, क्योंकि यह विधि के नामों के साथ कुंजियों को मिलाता है। यदि आपको कॉल करने की आवश्यकता है entrySet(), तो बस एक "क्लीन" ऑब्जेक्ट रैपर का उपयोग करें, जैसे कि डिफ़ॉल्ट एक, और लिखें map?api.entrySet()यदि आपको जावा एपीआई को कुंजी के बजाय एक्सेस करने की आवश्यकता है।
ddekany

2

वस्तुओं को निष्क्रिय करना

यदि आपकी मैप कीज़ एक ऑब्जेक्ट है और स्ट्रिंग नहीं है, तो आप इसे फ्रीमार्कर का उपयोग करके इटर्रेट कर सकते हैं।

1) मानचित्र को नियंत्रक में एक सूची में परिवर्तित करें:

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

2) फ़्रीमार्कर टेम्प्लेट में मानचित्र को कुंजी और ऑब्जेक्ट में ऑब्जेक्ट तक पहुँचते हुए मैप करें:

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

1

पूर्णता के लिए, यह ध्यान देने योग्य है कि हाल के दिनों से फ़्रीमार्क में खाली संग्रह का एक सभ्य संचालन है।

तो नक्शे को पुनरावृत्त करने का सबसे सुविधाजनक तरीका है:

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

कोई और <#if ...>रैपर नहीं ।


सबसे बढ़िया उत्तर। धन्यवाद।
उदाहरणार्थ

0

आप अपने जावा प्रोग्राम में जो कुंजी सेट करते हैं, उसे एक्सेस करने के लिए आप एक ही उद्धरण का उपयोग कर सकते हैं।

यदि आप जावा में इस तरह से एक मैप सेट करते हैं

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

तो फिर आप इस तरह से Fremarker में 'हैश' के सदस्यों तक पहुँच सकते हैं -

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

आउटपुट:

a
b

यह दर्शाता है कि अलग-अलग कुंजियों को कैसे संबोधित किया जाए, लेकिन सवाल पूछता है कि कैसे करें
लैम्बर्ट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.