IE Conditional Comments in XSLT 1.0


Zen gardener Dave Shea’s post Bye Bye Tan Hack attracted a number of comments from people claiming that Internet Explorer’s conditional comments (CCs) were ungeneratable if you are using XSLT to produce your pages. “Strange,” I thought, “I’ve done that before.”

I’ve been working with XSLT for several years, and the project I’m currently working on uses it intensively; getting CCs working was simmering somewhere down my todo list. (I couldn’t recycle any previous efforts for boring, legal IP reasons.) So I set to work, and am happy to present an XSLT template which will build your conditional comments for you. I’ve tested it with Xalan 2.2, Saxon 6.5.3, MSXML 3 and MSXML 4 (those being the only XSLT processors I had to hand), and it worked perfectly with all of them.

In addition, I’ve created a demonstration for Firefox, Internet Explorer and Safari (2.0.1 on Tiger, anyway). This XML file uses an XSL stylesheet which generates a conditional comment. Using Firefox’s DOM Inspector you can see that the comment is created correctly. Using Internet Explorer, a stylesheet is linked which modifies the appearance of the page’s heading. This demonstrates that the technique I’m describing can be used client-side as well as in server-side transformations.

First, the template:


<xsl:template name="conditionalComment">
    <xsl:param name="qualifier" select="'IE'"/>
    <xsl:param name="contentRTF" select="''" />
    <xsl:comment>[if <xsl:value-of select="$qualifier"/>]<![CDATA[>]]>
        <xsl:copy-of select="$contentRTF" />
        <![CDATA[<![endif]]]></xsl:comment>
</xsl:template>

Easy, yes? Well, maybe not; let’s look at it one step at a time.

The template takes two parameters:

qualifier
The qualifier for the “if” clause of the comment. Defaults to “IE”, which targets any version of Internet Explorer that recognises conditional comments.
contentRTF
The body of the comment: the stuff that IE gets to see (depending on the qualifier). This is passed as a result tree fragment; if you’re not sure what that means, you may want to go and read the relevant section of the XSLT spec. Defaults to an empty string.

We can invoke the template using the following code:


<xsl:call-template name="conditionalComment">
    <xsl:with-param name="qualifier" select="'lte IE 6'"/>
    <xsl:with-param name="contentRTF">
        &lt;link rel="stylesheet" type="text/css" href="ie-win-fixup.css" /&gt;
    </xsl:with-param>
</xsl:call-template>                

That will give us a conditional comment targeting Internet Explorer versions 6 and below (“lte IE 6”). NOTE: I haven’t messed up my character entities there; the HTML we want to output really is expressed as you see above in the XSLT code.

So how does it work?

The comment is generated using the element. Note that we want to keep tight control of our whitespace here, making the rest of the template pretty unreadable. Split into its component parts, we have:

<xsl:comment>
Starts outputting our comment to the result tree. Output so far: <!--
[if <xsl:value-of select="$qualifier"/>]
Starts adding on the bits needed to make IE parse this as a conditional comment, using the value of the qualifier parameter. In the example case, our output is now up to <!--[if lte IE 6]
<![CDATA[>]]>
This CDATA section is treated as raw characters to copy to the result tree by the XSLT processor. So our output becomes:
<!--[if lte IE 6]> which is the start of our conditional comment.
<xsl:copy-of select="$contentRTF"/>
This just copies the contents of our result tree fragment to the result tree. Our output is now:


<!--[if lte IE 6]>
<link rel="stylesheet" type="text/css" xhref="ie-win-fixup.css" mce_href="ie-win-fixup.css" />

Notice that the character entity references we passed in in contentRTF (&lt; and &gt;) have now been turned into the actual characters we wanted, through the magic of result tree fragments. (In fact, this technique can be abused to allow invalid XML output from an XSLT processor, which is why it isn’t likely to survive into XSLT 2.0.)

<![CDATA[>![endif]]]>
Our final line uses another CDATA section to provide the markup IE needs to recognise the end of the comment, and then the closes our comment. Note again that there is no whitespace between the CDATA section and the closing-comment element: this is where IE’s CC parser might trip up, so we make do with a little unreadability for the sake of getting the result we want which, in all its refulgent splendour, now looks like:


<!--[if lte IE 6]>
<link rel="stylesheet" type="text/css" href="ie-win-fixup.css" />
<![endif]-->

So there you have it: an XSLT template for creating Internet Explorer conditional comments. Hopefully re-targeting your CSS hacks in readiness for the new age just got a little easier.

This post is now available in a Romanian translation (by Web Geek Science).

, , ,

13 responses to “IE Conditional Comments in XSLT 1.0”

  1. Just about 2 months ago on xsl-list (forgot who posted it):

    :: [if IE]><link rel=”stylesheet” type=”text/css” href=”css/ieonly.css” media=”screen” /><![endif]”

    Which I like better b/c no CDATA sections. Shorter and somehow cleaner.

    “]]>”, an unescaped > is legal syntax, no need for CDATA. You only need to be careful w/”>”(s) when inside an element declaration.

  2. Nice one Nick!

    You just saved me hours of fiddling about trying to make a fix.

    Quality code as always!

  3. It might be 2008 not 2005 when this was first posted, but this post really really helped me out with Conditional Comments. No other article on the web seemed to quite work. Many thanks.

  4. Thank you very much.

    Now I can combine this trick with Dean Edwards’ IE7 library to get XHTML support in IE6 and IE7.

    W00t! 🙂

  5. Andy, Artyom: HTH 🙂

    BTW I’ve just noticed that WordPress appears to have changed some of the code slightly 🙁

    Until I get it fixed, please note that

    xhref="ie-win-fixup.css" mce_href="ie-win-fixup.css"

    should be

    href="ie-win-fixup.css"

  6. Oh Nick, if the secret of great comedy is in the timing, then the pique of tragedy is in the lack thereof. Just went through a final pre-launch of a site which worked in all but IE6, couldn’t find a fix to add conditionals in XSLT. “Never mind” I thought, the designer is bringing his Macbook so no chance of IE6’s ugly face around there. “Ho ho!” says God, casting a random spanner in my general direction, and lo the designer appears sans Macbook. “No problem” says random Bod, here use this workstation – “With IE6 on!!!”.
    So, now shamefaced and angry I search the net and your bounteous answers falls at my feet, fixing the site and looking fine and dandy in IE6… only 3 hours late. Bah. (thanks anyway).