Monty’s Gush

A free implementation of the Microsoft XDT language

Posted on: September 20, 2010

kick it on DotNetKicks.com

The XML Document Transform language, or XDT, shipped with Visual Studio 2010. It’s an XML dialect designed to help you automatically transform your .NET config files appropriately for your various deployment environments.

Great. I love XML, obviously

Don’t worry, XDT is very simple and specifically designed for the task of transforming configuration files. For this scenario, it is much easier to use than a general-purpose transformation language like XSLT.

Application configuration files tend to be mostly identical across different deployment environments. Only small modifications, such as the value of your connection strings, the debug attribute, and so on, are required to create a production Web.config file out of a development Web.config file.

XDT is a very simple way of expressing small differences between two XML documents.

To show how simple it is, the basic semantics of the language can be expressed in a few lines of C#.

Let’s assume an existing Web.config file for our input document. We’ll also write a small XDT transform document which sets the ASP.NET debug attribute to false:

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
	<system.web>
		<compilation debug="false" xdt:Transform="SetAttributes" />
	</system.web>
</configuration>

Notice it looks a bit like a small Web.config document. The input doc could be a big, complex Web.config file, but that doesn’t matter – the transform doc only needs to contain the differences.

The Transform attribute is defined within a distinguished XML namespace to ensure that it can’t clash with any existing attributes in the input doc. In this case, we’re using one of the most useful built-in transforms, SetAttributes, which modifies attribute values on the targeted element to those that are specified in the transform doc – in this case, setting debug to false. There are other useful transforms, such as Remove and Replace, which alter the targeted element in different ways.

A transform implicitly specifies the element(s) in the input document to act upon by virtue of the element that it belongs to: expressed in XPath, the above transform would target the
/configuration/system.web/compilation element(s).

A transform doc specifies a set of transforms, each paired with an XPath expression selecting the target element(s) in the input doc upon which to act.

Here is a simple implementation of XDT using C#:

        public XDocument Transform(XDocument inputDoc, XDocument transformDoc)
        {
            var workingDoc = new XDocument(inputDoc);

            // (1) pair each "Transform" element with the element(s)
            // it targets in the working document
            var xs = from e in transformDoc.Descendants()
                     from a in e.Attributes(Namespaces.Xdt + "Transform")
                     let xpath = GetElementXPath(e)
                     select new
                     {
                         TransformElement = e,
                         TargetElements = workingDoc.XPathSelectElements(xpath)
                     };

            // (2) apply each transform to its target elements
            foreach (var x in xs)
            {
                ApplyTransform(x.TransformElement, x.TargetElements);
            }

            return workingDoc;
        }

Show me the source code

This is a slight simplification, and of course doesn’t show you the implementation of the individual transforms or how to compute the XPath. You can find the full, reasonably complete implementation of XDT on Google Code.

Locators

The implicit XPath location of, for example, a /configuration/appSettings/add element would usually specify more than one element in most Web.config files. While this is valid, it’s not very useful. XDT provides a second attribute, Locator, which allows you to augment the implicit XPath expression with a predicate to filter the target element set:

                <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
                  <appSettings>
                    <add xdt:Locator="Condition(@key='key3')" />
                  </appSettings>
                </configuration>

This would give us target XPath of /configuration/appSettings/add[@key='key3'], which is much more useful (although it doesn’t do anything, because we haven’t specified any transform!).

A convenience case of the Condition locator is to simply Match on the specified attribute, so to actually alter a particular app setting value, you would write:


<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
	<appSettings>
		<add key="key3" value="new value" xdt:Locator="Match(key)" xdt:Transform="SetAttributes" />
	</appSettings>
</configuration>

This specifies a SetAttributes transform with the same target XPath as the previous example.

Why XDT?

  • It’s part of Visual Studio 2010, and you can expect it to become the standard way of managing different config files.
  • It’s really rather nice – it’s ideal for tweaking XML documents, so long as the changes aren’t big. It’s very readable (despite being XML) and quite easy for anyone to use.
  • You don’t really want to use XSLT for this sort of thing.

Why write a free implementation?

I wanted to use XDT in production before Visual Studio 2010 was released. I also find that thinking about the implementation of something helps you understand its semantics. However, there are some other good reasons:

  • XDT is currently restricted to web applications. Out of the box, it can’t be used with Windows or console apps, or even web “site” style projects. But this is no restriction of the language itself.
  • XDT is currently restricted to Web.config files. Real applications tend to have more than one XML configuration file which needs to be transformed.
  • You might not be using Visual Studio 2010.
  • You might want to decouple the notions of build configuration and build environment. They’re not the same concept, but the Visual Studio 2010 designers chose to keep things simple. With several “release” environments, this conceptual simplicity comes at the cost of flexibility and creates duplication in the project and solution manifest files. A more sophisticated build system might prefer to keep just the standard two build configurations (Debug, Release) but define several deployment environments (Dev, Test, Uat, Live…), each with different config transformations.
One scenario where this coupling causes a problem is building a shared code library from source inside a client application (for example via Subversion externals). The shared library may have standard build configurations (Debug, Release), but the client applications may need additional deployment configurations, necessarily unknown to the shared library. The problem is that if these additional build configurations don’t exist in the the shared library, its projects cannot be integrated into the client solution.

If you’re creating a serious build system, these restrictions would otherwise probably prevent you from using XDT for your transformations, which would be a shame.

It feels like a classic Microsoft situation – a well-engineered core technology, but restricted (understandably) for commercial / shipping reasons. If you do want to go ahead and use this alternative implementation, it’s very straightforward to create an MSBuild task to call XdtTransformer.Transform() in order to use XDT in your build system. If there’s enough demand, I could add one to the distribution on Google Code.

Disclaimer The semantics of this implementation are based purely on my reading of the XDT product documentation on MSDN. The implementation passes all of the example tests I’ve found on the web – but, as usual, no warranties are implied. ;-)

kick it on DotNetKicks.com

9 Responses to "A free implementation of the Microsoft XDT language"

I hear the point about “limited” transforms to a document, but it actually seems more clumsy and clunky to me than if I’d just used XSLT (which we do in our project).

I don’t have a need for it just yet but its cool that you made an implementation :)

Great work for those not ready for VS 2010 and for those that need to implement a custom deployment solution.

Great work! The only problem is the source control provider. Would there be a problem for you to switch to Mercurial, so other can also contribute (Google Code has suport for it) ?

Implemented Nant task for it. See http://code.google.com/p/xdt-nant/

I would strongly suggest you consider XSLT instead. There’s a great write-up on how to do it at http://mint.litemedia.se/2010/01/29/transforming-an-app-config-file/. I use this strategy and find it superior to XDT because:
– XSLT is THE standard for transforming XML and there is a lot of documentation on how to do things
– XSLT is not limited to a small subset of operations, and can make ANY desired change to your config file
– The solution presented is not limited to Web Sites, so you can use the same solution for ALL you config files
– Plus the solution he presented has no need for external tasks and suchlike since it integrates directly with the project file.

We want to integrate XDT in Apache NPanday (Maven for .NET)

https://issues.apache.org/jira/browse/NPANDAY-493

We think of using your version because it could possibly also run on Mono (if not we could make it run).

I’m not sure if we can redistribute LGPL-stuff; would you consider also providing XDT under the Apache license?

Hi Lars, yes of course. Apache licence is fine; let me know if I need to send you anything. Pete.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: