Question

I am using xslt to transform an xml file to html. The .net xslt engine keeps serving me self-closing tags for empty tags.

Example:

<div class="test"></div> 

becomes

<div class="test" />

The former is valid html, while the latter is illegal html and renders badly. My question is : How do I tell the xslt engine (XslCompiledTransform) to not use self-closing tags.

If it's not possible, how can I tell my browser (IE6+ in this case) to interpret self-closing tags correctly.

Was it helpful?

Solution

If you are using XmlWriter as your ouput stream, use HTMLTextWriter instead. XMLWriter will reformat your HTML output back to XML.

OTHER TIPS

Change your xsl:output method to be html (instead of xml).

Or add it if you haven't already got the element

<xsl:output method="html"/>

A workaround can be to insert a comment element to force generation of non self closing:

<script type="text/javascript" src="nowhere.js">
<xsl:comment></xsl:comment>
</script>

It is not a pretty soloution, but it works :-)

/Sten

For me it was a problem in the script tag. I solved it by filling it with a semicolon (;)

<script type="text/javascript" src="somewhere.js">;</script>

You can't tell your browser to handle invalid HTML as HTML -- you're lucky it understands malformed HTML at all. :)

Definitely do this in your stylesheet:

<xsl:output method="html"/>

But, if your source document has namespaces, this won't do the trick. XSLT processors seem to silently change the output method back to XML if namespace nodes are present in the output.

You need to replace all instances of <xsl:copy-of> and <xsl:copy> with creations of elements with just the local name, e.g.

<xsl:template match="*">
   <xsl:element name="{local-name()}">
     <xsl:apply-templates/>
   </xsl:element>
</xsl:template>

See

etc.

I used to put an <xsl:text> element inside, like:

<script type="text/javascript" src="/scripts/jquery.js"><xsl:text> </xsl:text></script>

There are a few things you need to be careful:

  1. In your xsl use < xsl:output method='html'>
  2. set OutputSettings in your output XmlWriter
  3. in the Html inside your xsl, don't set attributes in html tag like this < html xmlns="http://www.w3.org/1999/xhtml"> but use < html> instead.

This is a piece of working code:

string xmlStr = "<?xml version='1.0' encoding='UTF-8'?><Data></Data>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlStr);
string xslContents = @"
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'  
xmlns:msxsl='urn:schemas-microsoft-com:xslt' exclude-result-prefixes='msxsl'>
<xsl:output method='html' version='4.0' omit-xml-declaration='yes' indent='yes'/>
<xsl:template match='Data'>
<html>
<body>
    <div></div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>";
XslCompiledTransform xsl = new XslCompiledTransform();
xsl.Load(XmlReader.Create(new StringReader(xslContents)));
StringWriter result = new StringWriter();
using (XmlWriter writer = XmlWriter.Create(result, xsl.OutputSettings))
{
    xsl.Transform(doc, null, writer);
}
System.Diagnostics.Debug.Write( result.ToString());

The easy way I found was creating a new XmlTextWriter class to override the method WriteEndElement, forcing the non-closing tag and pass on the serialization process as parameter.

public class MyXmlTextWriter : XmlTextWriter
{
    public MyXmlTextWriter(Stream stream) : base(stream, Encoding.UTF8)
    { }
    public MyXmlTextWriter(TextWriter stream) : base(stream)
    { }

    public override void WriteEndElement()
    {
        base.WriteFullEndElement();
    }
}

Just experienced the same issue with PHP 5's XSL, with output/@method=html. Seems that assigning an empty value attribute will cause elements to be output as invalid non-self-closing, non-closed tags:

<input type="text" name="foo" value="{my-empty-value}" />

results in:

<input type="text" name="foo" value="">

One possible solution is to conditionally add the attribute:

<xsl:if test="string-length(my-empty-value) > 0">
    <xsl:attribute name="value">
        <xsl:value-of select="my-empty-value" />
    </xsl:attribute>
</xsl:if>

resulting in:

<input type="text" name="foo" />

I use the following whenever I wish to prevent an element from self-closing:

<xsl:value-of select="''" />

This fools the rendering engine into believe there is content inside the element, and therefore prevents self-closure.

It's a bit of an ugly fix so I recommend containing it in a descriptive template and calling that each time instead:

<xsl:template name="PreventSelfClosure">
   <xsl:value-of select="''" />
</xsl:template>


<div class="test">
   <xsl:call-template name="PreventSelfClosure"/>
</div>

This will then render the following:

<div class="test"></div>

http://curtistimson.co.uk/post/xslt/how-to-prevent-self-closing-elements-in-xslt/

Don't try this at home:

<xsl:when test="self::* and not(text())">
    <xsl:value-of select="concat('&lt;', name(), '&gt;', '&lt;/', name(), '&gt;')" disable-output-escaping="yes"/>
</xsl:when>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top