使用XSLT和.NET C# VS 2008替换\r\n换行符

3

我使用VS 2008,.net 3.5来使用XSLT生成页面HTML。

我的消息中包含\r\n(换行符)

我在XSL文件中使用以下代码:

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

我需要在XSL中用<br/>替换掉 \r\n。我看到了一些参考资料,但没有解决我的问题:

在调用转换XSLT之前,我使用以下C#代码,但不正确:

 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>";

我使用了这些参考资料,但并没有解决我的问题。

如何解析 xsl:text 中的换行符?

XSLT Replace 函数未找到

Replace 函数仅适用于 XSLT 2.0 版本,而 Visual Studio 使用的是 1.0 版本。即使你已经指定版本为“2.0”,也不意味着 Visual Studio 支持它。

我像最后一个参考资料那样使用,但是我收到了错误消息:

 <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>

建议,有任何示例代码可用吗?

好问题(+1)。请查看我的答案,其中解释了问题并提供了完整的解决方案。 :) - Dimitre Novatchev
3个回答

8
上面的调用模板看起来不错,你只需要与之匹配的模板即可!
<!-- 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>

我有模板,但是使用字符串作为搜索参数时出现错误:"\r\n"。 - Kiquenet
1
请注意,在样式表的文本中定义CRLF的技巧 - 不要缩进此文本,否则这种方法将会中断!另外,我在使用Linux,因此如果您从此答案中剪切粘贴,则可能无法获得完整的CRLF。 - Robin
这种定义“新行”的方式并不好,因为它限制了缩进。声明此类变量的有效方法是:<xsl:variable name="crlf" select="'&#xA;'"/> - user357812
我结合了user357812的建议并且去掉了变量,得到了以下代码:<xsl:template name="crlf-replace"> <xsl:param name="subject"/> xsl:choose <xsl:when test="contains($subject, ' ')"> <xsl:value-of select="substring-before($subject, ' ')"/> <br/> <xsl:call-template name="crlf-replace"> <xsl:with-param name="subject" select="substring-after($subject, ' ')"/> </xsl:call-template> </xsl:when> xsl:otherwise <xsl:value-of select="$subject"/> </xsl:otherwise> </xsl:choose> </xsl:template> - Simon The Cat

5

这里有两个问题:

  1. 你不应该尝试替换CRLF - 这样的字符串在文本中不存在。原因是任何合规的XML解析器都会通过将任何CR + LF组合替换为单个LF (&#xA)来规范化文本节点。 W3C XML规范说:"为了简化应用程序的任务,在外部解析实体或内部解析实体的文字实体值包含文字两个字符序列“#xD#xA”或独立文字“#xD”时,XML处理器必须将单个字符#xA传递给应用程序。(在解析之前,可以通过将所有换行符标准化为#xA来方便地产生此行为。)"

  2. 替换物不应该是字符串。它应该是一个节点 - <br />

解决这两个问题很容易:

<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>

当应用于此XML文档时的转换:

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

期望得到的正确结果已经生成:

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

Dimitre 是正确的,解析后的文本即使包含 Windows 换行符,也不包含字符串 CRLF。但是据我所知,如果文档使用字符实体特别编写了 CRLF 组合,则文档可以包含 CRLF 组合。如果您只使用 '&#xD&#xA' 而不是 '&#xA',那么 Dimitre 的答案在这种罕见情况下也适用。 - jasso

0

我需要将数据库数据写入XML文件并从XML文件中读取,使用LINQ to XML。记录中的某些字段本身是包含\r字符的xml字符串。这些必须保持不变。我花了几天时间试图找到可行的解决方案,但似乎微软设计上将\r转换为\n。

以下解决方案适用于我:

将已加载的XDocument保留\r并写入XML文件,其中xDoc是XDocument,filePath是字符串:

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

将XML文件读入XElement并保留\r:

using (XmlTextReader xmlTextReader = new XmlTextReader(filePath) 
   { WhitespaceHandling = WhitespaceHandling.Significant })
{
     xmlTextReader.MoveToContent();
     xDatabaseElement = XElement.Load(xmlTextReader);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接