3

I'm wondering how to list all parsed expressions (variables) by using a simple code snippet:

var template = Template.Parse(@"
<ul id='products'>
  {{ for product in products }}
    <li>
      <h2>{{ product.name }}</h2>
           Price: {{ product.price }}
           {{ product.description | string.truncate 15 }}
    </li>
  {{ end }}
</ul>
");

I need to know the used variables in orde to fetch only data (DB data) I really need. Is there some built-in method or do I need to implement my own?

Palle Due
  • 5,929
  • 4
  • 17
  • 32
Radek Uhlíř
  • 79
  • 1
  • 1
  • 9

1 Answers1

3

Looks like you may use custom TemplateContext to visit expression tree during evaluation. But this requires that all global variables from the template (products here) are registered in the context, at least in a dummy form.

E.g:

    class ScriptVariableMemberExpressionVisitorTemplateContext : TemplateContext
    {
        private readonly Action<ScriptVariableGlobal, ScriptVariableGlobal> memberExpressionVisitor;

        public ScriptVariableMemberExpressionVisitorTemplateContext(
            Action<ScriptVariableGlobal, ScriptVariableGlobal> memberExpressionVisitor)
        {
            this.memberExpressionVisitor = memberExpressionVisitor ??
                                           throw new ArgumentNullException(nameof(memberExpressionVisitor));
        }

        protected override object EvaluateImpl(ScriptNode scriptNode)
        {
            var memberExpression = scriptNode as Scriban.Syntax.ScriptMemberExpression;

            if (memberExpression != null
                && memberExpression.Target is ScriptVariableGlobal
                && memberExpression.Member is ScriptVariableGlobal)
            {
                this.memberExpressionVisitor((ScriptVariableGlobal)memberExpression.Target, (ScriptVariableGlobal)memberExpression.Member);
            }

            return base.EvaluateImpl(scriptNode);
        }
    }

...

    var template = Template.Parse(@"
<ul id='products'>
  {{ for product in products }}
    <li>
      <h2>{{ product.name }}</h2>
           Price: {{ product.price }}
           {{ product.description | string.truncate 15 }}
    </li>
  {{ end }}
</ul>
");

    Dictionary<string, HashSet<string>> productFields = new Dictionary<string, HashSet<string>>();
    var context = new ScriptVariableMemberExpressionVisitorTemplateContext(
        (target, member) =>
        {
            if (!productFields.ContainsKey(target.Name))
            {
                productFields[target.Name] = new HashSet<string>();
            }
            productFields[target.Name].Add(member.Name);
        });

    var scriptObject = new ScriptObject();
    scriptObject.Import(new { products = new[] { new { } } }); //required: `products` object from the template
    context.PushGlobal(scriptObject);
    template.Evaluate(context);

    productFields["product"].ToList().ForEach(Console.WriteLine); //show fields from product object, used by the template

The output is the list of fields from the template:

name
price
description
Renat
  • 7,718
  • 2
  • 20
  • 34