In .NET 2.0 framework when using System.Xml.Xsl.XslCompiledTransform class for transforming a document then we always get self closing tags for all the elements which have nothing inside their body. There is no direct way to tell it to use separate closing tags
e.g.
<BODY>
    <TABLE></TABLE>
    <BR></BR>
</BODY>

transforms as

<BODY>
    <TABLE/>
    <BR/>
</BODY>

This might cause problems when we are transforming a document for HTML processing as HTML doesn't identify self closing tags properly.
So although <Table/> is a valid XML closed tag but HTML identifies it as starting of a table only which causes its output to be different than what we want.
This thing did not happen with System.Xml.Xsl.XslTransform class in .NET 1.1 framework. It gives separate closing tags for empty elements too

This problem is caused because xslcompiledtransform class uses self closing tags for all the elements irrespective of whether they are empty or not.

The resolution of the issue involves creating a class derived from XmlTextWriter and overriding few methods in it. Here are the steps:

  • Create a new class XmlHtmlWriter inherited from XmlTextWriter.
  • Override two functions WriteStartElement and WriteEndElement.
  • Create a list fullyClosedElements for storing names of all the tags which you want not to be self closed.
  • In WriteStartElement function record the tag which is being written and in WriteEndElement check whether we need to close this element using separate closing tag or not by checking whether it exists in fullyClosedElements list or not.
  • To use separate tag for closing call WriteFullEndElement function else call base.WriteEndElement.
  • Then use an instance of this XmlHtmlWriter class in your application for output of xsl transform.
  • Here is the code for reference.

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace XSLSelfClosing
{
    public class XmlHtmlWriter : XmlTextWriter
    {
        public XmlHtmlWriter(System.IO.Stream stream, Encoding en)
            : base(stream, en)
        {

            //Put all the elemnts for which you want self closing tags in this list.
            //Rest of the tags would be explicitely closed

            fullyClosedElements.AddRange(new string[] { "br", "hr" });
        }

        string openingElement = "";
        List<string> fullyClosedElements = new List<string>();

        public override void WriteEndElement()
        {
            if (fullyClosedElements.IndexOf(openingElement) < 0)
                WriteFullEndElement();
            else
                base.WriteEndElement();
        }

        public override void WriteStartElement(string prefix, string localName, string ns)
        {
            base.WriteStartElement(prefix, localName, ns);
            openingElement = localName;
        }
    }
}