When attempting to output an empty textarea element, the .NET XSLT processor collapses the element to its short form. Instead of this:
<textarea id="blah" name="blah"></textarea>
I get this:
<textarea id="blah" name="blah"/>
Which causes many web browsers (including IE and Firefox) to render the rest of the page as if it were the contents of the textarea. This sucks.
I can force the XSLT processor to output both the opening and closing textarea tags if I place something in between like a non-breaking space. But that means I have to do more parsing and validation on the client side to tell when the textarea is "truly" empty. I also have to use JavaScript to remove the extra space so that users don't begin their comments with a blank space.
Does anyone know of a way to force the XSLT processor to render both the opening and closing tags without having to insert dummy content?
I you have to use dummy content, this was the xsl:template I used, having just the Line Feed character inside the textarea.
<!-- This prevents empty textarea elements being rendered as singletons in the XHTML output by adding a newline character -->
<xsl:template name="xhtml-textarea-contents">
<!-- what should be contained in the textarea -->
<xsl:param name="contents" />
<xsl:choose>
<xsl:when test="$contents = ''"><xsl:text>
</xsl:text></xsl:when>
<xsl:otherwise><xsl:copy-of select="$contents" /></xsl:otherwise>
</xsl:choose>
</xsl:template>
If you are generating an xml or html, you can write a newline inside the textarea and then remove it with jquery.
This is an example with jQuery:
<textarea> <textarea>
<script>
$(document).ready(function(){
$('textarea').each(
function(index){$(this).text('');}
);
});
</script>
I've come across this issue outside of .net, which is reproducible [for me] in both <xsl:output method="xml">
and <xsl:output method="xhtml">
(I'm making an assumption that method="html"
is inapplicable to our scenario where output has to be well-formed xml)
To avoid the textarea tag from collapsing we have to insert some content into it, but we also have to avoid tampering with actual content. The following:
<xsl:if test="not(normalize-space())"><xsl:comment></xsl:comment></xsl:if>
produces correct results (ie prevents empty textarea
from self-closing and does not introduce artificial content). I believe this behaviour is mentioned in spec under node construction from post-schema-validation infoset , where empty comments' string values would become zero length strings; however the document's phrasing is waaay too w3-ey for light afternoon reading.
Pushing it a bit further ( so if it doesn't tamper with content, do we really need xsl:if
? ), this is the final template that prevents certain tags from collapsing (I aspire to follow the identity transform pattern):
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="textarea">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
<xsl:comment></xsl:comment>
</xsl:copy>
</xsl:template>
NB: browsers' behaviour would suggest this transformation should be applied to some other elements as well, like paragraphs. Having a self-closing <p/>
, however, is not as destructive as having a self-closing <textarea/>
!
Chris Ballance had an answer that worked for me. But it's worth noting that I had been using an overload of XslCompiledTransform that output to a stream, like so:
XslCompiledTransform transform = new XslCompiledTransform();
...
MemoryStream stream = new MemoryStream();
transform.Transform(reader, args, stream);
In order to pass the correct settings along, I had to use the overload that accepted an XmlWriter instead.
// using XmlWriter so I can pass the output settings along.
XmlWriter writer = XmlWriter.Create(stream, transform.OutputSettings);
transform.Transform(reader, args, writer);
Microsoft's using a really odd design pattern there.
I had a similar problem and just realized that if you set the ConformanceLevel of the XmlWriterSettings to Fragment, it eliminates some of the XslCompiledTransform quirks.
FileStream xmlFileStream = File.Create("file.xml");
XslCompiledTransform transform = new XslCompiledTransform();
transform.Load("transform.xsl");
XmlWriterSettings settings = new XmlWriterSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
XmlWriter xmlWriter = XmlWriter.Create(xmlFileStream, settings);
transform.Transform(sourceXml, null, xmlWriter);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.