3

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

Interpreting newlines with xsl:text?

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 ?

Community
  • 1
  • 1
Kiquenet
  • 14,494
  • 35
  • 148
  • 243

3 Answers3

8

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
  • 4,242
  • 1
  • 20
  • 20
  • I have the template, but get error, using string for search parameter: "\r\n" – Kiquenet Aug 22 '10 at 12:40
  • 1
    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 Aug 22 '10 at 12:47
  • This way to define "new line" is not good precisely because such indent restriction. The effective way of declaring such variable would be: `` –  Aug 23 '10 at 13:52
  • I combined user357812's suggestion and dropped the variables and got this:
    – Simon The Cat Aug 26 '15 at 13:05
5

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">
    <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
  • 240,661
  • 26
  • 293
  • 431
  • 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 Aug 22 '10 at 22:26
0

I had to write database data to an xml file and read it back from the xml file, using LINQ to XML. Some fields in a record were themselves xml strings complete with \r characters. These had to remain intact. I spent days trying to find something that would work, but it seems Microsoft was by design converting \r to \n.

The following solution works for me:

To write a loaded XDocument to the XML file keeping \r intact, where xDoc is an XDocument and filePath is a string:

XmlWriterSettings xmlWriterSettings = new XmlWriterSettings 
    { NewLineHandling = NewLineHandling.None, Indent = true };
using (XmlWriter xmlWriter = XmlWriter.Create(filePath, xmlWriterSettings))
{
    xDoc.Save(xmlWriter);
    xmlWriter.Flush();
}

To read an XML file into an XElement keeping \r intact:

using (XmlTextReader xmlTextReader = new XmlTextReader(filePath) 
   { WhitespaceHandling = WhitespaceHandling.Significant })
{
     xmlTextReader.MoveToContent();
     xDatabaseElement = XElement.Load(xmlTextReader);
}
CMarsden
  • 361
  • 3
  • 5