2009-12-17 3 views
15

मुझे पूरा यकीन नहीं है कि यह एक हल करने योग्य समस्या भी है, लेकिन मुझे लगता है कि मेरे पास एक फ्रीमार्कर टेम्पलेट है, मैं टेम्पलेट से पूछने में सक्षम होना चाहता हूं कि यह किस चर का उपयोग करता है।यह पता लगाने के लिए कि यह किस चर का उपयोग करता है, मैं एक फ्रीमार्कर टेम्पलेट का निरीक्षण कैसे कर सकता हूं?

मेरे उद्देश्यों के लिए, हम मान सकते हैं कि फ्रीमार्कर टेम्पलेट बहुत आसान है - बस "रूट लेवल" प्रविष्टियां (इस तरह के टेम्पलेट के लिए मॉडल एक साधारण मानचित्र हो सकता है)। दूसरे शब्दों में, मुझे टेम्पलेट्स को संभालने की आवश्यकता नहीं है जो नेस्टेड संरचनाओं के लिए कॉल करते हैं, आदि

+0

आप मुद्रित करने के लिए क्या मॉडल मूल्यों पर उपलब्ध होते हैं टेम्पलेट संसाधित किया जाता है करना चाहते हैं? या क्या आपको टेम्पलेट में वास्तव में किस चर का उपयोग किया जाता है? '$ {Foo.bar} 'कहें, आप जानना चाहते हैं कि' foo' का उपयोग किया जाएगा?क्या आपको टेम्पलेट संसाधित होने से पहले पता होना चाहिए या इसके बाद हो सकता है? – huynhjl

+0

यदि $ {foo} और $ {bar} टेम्पलेट में हैं, तो मैं जानना चाहता हूं कि "foo" और "bar" का उपयोग किया जाता है। – Jared

उत्तर

1

इससे पहले कि मैं जावा तरफ टेम्पलेट से चर की सूची प्राप्त करने में एक ही काम था और प्रतिबिंब का उपयोग कर, सिवाय इसके कि के लिए किसी भी अच्छा दृष्टिकोण नहीं मिला है मेल खाता है। मुझे यकीन है कि इस डेटा या नहीं पाने के लिए एक बेहतर तरीका है कि क्या वहाँ नहीं कर रहा हूँ, लेकिन यहाँ मेरा दृष्टिकोण है:

public Set<String> referenceSet(Template template) throws TemplateModelException { 
    Set<String> result = new HashSet<>(); 
    TemplateElement rootTreeNode = template.getRootTreeNode(); 
    for (int i = 0; i < rootTreeNode.getChildCount(); i++) { 
     TemplateModel templateModel = rootTreeNode.getChildNodes().get(i); 
     if (!(templateModel instanceof StringModel)) { 
      continue; 
     } 
     Object wrappedObject = ((StringModel) templateModel).getWrappedObject(); 
     if (!"DollarVariable".equals(wrappedObject.getClass().getSimpleName())) { 
      continue; 
     } 

     try { 
      Object expression = getInternalState(wrappedObject, "expression"); 
      switch (expression.getClass().getSimpleName()) { 
       case "Identifier": 
        result.add(getInternalState(expression, "name").toString()); 
        break; 
       case "DefaultToExpression": 
        result.add(getInternalState(expression, "lho").toString()); 
        break; 
       case "BuiltinVariable": 
        break; 
       default: 
        throw new IllegalStateException("Unable to introspect variable"); 
      } 
     } catch (NoSuchFieldException | IllegalAccessException e) { 
      throw new TemplateModelException("Unable to reflect template model"); 
     } 
    } 
    return result; 
} 

private Object getInternalState(Object o, String fieldName) throws NoSuchFieldException, IllegalAccessException { 
    Field field = o.getClass().getDeclaredField(fieldName); 
    boolean wasAccessible = field.isAccessible(); 
    try { 
     field.setAccessible(true); 
     return field.get(o); 
    } finally { 
     field.setAccessible(wasAccessible); 
    } 
} 

