开发者

Replace \r\n Newlines using XSLT and .NET C# VS 2008

开发者 https://www.devze.com 2023-01-12 19:47 出处:网络
I use VS 2008, .net 3.5 for generate page html using XSLT. I have Message, that contains \\r\\n (newlines)

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 functi开发者_如何学编程on 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 ?


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>


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>


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

精彩评论

暂无评论...
验证码 换一张
取 消