XslCompiledTransform - closes tags

Hello all.
When transform using XslCompiledTransform it inserst single tags into output like <title /> and <script />
but must be <title></title> and <script></script> because it's conforms to XHTML standart
in Net 1.1 it was right but in Net 2.0 - it's not so.
problem can be solved by adding something like this:
<xsl:text disable-output-escaping="yes">&gt;/script&lt;</xsl:text>


but it should be in the right way anyway
could you please help me with this problem
Simple example illustrate that Net 2.0:
using System;
using System.Xml;
using System.Xml.Xsl;

namespace scriptTagTest
{
  class Program
  {
    static void Main(string[] args)
    {
      XmlDocument xmlDoc = new XmlDocument();
      xmlDoc.AppendChild(xmlDoc.CreateElement("root"));
      XslCompiledTransform xslDoc = new XslCompiledTransform();
      xslDoc.Load("xsl.xsl");
      xslDoc.Transform(xmlDoc, null, Console.Out);
    }
  }
}


same code (Net 1.1):
using System;
using System.Xml;
using System.Xml.Xsl;

namespace scriptTagText1
{
  class Class1
  {
    [STAThread]
    static void Main(string[] args)
    {
      XmlDocument xmlDoc = new XmlDocument();
      xmlDoc.AppendChild(xmlDoc.CreateElement("root"));
      XslTransform xslDoc = new XslTransform();
      xslDoc.Load("xsl.xsl");
      xslDoc.Transform(xmlDoc, null, Console.Out, null);
    }
  }
}

source of xsl.xsl:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
<xsl:output method="xml" encoding="UTF-8" indent="yes" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" omit-xml-declaration="yes"/>
<xsl:template match="/root">
 <html>
  <head>
   <title></title>
   <script type="text/javascript" src="script.js"></script>
  </head>
  <body>
  </body>
 </html>
</xsl:template>
</xsl:stylesheet>

output Net 2.0:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
  <title />
  <script type="text/javascript" src="script.js" />
 </head>
 <body />
</html>

output Net 1.1:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
  <title></title>
  <script type="text/javascript" src="script.js"></script> 
 </head>
 <body>
 </body>
</html>

Thank you.


Answer this question

