Frage

I'm using StringTemplate4 to allow users to pass an HTML template and page ID to a web service, then get the parsed result. The name and number of fields is dynamic, meaning that while some pages might return only one value for a given field, other pages might return many. An example is page URL. Each page can have several URLs, but the first should be considered the default URL (the canonical URL). I want my users to be able to add $url$ to the template and it just spit out the first URL. I know that StringTemplate doesn't provide indexing on arrays, so I can't just say $url[0]$, so I took a different approach. Here is my code:

public class TemplateField : Dictionary<string, dynamic>
{
    // Empty class
}

public class TemplateValue : List<string>
{
    public override string ToString(){
        return this.FirstOrDefault();
    }
}

// This is a test method to render a template using my planned objects
public static string ReplaceTokens()
{
    var template =  @"
        <Title>$Title$</Title>
        <ul class=""menu"">
            $menu:{m|<li><a href=""$m.url$"">$m.name$</a></li>};separator=""\n""$
        </ul>";

    var g = new TemplateGroup('$','$');
    var t = new Template(g,template);

    var menu = new List<TemplateField>();

    var item1 = new TemplateField();
    item1.Add("name", new TemplateValue { "Home" });
    item1.Add("url", new TemplateValue {
        "/home",
        "/index",
        "/default"
    });
    t.Add("menu",item1);

    var item2 = new TemplateField();
    item2.Add("name", new TemplateValue { "About Us" });
    item2.Add("url", new TemplateValue { "/about-us" });
    t.Add("menu", item2);

    var item3 = new TemplateField();
    item3.Add("name", new TemplateValue { "Contact" });
    item3.Add("url", new TemplateValue { "/contact" });
    t.Add("menu", item3);

    t.Add("Title", new TemplateValue { "My test" });
    return t.Render();
}

So as you can see by looking at my template, I am hoping that $m.url$ will render out "/home" instead of "/home/index/default" as it is doing currently. I have tried to accomplish this by overriding the ToString() method on the TemplateValue class but to no avail. I have tried to look through the source for StringTemplate and couldn't find a way to change the value returned by an object when it is rendered. Can anyone point me in the right direction?

War es hilfreich?

Lösung

You can use $first(url)$. If the item is not an array (or collection), then the result of this expression is just the item itself.

Andere Tipps

I ended up switching to XSLT in the end. I'd originally avoided it because I didn't think it was elegant enough (compare to Razor, for instance). But it has a lot of pros to outweight that one con:

  • As long as I can represent my class as XML, I can have any level of complexity in the object I pass to the template parser.
  • I don't need any custom classes like TemplateField and TemplateValue to represent my object: simple XML will do.
  • It's a standard technology, so support is much better than I can expect from 3rd party libraries, and getting new developers up to speed will be much easier.
  • It lets me use standard logic in the template.
  • It works!
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top