使用XSLT 1.0将字符串限制为列入白名单的字符

phl*_*opy 0 string xslt whitelist

使用XSLT 1.0,给定一个包含任意字符的字符串,如何找回符合以下规则的字符串.

  1. 第一个字符必须是以下字符之一:az,AZ,冒号或下划线
  2. 所有其他字符必须是上述任何字符或0-9,句点或连字符
  3. 如果任何字符不符合上述规则,请将其替换为下划线

背景

在XSLT中,我将一些属性转换为元素,但我需要确保该属性不包含任何不能在元素名称中使用的值.我不关心转换为名称的属性的完整性,只要它被可预测地转换.我也不需要补偿元素名称中的每个有效字符(有一堆).

我遇到的问题是有空格的属性,translate函数可以很容易地转换为下划线:

translate(@name,' ','_')
Run Code Online (Sandbox Code Playgroud)

但是不久之后我发现了一些使用斜杠的属性,所以我现在也必须添加它.这很快就会失控.我希望能够定义允许字符的白名单,并用下划线替换任何不允许的字符,但翻译可以通过替换黑名单来实现.

Jen*_*niT 6

可以编写一个递归模板来执行此操作,逐个处理字符串中的字符,测试它们并在必要时更改它们.就像是:

<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>
Run Code Online (Sandbox Code Playgroud)

但是,如果你准备好了一些hackery,那么这样做的方法会更短.首先声明一些变量:

<xsl:variable name="underscores"
  select="'_______________________________________________________'" />
<xsl:variable name="initialNameChars"
  select="'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:_'" />
<xsl:variable name="nameChars"
  select="concat($initialNameChars, '0123456789.-')" />
Run Code Online (Sandbox Code Playgroud)

现在,该技术是取的名字和标识的人物不是由该名称替换所有字符的法律合法的什么也没有.您可以使用该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>
Run Code Online (Sandbox Code Playgroud)

您唯一需要注意的是,下划线字符串需要足够长以覆盖可能出现在单个名称中的所有非法字符.使它与您可能遇到的最长名称相同的长度将起到作用(尽管可能你可以侥幸使用它更短).