如何在XSLT的href属性中正确显示含法语特殊字符的动态链接?
看起来你遇到的核心问题是XML里的实体编码字符在链接href属性中被双重转义了——文本显示正常,但href里的é变成了é,导致URL失效。我来帮你拆解问题并给出解决方案:
问题根源
你的XML中Attachments节点的内容是实体编码后的字符串(比如Présentation.pdf),而不是原生的UTF-8字符。当你在文本节点用disable-output-escaping="yes"时,XSLT会把实体解码成正确的字符,所以链接文本显示正常;但在属性值中,disable-output-escaping的行为在XSLT 1.0中是未定义的,处理器会自动转义&符号,把é变成é,最终生成的href就变成了无效的Présentation.pdf。
解决方案
我们需要先把实体编码的字符串解码成原生UTF-8字符,再拼接成链接。下面是两种情况的处理方式:
情况1:XML中存储的是实体编码字符串(如Présentation.pdf)
添加一个递归模板来解码HTML数字实体,然后在构建href和链接文本时调用这个模板:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html" encoding="UTF-8"/> <!-- 递归模板:解码HTML数字实体(如é) --> <xsl:template name="decode-entities"> <xsl:param name="text"/> <xsl:choose> <xsl:when test="contains($text, '&#')"> <xsl:variable name="before" select="substring-before($text, '&#')"/> <xsl:variable name="after" select="substring-after($text, '&#')"/> <xsl:variable name="code" select="substring-before($after, ';')"/> <!-- 将数字编码转换为对应字符 --> <xsl:value-of select="$before"/> <xsl:value-of select="concat('&#', $code, ';')" disable-output-escaping="yes"/> <!-- 递归处理剩余文本 --> <xsl:call-template name="decode-entities"> <xsl:with-param name="text" select="substring-after($after, ';')"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$text"/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="/"> <table id="tableRepeat" border="1" width="100%" style="border-collapse:collapse;color:black;font-size:100%;font-family:arial,helvetica,sans-serif;"> <thead> <tr> <td>Attachments</td> </tr> </thead> <tbody> <xsl:for-each select="//Items/Item"> <tr> <td> <a> <xsl:attribute name="href"> https://website.com/sites/ <xsl:call-template name="decode-entities"> <xsl:with-param name="text" select="Attachments"/> </xsl:call-template> </xsl:attribute> <xsl:call-template name="decode-entities"> <xsl:with-param name="text" select="Attachments"/> </xsl:call-template> </a> </td> </tr> </xsl:for-each> </tbody> </table> </xsl:template> </xsl:stylesheet>
这个模板会遍历文本,把所有&#xxx;格式的实体解码成对应的UTF-8字符,无论在属性还是文本中都能正常显示,不会出现双重转义的问题。
情况2:XML中存储的是原生UTF-8字符(如Présentation.pdf)
这种情况更简单,直接用属性值模板简化代码,移除disable-output-escaping即可:
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html" encoding="UTF-8"/> <xsl:template match="/"> <table id="tableRepeat" border="1" width="100%" style="border-collapse:collapse;color:black;font-size:100%;font-family:arial,helvetica,sans-serif;"> <thead> <tr> <td>Attachments</td> </tr> </thead> <tbody> <xsl:for-each select="//Items/Item"> <tr> <td> <!-- 使用属性值模板直接拼接链接 --> <a href="https://website.com/sites/{Attachments}"> <xsl:value-of select="Attachments"/> </a> </td> </tr> </xsl:for-each> </tbody> </table> </xsl:template> </xsl:stylesheet>
只要XML和XSLT文件都使用UTF-8编码,输出也指定UTF-8,浏览器就能正确识别法语特殊字符,生成的href会是你期望的https://website.com/sites/Présentation.pdf。
内容的提问来源于stack exchange,提问作者devLope

