含%符号文件名导致XSL的document()函数失效问题求助
解决XSLT中document()函数处理含%符号文件名失效的问题
这个问题我碰到过不少次啦——核心原因是**%在URL里是特殊的转义字符**,你直接把带%的文件名拼进file:/// URL里,document()函数会把它当成转义序列的开头(比如%20代表空格),自然就找不到正确的文件了。
解决方案:转义文件名中的%符号
要让document()正确识别带%的文件名,你需要把文件名里的%替换成URL安全的转义编码%25。下面分两种XSLT版本给你修改方案:
方案1:XSLT 2.0及以上(推荐)
直接用内置的replace()函数就能快速替换,修改你的代码片段如下:
<xsl:template match="file"> <!-- 把文件名中的%替换为%25后再拼接URL --> <xsl:variable name="escaped-filename" select="replace(text(), '%', '%25')"/> <xsl:variable name="sourcedoc" select="concat('file:///', $escaped-filename)"/> <madcapfile> <xsl:attribute name="filename"><xsl:value-of select="text()"/></xsl:attribute> <xsl:apply-templates select="document($sourcedoc)"/> </madcapfile> </xsl:template>
replace(text(), '%', '%25')会把文件名里所有的%都替换成%25,这样生成的file:/// URL就是合法的,document()就能正常加载文件了。
方案2:XSLT 1.0(兼容旧环境)
如果你的环境只能用XSLT 1.0,没有内置的replace()函数,就需要写一个递归模板来替换%:
<!-- 先定义一个递归替换%的模板 --> <xsl:template name="escape-percent"> <xsl:param name="input"/> <xsl:choose> <xsl:when test="contains($input, '%')"> <xsl:value-of select="substring-before($input, '%')"/> <xsl:text>%25</xsl:text> <xsl:call-template name="escape-percent"> <xsl:with-param name="input" select="substring-after($input, '%')"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$input"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- 然后修改你的file匹配模板 --> <xsl:template match="file"> <xsl:variable name="escaped-filename"> <xsl:call-template name="escape-percent"> <xsl:with-param name="input" select="text()"/> </xsl:call-template> </xsl:variable> <xsl:variable name="sourcedoc" select="concat('file:///', $escaped-filename)"/> <madcapfile> <xsl:attribute name="filename"><xsl:value-of select="text()"/></xsl:attribute> <xsl:apply-templates select="document($sourcedoc)"/> </madcapfile> </xsl:template>
这个递归模板会逐个找出文件名里的%,替换成%25,直到处理完整个字符串。
额外提醒
除了%之外,文件名里的其他特殊字符(比如空格、&、#等)也可能导致URL解析问题,如果之后碰到类似情况,也需要对这些字符做对应的URL转义处理哦。
内容的提问来源于stack exchange,提问作者Hobbes
相关产品推荐
相关产品推荐

