GUIDs and XSLT

An interesting email today... how do you generate GUIDs for every output element using XSLT?  The short answer is "you don't."  XSLT itself doesn't have the capability to generate GUIDs.  Suppose that every node in the result tree needs a GUID attribute appended to it.  One way to solve this is to modify the transformation source before processing it.  Another would be to create an extension object and call the extension from XSLT.  Yet another way is to post-process the resulting XML, adding the GUID to every element.

There is another, simpler way: create a custom XmlTextWriter.  This example shows a custom XmlTextWriter implementation that adds a new attribute, "guid", every time an element is written.  Use this as the target of the transformation, and every element in the result will have the new attribute.

using System;
using System.Xml;
using System.Xml.Xsl;
using System.Xml.XPath;
using System.IO;

namespace ConsoleApplication2
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
XPathDocument doc = new XPathDocument(@"c:\temp\input.xml");

XslTransform trans = new XslTransform();
trans.Load(@"c:\temp\toc.xsl");
try
{
using(System.IO.FileStream fs = new System.IO.FileStream(@"c:\temp\out.xml",FileMode.OpenOrCreate,FileAccess.Write,FileShare.ReadWrite))
{
trans.Transform(doc,null,new MyCustomWriter(fs,System.Text.Encoding.UTF8),null);
}
}
catch(Exception oops)
{
Console.WriteLine(oops.ToString());
}
}
}

 public class MyCustomWriter : System.Xml.XmlTextWriter
{
public MyCustomWriter(System.IO.Stream stream, System.Text.Encoding encoding) : base(stream,encoding)
{

  }

  public override void WriteStartElement(string prefix, string localName, string ns)
{
base.WriteStartElement(prefix, localName,ns);
base.WriteAttributeString("guid",Guid.NewGuid().ToString());
}

 }
}

Provide any source XML document and transformation, and every node in the output will have a guid attribue with a GUID value.  Here is a sample input XML document:

<root>
<foo/>
<bar/>
<baz/>
</root>

We use the identity transformation to transform the document.

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="https://www.w3.org/1999/XSL/Transform">
<xsl:template match="*|@*">
<xsl:copy>
<xsl:apply-templates select="@* | *"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

The result:

<root guid="887cc7b1-e806-45f6-bb01-ee258f355919">
<foo guid="edf2acdd-5bbb-4515-ab67-9a40efe8e999"></foo>
<bar guid="0a2cf23f-6c3e-4350-872e-cb44c55550fe"></bar>
<baz guid="75204595-ea04-409d-a4d8-d3225f2c1e73"></baz>
</root>