您可以编写一个递归模板来执行此操作,逐个处理字符串中的字符,测试它们并在必要时更改它们。就像是:
<xsl:template name="normalizeName">
<xsl:param name="name" />
<xsl:param name="isFirst" select="true()" />
<xsl:if test="$name != ''">
<xsl:variable name="first" select="substring($name, 1, 1)" />
<xsl:variable name="rest" select="substring($name, 2)" />
<xsl:choose>
<xsl:when test="contains('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:_', $first) or
(not($first) and contains('0123456789.-', $first))">
<xsl:value-of select="$first" />
</xsl:when>
<xsl:otherwise>
<xsl:text>_</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:call-template name="normalizeName">
<xsl:with-param name="name" select="$rest" />
<xsl:with-param name="isFirst" select="false()" />
</xsl:call-template>
</xsl:if>
</xsl:template>
但是,如果您准备好进行一些黑客攻击,则可以使用更短的方法来执行此操作。首先声明一些变量:
<xsl:variable name="underscores"
select="'_______________________________________________________'" />
<xsl:variable name="initialNameChars"
select="'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:_'" />
<xsl:variable name="nameChars"
select="concat($initialNameChars, '0123456789.-')" />
现在的技术是通过将名称中所有合法的字符替换为空来获取名称并识别不合法的字符。您可以使用该功能执行此操作。一旦您获得了字符串中出现的一组非法字符,您可以再次使用该函数将它们替换为下划线。这是模板:translate()
translate()
<xsl:template name="normalizeName">
<xsl:param name="name" />
<xsl:variable name="first" select="substring($name, 1, 1)" />
<xsl:variable name="rest" select="substring($name, 2)" />
<xsl:variable name="illegalFirst"
select="translate($first, $initialNameChars, '')" />
<xsl:variable name="illegalRest"
select="translate($rest, $nameChars, '')" />
<xsl:value-of select="concat(translate($first, $illegalFirst, $underscores),
translate($rest, $illegalRest, $underscores))" />
</xsl:template>
唯一需要注意的是,下划线字符串需要足够长,以覆盖单个名称中可能出现的所有非法字符。使它的长度与您可能遇到的最长名称的长度相同就可以解决问题(尽管您可能会逃脱它的长度要短得多)。