PRB: XML/XSL Render Tags as Empty-Element Tag When an Attribute Is Added with No Content (251145)



The information in this article applies to:

  • Microsoft XML 2.0
  • Microsoft XML 2.5
  • Microsoft XML 2.6
  • Microsoft XML 3.0
  • Microsoft XML 4.0

This article was previously published under Q251145

SYMPTOMS

When you use XSL to add an attribute without any content between the start tag and the end tag, the Microsoft XML parser, MSXML, will render it as empty-element tag.

CAUSE

MSXML is trying to generate well-formed HTML without knowledge of HTML's requirement that some elements need end tags and some don't. MSXML performs heuristics that try to evaluate whether there was an attempt to add content to the tag, and if so it produces separate start and end tags. This works reasonably well, but it can be thrown off by the use of <xsl:attribute> when creating empty HTML elements that require end tags.

The XSLT Recommendation (see "References" section) addresses this problem by allowing stylesheets to output legal HTML. The XHTML Candidate Recommendation addresses this problem by promoting HTML parsers to recognized well-formed markup.

RESOLUTION

Adding an empty CDATA tag in between the start tag and the end tag immediately after the attributes will resolve the problem.

STATUS

This behavior is by design.

MORE INFORMATION

Steps Showing the Problem and the Workaround

  1. Create Test.xml like the following:
    <?xml version="1.0"?>
    <?xml-stylesheet type="text/xsl" href="test.xsl"?>
    <Data>
        <Tag1>
           <color>#CFCFCF</color>
        </Tag1>
        <Tag2> This is a paragraph.</Tag2>
    </Data>
    					
  2. Create Test.xsl like the following:
    <?xml version="1.0"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
    <xsl:template match="/">
    <html>
    <body onLoad="ShowProblem()">
      <script language="jscript">
        <xsl:comment><![CDATA[   
          function ShowProblem()
          {
             d1.innerHTML += "Content of the d1";
             alert('The innerHTML of the Div (d1) is now:" ' + d1.innerHTML + '"');
          } 
        ] ]></xsl:comment>
      
      </script>
      <xsl:apply-templates select="Data/Tag1" />
      <xsl:apply-templates select="Data/Tag2" />
      <p> The innerHTML of the Div (d1) show be just "Content of the d1".  But instead it's now including the p tag. </p>
    </body>
    </html>
    </xsl:template>
    
    <xsl:template match="Tag1">
      <div id="d1" name="d1">
        <xsl:attribute name="style">background-color: <xsl:value-of/>; </xsl:attribute>
      </div>
    </xsl:template>
    
    <xsl:template match="Tag2">
      <p>
        <xsl:value-of />
      </p>
    </xsl:template>
    
    </xsl:stylesheet>
    					
  3. Navigate to Test.xml using Internet Explorer. You will see an alert box showing the innerHTML of the Div tag. You will see it includes the content of the paragraph following the Div.
  4. To work around the problem, you can add an empty CDATA immediately after the ending tag of the attribute. (NOTE: When pasting this example, be sure to eliminate any extraneous white space that may appear in the formatting of the article, as this may affect the appearance of your transformed document.)
  5. Create Fix.xsl with the following code:
    <?xml version="1.0"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
    <xsl:template match="/">
    <html>
    <body onLoad="ShowProblem()">
      <script language="jscript">
        <xsl:comment><![CDATA[   
          function ShowProblem()
          {
             d1.innerHTML += "Content of the d1";
             alert('The innerHTML of the Div (d1) is now:" ' + d1.innerHTML + '"');
          } 
        ] ]></xsl:comment>
      
      </script>
      <xsl:apply-templates select="Data/Tag1" />
      <xsl:apply-templates select="Data/Tag2" />
      <p> With the CDATA tag, the innerHTML of the Div (d1) now show up correctly. </p>
    </body>
    </html>
    </xsl:template>
    
    <xsl:template match="Tag1">
      <div id="d1" name="d1">
        <xsl:attribute name="style">background-color: <xsl:value-of/>; </xsl:attribute>
        <![CDATA[ ] ]>
      </div>
    </xsl:template>
    
    <xsl:template match="Tag2">
      <p>
        <xsl:value-of />
      </p>
    </xsl:template>
    
    </xsl:stylesheet>
    					
  6. Alter Test.xml to point to Fix.xsl.
  7. Navigate to Test.xml again to show the workaround. Now the alert box will show the correct content of the Div.

REFERENCES

For more information about developing Web-based solutions for Microsoft Internet Explorer, visit the following Microsoft Web sites:

Modification Type:MajorLast Reviewed:5/11/2006
Keywords:kbprb KB251145