नमूना परियोजना है कि मैं टेम्पलेट आत्मनिरीक्षण प्रदर्शन करने के लिए बनाया GitHub पर पाया जा सकता है: https://github.com/SimY4/TemplatesPOC.git

+0

यह बहिष्कृत चिह्नित विधियों का उपयोग करता है क्योंकि वे आंतरिक उपयोग के लिए आगे बढ़ रहे हैं और पूरी तरह से बदला जा सकता है। कोड 2016 के अंत तक फ्रीमार्कर 2.3.25 के साथ मेरे लिए भी काम नहीं करता था। –

+0

@MichaelOryl हाय। मुझे पता है कि बहिष्कृत एपीआई और मैं व्यक्तिगत रूप से उपयोग करने का मेरा दृष्टिकोण इसका उपयोग करने की अनुशंसा नहीं करता। लेकिन यह अभी भी 2016 में और फ्रीमार्कर 2.3.25 में मेरे लिए काम करता है। आप https://github.com/SimY4/TemplatesPOC.git – SimY4

5

यह शायद देर हो चुकी है, लेकिन अगर किसी और को इस समस्या का सामना करना पड़ता है: तो आप निरीक्षण के लिए 'data_model' और 'globals' का उपयोग कर सकते हैं मॉडल - data_model में केवल मॉडल द्वारा प्रदान किए गए मान होंगे, जबकि ग्लोबल्स में टेम्पलेट में परिभाषित कोई भी चर शामिल होगा। आप एक बिंदु के साथ विशेष चरों पहले जोड़ें करने की जरूरत है - तो वैश्विक अन्य विशेष चरों को देखने के लिए उपयोग करने के लिए, $ का उपयोग

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

+1

असल में, मैं अपने जावा कोड में टेम्पलेट में चर की सूची प्राप्त करना चाहता हूं। मैं कुछ ऐसा करने में सक्षम होना चाहता हूं: टेम्पलेट टी; .... सूची = t.getReferenceVariables(); – Jared

+1

http://freemarker.org/docs/api/freemarker/template/Template.html#getRootTreeNode() आपको मॉडल –

+1

मॉडल का हैशटेबल देता है यह प्रश्न का उत्तर नहीं देता है। चर की सामग्री सूचीबद्ध करने के लिए, आपको इससे अधिक करने की आवश्यकता है। –

-1

टेम्पलेट पर regex निम्नलिखित निष्पादित {वैश्विक।}:

(?<=\$\{)([^\}]+)(?=\}) 
  • (? < = \ $ \ {) $ {
  • ([^ \}]) युक्त नहीं किसी भी स्ट्रिंग से मेल खाता है, जिसके बाद सब कुछ मेल}
  • (? = \}) सब कुछ}
+0

आप केवल '$ {जो भी} 'चर को खींचने के लिए केवल एक साधारण रेगेक्स का उपयोग कर सकते हैं। यह '<#if जो भी>' या लूपिंग संरचनाओं में संदर्भित चीजें नहीं मिलेगा। –

1

एक जावा से चर प्राप्त करने का दूसरा तरीका। यह सिर्फ टेम्पलेट की प्रक्रिया और InvalidReferenceException पकड़ने एक freemarker-टेम्पलेट

/** 
* Find all the variables used in the Freemarker Template 
* @param templateName 
* @return 
*/ 
public Set<String> getTemplateVariables(String templateName) { 
    Template template = getTemplate(templateName); 
    StringWriter stringWriter = new StringWriter(); 
    Map<String, Object> dataModel = new HashMap<>(); 
    boolean exceptionCaught; 

    do { 
     exceptionCaught = false; 
     try { 
      template.process(dataModel, stringWriter); 
     } catch (InvalidReferenceException e) { 
      exceptionCaught = true; 
      dataModel.put(e.getBlamedExpressionString(), ""); 
     } catch (IOException | TemplateException e) { 
      throw new IllegalStateException("Failed to Load Template: " + templateName, e); 
     } 
    } while (exceptionCaught); 

    return dataModel.keySet(); 
} 