XslCompiledTransform - closes tags

  • jamie r

    Navigating this link

    http://www.w3.org/TR/REC-xml/#sec-starttags

    one can easily find

    Empty-element tags MAY be used for any element which has no content, 

    whether or not it is declared using the keyword EMPTY. For interoperability, the empty-element tag

    SHOULD be used, and SHOULD only be used, for elements which are declared EMPTY.

    since i've asked to produce XML in output-method it should be this way

    in the same element (output-method) i've placed attribute

    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"

    reading this dtd i cannot find any empty declaration with script tag
    which i can easily find with br tag for instance

    <!ELEMENT br EMPTY>
    <!ELEMENT script (#PCDATA)>

    I belive there is no problem in XSL files - xsl processor should attempt to generate it's output according to DTD specified. Besides dtds for xhtml strict/transitional/frameset may be supported very nice since they are not modified very often.

    ps
    same problem with textareas


  • qmshou

    The problem is in you xsl file.
    You demand the output to be XML and pass it to IE as HTML.

    For XML there is no difference between <script/> and <script></script>, but HTML doesn't have abbreviated form for empty elements.

    1. You can change xsl:output/@method to HTML
    2. You can try to force XSLT produce full end tag by adding non-empty content to script element:
    <scrupt><xsl:text> </xsl:text></script>
    3. Write your custom XmlWriter which produce XHTML output.

    In case 2. you will stay on gray area because abbreviated form of empty elements is not the only XML/HTML incompatibility. (see http://www.w3.org/TR/xslt#section-HTML-Output-Method)



  • metro16327

    I do know this.
    But
    XslTransform in Net 1.1 closes <script> tag (and <link> tag)
    but XslCompiledTransform does not - it puts it as single empty tag.

    besides such HTML
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <title />
    <script type="text/javascript" src="script.js" />
    </head>
    <body>
    text goes here.
    </body>
    </html>

    passes validation but does not shown by IE - so IE believes that all content after script tag is script (IMHO).
    when you put </script> tag - it's ok - IE shows content
    So where is problem in IE or in XslCompiledTransform class

  • Luis E

    Use this ...

    Public Class XHTMLWriter : Inherits System.Xml.XmlTextWriter

    Public Sub New(ByVal textwriter As System.IO.TextWriter)

    MyBase.New(textwriter)

    End Sub

    Public Overloads Overrides Sub WriteEndElement()

    MyBase.WriteFullEndElement()

    End Sub

    End Class


  • dave dave

    SHOULD is rather recommendation it is not MUST.

    The question may be put wider: If you output doctype to XmlWriter would it do DTD validation for you The same can be asked for schema.

    Currently XmlWriter doesn't do any validation, it just copies DTD without even parsing it.

    In any case this is in some sort out of scope for XSLT. Spec doesn’t require you do any validation. It's questionable does it even allow it.

    If you have ValidatiXmlWriter (say you write it yourself) you can pass it to XslCompiledTransform and have validation behavior.

    If you fill this is an important feature fill free to file this suggestion to MS as a new thread in this forum or in the http://connect.microsoft.com.



  • mike5432

    I am experiencing the same problem as well. Regardless of whether the problem is that the output tag on the xslts is incorrectly set to "xml" rather than "html", the mechanism for performing a transform on an xlst has changed from version 1.1 to 2.0 (for the better in many ways). However, that being said my xslts are designed for the 1.1 mechanism (which apparantly either didn't enforce this tag or ignored it all together). Regardless, my predecessors firgured out how to get the desired html to be output in an agreeable manner using the transform 1.1 method.

    This leaves me in the unfortunate predicament of having a stack of xslt's that have the attribute output to "xml" that are no longer producing html that is agreeable to the browser. Unfortunately changing this attribute to "html" did not solve my problem either because it causes the output html to be rendered in a totally differnent (unagreeable) manner.

    Since are eventually moving away from this xslt mechanism I have no intension of going through and debugging all of these new ui issues by modifying the existing xslts. So going with the third suggestion, I went ahead and wrote a very simple writer. It obviously does not do everything at this point but for those of you out there that have the same problem, it should give you guidance in how to solve this issue (at least until microsoft comes up with its own html writer that is backwards compatible with 1.1). I am posting it here because I could not find any documentation on how to build these types of writers and so I had to figure it out by watching which overridden methods get called in which order.

    Hopefully for those of you out there with the same problem, this will save you a few minutes of your time.

    using System;

    using System.Collections.Generic;

    using System.Text;

    using System.Xml;

    namespace nsl.Xml

    {

    public class XmlHtmlWriter : XmlTextWriter

    {

    //array of elements that must be closed with a full end element

    private string[] fullEndElements = new string[] { "script", "title" };

    private string lastStartElement = null;

    public XmlHtmlWriter(System.IO.Stream stream) : base(stream, Encoding.UTF8) { }

    public override void WriteStartElement(string prefix, string localName, string ns)

    {

    lastStartElement = localName;

    base.WriteStartElement(prefix, localName, ns);

    }

    public override void WriteEndElement()

    {

    //if the last opened element is in the full end elements array, then write a full end element for it

    if (Array.IndexOf(fullEndElements, lastStartElement) > -1)

    WriteFullEndElement();

    else

    base.WriteEndElement();

    }

    }

    }



  • Lai F K

    Thanks for your input and sample.
    We are planning to produce XhtmlXmlWriter class at some point and publish it in sources.
    We will announce it in the forum when it will be available.

    Sorry for inconvenience.



  • adb444

    Updated to output & , <,> in script blocks rather than escaped as &amp; &lt; &gt;

    Public Class XHTMLWriter : Inherits System.Xml.XmlTextWriter

    Dim lastStartElement As String

    Public Sub New(ByVal textwriter As System.IO.TextWriter)

    MyBase.New(textwriter)

    End Sub

    Public Overloads Overrides Sub WriteEndElement()

    MyBase.WriteFullEndElement()

    End Sub

    Public Overloads Overrides Sub WriteString(ByVal text As String)

    If lastStartElement = "SCRIPT" Then

    MyBase.WriteRaw(text)

    Else

    MyBase.WriteString(text)

    End If

    End Sub

    Public Overloads Overrides Sub WriteStartElement(ByVal prefix As String, ByVal localName As String, ByVal ns As String)

    lastStartElement = localName.ToUpper

    MyBase.WriteStartElement(prefix, localName, ns)

    End Sub

    End Class


  • Todd Follansbee

    I think you're treading in a gray area, but I definitely see where you're coming from. I briefly reviewed the XHTML standard specific to this matter. You can read it here:
    http://www.w3.org/TR/xhtml1/#prohibitions

    The pertinent sections are C.2 and C.3.

    C.2. Empty Elements

    Include a space before the trailing / and > of empty elements, e.g. <br />, <hr /> and <img src="karen.jpg" alt="Karen" />. Also, use the minimized tag syntax for empty elements, e.g. <br />, as the alternative syntax <br></br> allowed by XML gives uncertain results in many existing user agents.

    C.3. Element Minimization and Empty Element Content

    Given an empty instance of an element whose content model is not EMPTY (for example, an empty title or paragraph) do not use the minimized form (e.g. use <p> </p> and not <p />).

    First let's define a couple things, so we're on the same page. I would define the following as such for the sake of argument:

    Empty = NULL
    Not-Empty = NOT NULL, with or without characters (ie a blank string)

    Now, C.2 says it is OKAY to have minimized tags, if the element has an Empty value. However, C.3 says that if your element contains a Non-Empty value, ie a blank title, than don't use the minimized form.

    I guess I'm sort of reinforcing what you're saying because in your xsl, which, assuming, is XHTML 1.0 compliant, you specfically put <title></title> which should mean to the parsing engine that this title is Not-Empty, but just blank.



  • XslCompiledTransform - closes tags