XML Typed Templates

Topics: Developer Forum, User Forum
Coordinator
Feb 12, 2007 at 3:25 AM
Edited Feb 12, 2007 at 3:38 AM
I've just released a beta version which is a complete rewrite of my earlier prototype on XML Typed Templates. (XTT? I need a cooler acronym/codename ;))

Please take a look at it at: http://www.codeplex.com/MVPXML/Release/ProjectReleases.aspx?ReleaseId=1860

The point of the prototype is to prove that there's an alternative way to render objects into XML that doesn't require filling-up memory with objects (like XLinq does for "functional construction"). It also shows that C# developers could still produce significant amounts of XML output without losing productivity, and in fact gaining in maintainability and readability (IMO) over VB9 XML literals.

So what's the idea? The idea is to generate at design-time, a typed template rendering class (a class with a Render method receiving an XmlWriter) which basically uses XmlWriter methods to output to the writer, at run-time, the same XML that was designed using the XML editor.

So, say you have the following XML:

 
<Books>
   <Book Id="55" Title="XML Rocks" />
</Books>

after associating the custom tool Mvp.Xml.TypedTemplate in VS, you will get a child/dependent file named xml file.Designer.cs which looks like the following:

 
public partial class Template1
{
    public void Render(System.Xml.XmlWriter writer)
    {
        writer.WriteStartElement("", "Books", "");
        writer.WriteStartElement("", "Book", "");
        writer.WriteAttributeString("", "Id", "", "55");
        writer.WriteAttributeString("", "Title", "", "XML Rocks");
        writer.WriteEndElement();
        writer.WriteEndElement();
    }
    ....  
}

See how the XML "source" was converted to its equivalent XmlWriter-based generation.
The interesting bit comes when you add dynamism to the template:

 
<?template typename="CustomerTemplate" ?>
<?using namespace="ConsoleDemo" ?>
<?property name="Customer" type="Customer" ?>
<Customer xmlns="mvp-xml-templates" FullName="${Customer.LastName + &quot;, &quot; + Customer.FirstName}">
    <?foreach (Order o in this.Customer.Orders) ?>
    <Order Id="${o.Id}" Premium="${CalculateTotal(o) > 5000}" Date="${o.DateOrdered}">
        <GrandTotal>${CalculateTotal(o)}</GrandTotal>
        <?if (o.Items != null) ?>
        <?foreach (Item i in o.Items) ?>
        <Item Id="${i.ProductId}" SubTotal="${i.Quantity * i.Price}">
            <Quantity>${i.Quantity}</Quantity>
            <Price>${i.Price}</Price>
        </Item>
        <?end?>
        <?end?>
    </Order>
    <?end?>
</Customer>

The syntax for the dynamic parts was carefully chosen so that the XML editor doesn't break, and therefore you maintain all the great XML editing experience you're used to, including intellisense if you have a corresponding XSD schema.

Note the CalculateTotal(o) call: it's a method, which does not exist in the template itself, but rather in a partial class that the developer can create to augment the generated template rendering class if necessary. This is very important because you want to maintain high productivity in doing so (as opposed to typing C# inside the XML editor, which would make for a tedious trial/error as you don't have any C# editing aids). The partial class looks like the following:

 
    public partial class CustomerTemplate
    {
        private double CalculateTotal(Order o)
        {
            double total = 0;
            foreach (Item i in o.Items)
            {
                total = i.Quantity * i.Price;
            }
 
            return total;
        }
    }

Also, and another important feature I tried to maintain, is that the generated code has no dependency whatesoever on anything. It's plain old XmlWriter code that you could have written yourself. You only need the design-time custom tool if you edit the templates and want to have the code re-generated (MSBuild integration pending).

So, finally, as a user of the generated template rendering class, you don't even need to know how it works internally. All you need to do is instantiate the template, pass the input properties, and call Render!:

CustomerTemplate ct = new CustomerTemplate();
ct.Customer = BuildCustomer();
 
XmlWriterSettings ws = new XmlWriterSettings();
ws.Indent = true;
 
using (XmlWriter writer = XmlWriter.Create(Console.Out, ws))
{
	ct.Render(writer);
}


Let me know what you think.
Thanks!
Coordinator
Feb 19, 2007 at 4:56 PM
So here you basically don't mix C# code with XML as VB does, right?

This is definitely cool, especially latest snippet, but let me play devil's advocate here:

1. It's not exactly C#, but yet another syntax.
2. It's XML file so no intellisense for code parts.
3. This probably would make people who like VB XML literals disappointed

Otherwise I like and I'd use it.

But what about going opposite extreme and building xcs - C# with XML literals?
Coordinator
Feb 19, 2007 at 7:43 PM
1. Actually, when you need to write C# (CalculateTotal method above), you write it with full intellisense. When you're writing XML, you're using the XML editor also with full intellisense powered by the appropriate XSD if you have any (unlike VB9 XML literals, IIRC).

2. There are no code parts. There are simple expressions (kind of binding expressions in ASP.NET) which carry the semantics of their accompanying PI (<?foreach?>, <?if?>, etc). Because these expressions are one-liners, they shouldn't be too much typing. Also, even if you don't get inmediate intellisense, you do get inmediate compile errors if the syntax is wrong. Hence, the template always works.

3. People who like VB XML literals will probably end up building spaghetti-like apps where XML "rendering" will be mixed with code and logic. I fail to see how that can be any good. This separation of "presentation" from model is a good thing, and I'm sure most will appreciate it pretty soon.
Coordinator
Feb 21, 2007 at 5:01 PM
Well, this approach also kinda mixes logic and presentation. It's only in tutorials an object is always ready for presentation, in the real world people would end up writing programs with those "expressions", immediately starting asking for variables etc.

Do you need any help with this stuff?

And still I believe a killer feature would be intellisense for "expressions". That would actually bring wide adoption, not only XML geeks.
Coordinator
Feb 21, 2007 at 5:23 PM
The prototype is fully functional at this point, so other than the discussion, which is very valuable, I don't think we need to put much more effort on it.
Intellisense for the expressions would be VERY tricky, as we know the XML editor is not ready for such a heavy extensibility scenario.

The object doesn't need to be ready for presentation, but whatever manipulation has to be done on the object to produce something more amenable for presentation, can be done on the guy setting the context (properties) for the transformation (i.e. building a CustomerPresentation), or by adding manipulation methods to the partial class. I haven't seen many XSLT transformations that render HTML and make significant use of variables. But they could be added pretty easily to our language, kinda:

<?var foo = context.SomeValue ?>

This should be straightforward to add.

Maybe we can talk to the XML team in the summit and see if it's possible to add intellisense for the expressions...