private Template getTemplate(String templateName) { 
    try { 
     return configuration.getTemplate(templateName); 
    } catch (IOException e) { 
     throw new IllegalStateException("Failed to Load Template: " + templateName, e); 
    } 
} 
+0

पर कार्य कोड देख सकते हैं यह एकमात्र तरीका है जिसे मैंने देखा है ए) काम करता है और बी) बहिष्कृत FreeMarker विधियों का उपयोग नहीं करता है। वाहवाही। –

+0

@MichaelOryl बड़े पैमाने पर विशाल टेम्पलेट के लिए इसका उपयोग करने के बारे में क्या? क्या आप इस टेम्पलेट को अलग-अलग चर के रूप में कई बार प्रस्तुत करने के लिए तैयार हैं? – SimY4

0

मैं अपने बहुत ही सरल USECASE के लिए इस हल में सभी चर लगता है की कोशिश करता है (केवल फ्लैट आंकड़ा संरचना का उपयोग करते हुए, कोई (उदाहरण के लिए घोंसले: $ { parent.child}), डमी डेटा प्रदाता से सूचियों या अधिक विशिष्ट):

public class DummyDataProvider<K, V> extends HashMap<K, V> { 
    private static final long serialVersionUID = 1; 

    public final Set<String> variables = new HashSet<>(); 

    @SuppressWarnings("unchecked") 
    @Override 
    public V get(Object key) { 
     variables.add(key.toString()); 
     return (V) key; 
    } 
} 

आप इस प्रक्रिया के लिए एक टेम्पलेट को दे सकते हैं और जब यह खत्म सेट variables अपने चर होते हैं।

यह बहुत ही सरल दृष्टिकोण है, जिसे निश्चित रूप से सुधार की आवश्यकता है, लेकिन आपको विचार मिलता है।

+0

असल में मुझे रेगेक्स आधारित समाधान का उपयोग करने के लिए मजबूर होना पड़ा, क्योंकि <#if ..> और <#elseif ..> इस तरह के डमीडाटाप्रोवाइडर के लिए अदृश्य थे। बहुत साफ समाधान नहीं है। यदि विचार करने के लिए कुछ भी होगा तो मैं विभिन्न टेम्पलेट इंजन का भी उपयोग करूंगा। एचटीटीएल ने प्रथम श्रेणी के नागरिक के रूप में टेम्पलेट चर के लिए कहा है, लेकिन एचटीटीएल स्वयं मर चुका है और उनके दस्तावेज वहां नस्ल का सबसे अच्छा नहीं है ... –

0

मुझे एक ही समस्या थी और पोस्ट किए गए समाधान में से कोई भी मुझे समझ में नहीं आया। मैं जो आया उसके साथ TemplateExceptionHandler के कस्टम कार्यान्वयन को जोड़ रहा है। उदाहरण:

final private List<String> missingReferences = Lists.newArrayList(); 
final Configuration cfg = new Configuration(Configuration.VERSION_2_3_23); 
cfg.setTemplateExceptionHandler(new TemplateExceptionHandler() { 

    @Override 
    public void handleTemplateException(TemplateException arg0, Environment arg1, Writer arg2) throws TemplateException { 
     if (arg0 instanceof InvalidReferenceException) { 
      missingReferences.add(arg0.getBlamedExpressionString()); 
      return; 
     } 
     throw arg0; 
    } 

} 

Template template = loadTemplate(cfg, templateId, templateText); 

StringWriter out = new StringWriter(); 

try { 
    template.process(templateData, out); 
} catch (TemplateException | IOException e) { 
     throw new RuntimeException("oops", e); 
} 

System.out.println("Missing references: " + missingReferences); 

यहां अधिक पढ़ें: https://freemarker.apache.org/docs/pgui_config_errorhandling.html

संबंधित मुद्दे

 संबंधित मुद्दे