简体   繁体   中英

Using XSLT to output an empty HTML textarea element

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?

Find your answer via a similar question right here on Stackoverflow.com :-)

Here is further explanation from MSDN.

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>&#x0A;</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>&#160;<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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM