views:

332

answers:

2

I use VS 2008, .net 3.5 for generate page html using XSLT.

I have Message, that contains \r\n (newlines)

I use this in XSL file:

<b>Message: </b><xsl:value-of select="Message"/><br/>

I need replace \r\n by <br/> in xsl. I have seen several references but not get solution for my issue:

I use this code C# before I call to transform XSLT, but not right:

 m = m.Replace(@"\r\n", "&#xD;&#xA;");
            m = m.Replace(@"\n", "&#xA;");
            //m = System.Web.HttpUtility.HtmlDecode(m);

            m = m.Replace(@"\r\n", "<br/>");
            m = m.Replace(@"\n", "<br/>");
            msg = "<Exception>"
            + "<Description>" + d + "</Description>"
            + "<Message>" + m + "</Message>"
            + "<DateTime>" + localTimeString + "</DateTime>"
            + "</Exception>";

I use this references, but not solution

http://stackoverflow.com/questions/185101/interpreting-newlines-with-xslt-xsltext

http://stackoverflow.com/questions/1069092/xslt-replace-function-not-found

The replace function is only available in XSLT version 2.0, not in version 1.0 which is what Visual Studio uses. Just because you've specified version="2.0" doesn't mean that Visual Studio supports it.

I use this like the last reference, but I get error:

 <xsl:call-template name="string-replace-all">
      <xsl:with-param name="text" select="Message"/>
      <xsl:with-param name="replace" select="\r\n"/>
      <xsl:with-param name="by" select="&lt;br/&gt;"/>
 </xsl:call-template>

suggestions, any sample code works ?

+1  A: 

The call template above looks OK, you just need the template to go with it!

<!-- XSL FILE -->


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">
  <xsl:variable name="_crlf"><xsl:text>
</xsl:text></xsl:variable>
  <xsl:variable name="crlf" select="string($_crlf)"/>
  <xsl:template match="/">

    <xsl:for-each select="//demo">
      Demo:
      <xsl:call-template name="crlf-replace">
    <xsl:with-param name="subject" select="./text()"/>
      </xsl:call-template>
    </xsl:for-each>
  </xsl:template>

  <xsl:template name="crlf-replace">
    <xsl:param name="subject"/>

    <xsl:choose>
      <xsl:when test="contains($subject, $crlf)">
    <xsl:value-of select="substring-before($subject, $crlf)"/><br/>
    <xsl:call-template name="crlf-replace">
      <xsl:with-param name="subject" select="substring-after($subject, $crlf)"/>
    </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
    <xsl:value-of select="$subject"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>


<!-- XML FILE -->

<?xml version="1.0"?>

<demos>
  <demo>xslt is really fun</demo>
  <demo>you quite often use recursion in xslt</demo>
  <demo>so there!</demo>
</demos>
Robin
I have the template, but get error, using string for search parameter: "\r\n"
alhambraeidos
Note the hack with defining a CRLF from the text of the stylesheet - DO NOT indent this text otherwise the approach will break! Also - I'm on Linux so if you cut-paste from this answer you might not get the full CRLF
Robin
@Robin: This way to define "new line" is not good precisely because such indent restriction. The effective way of declaring such variable would be: `<xsl:variable name="crlf" select="''"/>`
Alejandro
+2  A: 

There are two problems here:

  1. You should not try to replace CRLF -- such a string isn't present in the text. The reason for this is that any compliant XML parser normalizes the text nodes by replacing any CR+LF combination with a single LF (&#xA). The W3C XML Specification says: "To simplify the tasks of applications, wherever an external parsed entity or the literal entity value of an internal parsed entity contains either the literal two-character sequence "#xD#xA" or a standalone literal #xD, an XML processor must pass to the application the single character #xA. (This behavior can conveniently be produced by normalizing all line breaks to #xA on input, before parsing.) "

  2. The replacement shouldn't be a string. It should be a node -- <br />.

Fixing these two problems is easy:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="text()" name="replaceNL">
  <xsl:param name="pText" select="."/>

  <xsl:choose>
    <xsl:when test="contains($pText, '&#xA;')">
      <xsl:value-of select=
        "substring-before($pText, '&#xA;')"/>
      <br />
      <xsl:call-template name="replaceNL">
        <xsl:with-param name="pText" select=
          "substring-after($pText, '&#xA;')"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$pText"/>
    </xsl:otherwise>
  </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on this XML document:

<Exception>
 <Description>Quite common error:
 Missing '('
 </Description>
 <Message>Error1001:
 Syntax error 2002
 </Message>
 <DateTime>localTimeString</DateTime>
</Exception>

the wanted, correct result is produced:

<Exception>
    <Description>Quite common error:<br/> Missing '('<br/> </Description>
    <Message>Error1001:<br/> Syntax error 2002<br/> </Message>
    <DateTime>localTimeString</DateTime>
</Exception>
Dimitre Novatchev
Dimitre is correct in that the parsed text doesn't contain string CRLF even if the document had Windows newlines. However AFAIK the document can contain CRLF combination if it is especially written in it using character entities. Dimitre's answer works in that rare situation too if you just use '' instead of ''
jasso