XSLT self-closing tags issue

2019-01-17 10:37发布

问题:

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.

回答1:

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



回答2:

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"/>


回答3:

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



回答4:

This is related to the XslCompiledTransform class

here is a workaround:

http://blogs.msdn.com/b/nareshjoshi/archive/2009/01/15/how-to-force-non-self-closing-tags-for-empty-nodes-when-using-xslcompiledtransform-class.aspx



回答5:

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>


回答6:

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

  • http://www.biglist.com/lists/xsl-list/archives/200708/msg00538.html
  • http://www.stylusstudio.com/xsllist/200509/post90860.html
  • http://www.richardhallgren.com/removing-namespace-from-outgoing-messages/

etc.



回答7:

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

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


回答8:

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());


回答9:

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" />


回答10:

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/



回答11:

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();
    }
}