views:

617

answers:

7

I'm looking for a free templating engine to generate simple reports. I want some basic features such as :

  • Ability to Write Loops (with any IEnumerable)
  • Passing Variables
  • Passing Templates Files (main template, footer, header)

I'll use this to generate reports in HTML and XML. I'm not looking for a ASP.NET Template Engine.

This is for a WinForms applications.

I've seen this question http://stackoverflow.com/questions/340095/can-you-recommend-a-net-template-engine, however all of those template engines are total overkill for me and focused for ASP.NET.

Please only recommend free libraries.

// I'm still looking an NVelocity but it doesn't look any promising for .NET, overly complicated, when you download it's bunch of files not clear what to do, no tutorial, startup document etc.

+1  A: 

I would recommend StringTemplate (http://www.stringtemplate.org). I used it for generation of mails. You can use Template Groups stored on Filesystem or in a database (costs a little bit of work).

H-Man2
Do you know any website for some .NET examples for stringtemplate ?
dr. evil
The wiki on the stringtemplate webside shows examples for the most supported languages, including c#. But the syntax of the templates is the same for all languages. Only instantiation of the templates differs.
H-Man2
+1  A: 

We use NVelocity as part of our MonoRail-based Web site. In all honesty, I would not recommend NVelocity. It's a direct port (and by direct I mean CTRL+C, CTRL+V, change some Java keywords to C# keywords -- this is not maintainable) from the Java version to the .NET version. Castle had to fork it to add some .NET-oriented features (dictionary access, fancy foreach loops) since the original .NET maintainers are leaving it in an unhealthy state. Has problems escaping some of its own directives, gets really irritated should you try to split a long if statement across multiple lines. I don't mean to dump all over it, it's a nice language, it's free, and it's used on our site which servers thousands of requests per day--I just wouldn't use it again unless I saw a new implementation of the same syntax.

For other areas of the system that generate e-mails, I just use the old-fashioned method of replacing $SPECIAL_KEYWORDS$ in a string (that is, a dictionary that maps keywords to values, iterate through it and replace). Not efficient, but works well enough.

Look forward to reading some of the other answers.

Nicholas Piasecki
Nicholas - NVelocity fork of Castle is alive and kicking, and I think since they use it for Windsor configuration, it should be quite stable. I personally haven't had any issues with it.http://jonorossi.com/blog/archive/2009/09/29/nvelocity-1.1-and-templateengine-1.1.aspx
Igor Brejc
+2  A: 

I second not recommending nVelocity. It is a horrible port.

.NET actually has built in templating abilities by using CodeDOM.

Here is a pretty good walkthrough of how to do it:

http://www.codeproject.com/KB/cs/smarttemplateengine.aspx

With some minor coding, you'll be able to create templates that have inline C#:

<html>
    <head>
         <title>My Report</title>
    </head>
    <body>
        <% foreach (ReportRow r in ReportData) { %>
             <!-- Markup and Code for Report -->
        <% } %>
    </body>
</html>
FlySwat
A: 

Thanks for the help, CodeDOM specifically showed me a nice way, now I'm working with this : http://www.stefansarstedt.com/templatemaschine.html

It's not the best and a bit dirty but doing the trick for me. It's LGPL which fits me, and short.

I've looked at the other suggestions but didn't like them, too complicated for what I want (and quite messy -tons of DLLs, dependencies etc.-)

dr. evil
A: 

John Resig has a great Javascript template end called micro-template. The syntax for a template is:

<script type="text/html" id="item_tmpl">
  <div id="<%=id%>" class="<%=(i % 2 == 1 ? " even" : "")%>">
    <div class="grid_1 alpha right">
      <img class="righted" src="<%=profile_image_url%>"/>
    </div>
    <div class="grid_6 omega contents">
      <p><b><a href="/<%=from_user%>"><%=from_user%></a>:</b> <%=text%></p>
    </div>
  </div>
</script>

The template function will support the use of Javascript, and therefore you get the looping functionality and full access to the DOM, so any jQuery or other frameworks are at your disposal. This is a very flexible approach as it allows you quickly include new features to a web page with very little effort and alteration. It also works well with .Net as shown in this post from Dave Ward.

The template can be an html file that you can retrieve with a $.get() command. You feed the template a JSON object as the data source. Finally, there is also a feature that allows you to pre-compile the template.

David Robbins
A: 

Here is another Template Engine: UltTemplate Engine

Here is the template code:

Dear $User.FullName$,
{%set orders=User.GetOrders() /}
Thank you for your order of $orders.Length$ items, We believe you will be very satisfied with the quality of costume pieces included in each. It is this quality that makes our imaginative play apparel so unique.

We created an account for you to track your orders. Here is the login information:
Email: $User.EmailAddress$
Password: $User.Password$

Following is the details of your order (OrderId: $OrderId$):
#   Part ID    Name            Quantity     Price(per unit)       Sub Total
{%set Total=0.0 /}{%foreach orderproduct,i in orders%}{%set Total = Total + orderproduct.Price * orderproduct.Quantity/}
{%rendertemplate orderproducttemplate item=orderproduct/}{$foreach%}
                                                                                               Total: $PadLeft(Format(Total,"$$#.##"),11)$

If you have any concern, please call us at 913-555-0115.

Sincerely,

$CompanyName$

{%template orderproducttemplate%}$PadLeft(i,4)$$PadLeft(item.PartId, 7)$    $PadRight(item.ProductName, 15)$        $PadRight(item.Quantity, 5)$        $PadLeft(Format(item.Price,"$$#.##"), 7)$   $PadLeft(Format(item.Price*item.Quantity,"$$#.##"), 12)${$template%}

and here is the output:

Dear John Borders,

Thank you for your order of 3 items, We believe you will be very satisfied with the quality of costume pieces included in each. It is this quality that makes our imaginative play apparel so unique.

We created an account for you to track your orders. Here is the login information:
Email: [email protected]
Password: 123abc

Following is the details of your order (OrderId: 1625DGHJ):
#   Part ID    Name            Quantity     Price(per unit)       Sub Total

   0   1239    Product A              3            $104.09        $312.27
   1     22    Product B              1            $134.09        $134.09
   2    167    Product C              5              $14.7          $73.5

                                               Total:     $519.86

If you have any concern, please call us at 913-555-0115.

Sincerely,

My Company Name

Here is the C# code:

        class OrderProduct
        {
            private int _partId;
            private string _productName;
            private int _quantity;
            private float _price;

            public int PartId
            {
                get { return _partId; }
                set { _partId = value; }
            }

            public string ProductName
            {
                get { return _productName; }
                set { _productName = value; }
            }

            public int Quantity
            {
                get { return _quantity; }
                set { _quantity = value; }
            }

            public float Price
            {
                get { return _price; }
                set { _price = value; }
            }
        }

        class User
        {
            private string _fullName;
            private string _emailAddress;
            private string _password;

            public string FullName
            {
                get { return _fullName; }
                set { _fullName = value; }
            }

            public string EmailAddress
            {
                get { return _emailAddress; }
                set { _emailAddress = value; }
            }

            public string Password
            {
                get { return _password; }
                set { _password = value; }
            }

            public OrderProduct[] GetOrders()
            {
                OrderProduct[] ops = new OrderProduct[3];

                ops[0] = new OrderProduct();
                ops[0].PartId = 1239;
                ops[0].Price = 104.09f;
                ops[0].ProductName = "Product A";
                ops[0].Quantity = 3;

                ops[1] = new OrderProduct();
                ops[1].PartId = 22;
                ops[1].Price = 134.09f;
                ops[1].ProductName = "Product B";
                ops[1].Quantity = 1;

                ops[2] = new OrderProduct();
                ops[2].PartId = 167;
                ops[2].Price = 14.7f;
                ops[2].ProductName = "Product C";
                ops[2].Quantity = 5;

                return ops;
            }
        }

        private void btnRun_Click(object sender, EventArgs e)
        {
            try
            {
                dt.LoadFromString(txtSource.Text);
                dt.SetValue("CompanyName", "My Company Name");

                User u = new User();
                u.EmailAddress = "[email protected]";
                u.FullName = "John Borders";
                u.Password = "123abc";
                dt.SetValue("User", u);
                dt.SetValue("OrderId", "1625DGHJ");

                txtOutput.Text = dt.Run();
            }
            catch (Exception exc)
            {
                MessageBox.Show("An error occurred: " + exc.Message);
            }
        }
+1  A: 

Although I see you've already accepted an answer, I would encourage you to take a look at the Spark view engine.

Example from the site:

<viewdata products="IEnumerable[[Product]]"/>
<ul if="products.Any()">
  <li each="var p in products">${p.Name}</li>
</ul>
<else>
  <p>No products available</p>
</else>
EvilRyry