XSLT 3.0:将数字字符替换为英文单词形式的实现求助
解决XSLT中XML元素名数字转英文单词的问题
你之前的思路方向是对的,但问题出在直接用整个属性值去匹配map的键——map只会返回完全匹配的键对应的值,而不会逐个字符替换数字。要实现把字符串里每个数字都换成对应的英文单词,我们需要逐个处理字符串中的每个字符,或者用正则匹配替换的方式来实现。
方案一:XSLT 3.0(推荐,适配你已用到的map特性)
首先定义数字到英文单词的映射map,然后用analyze-string配合函数式替换来逐个处理每个数字字符:
<!-- 定义数字到单词的映射 --> <xsl:variable name="digit-word-map" as="map(xs:string, xs:string)" select=" map { '0': 'zero', '1': 'one', '2': 'two', '3': 'three', '4': 'four', '5': 'five', '6': 'six', '7': 'seven', '8': 'eight', '9': 'nine' } "/> <!-- 处理属性值,替换所有数字为对应单词 --> <xsl:value-of select=" analyze-string(current()/@name, '\d') => replace( function($match) { $digit-word-map($match[1]) <!-- 取出匹配的数字,从map中获取对应单词 --> } ) "/>
效果验证:
3RD_RACK→threeRD_RACKENERGY_CLASS_2010→ENERGY_CLASS_twozeroonezeroPROGRAMMDAUERPROGRAM1→PROGRAMMDAUERPROGRAMone
analyze-string会把输入字符串按正则\d(匹配单个数字)拆分,然后replace方法用自定义函数把每个匹配到的数字替换成map里对应的单词,完美实现你要的效果。
如果你习惯用遍历字符的方式,也可以这样写:
<xsl:value-of select=" string-join( for $char in string-to-codepoints(current()/@name) => codepoints-to-string() return if ($char castable as xs:integer) then $digit-word-map($char) else $char, '' ) "/>
这段代码会把字符串拆成单个字符,逐个判断是否是数字,如果是就取map里的单词,否则保留原字符,最后用string-join拼接成完整字符串。
方案二:XSLT 2.0(如果无法使用XSLT 3.0特性)
如果你的环境不支持XSLT 3.0的map和函数式操作,可以用递归模板来逐个处理字符:
<xsl:template name="replace-digits-with-words"> <xsl:param name="input-string"/> <xsl:if test="$input-string"> <!-- 取第一个字符 --> <xsl:variable name="first-char" select="substring($input-string, 1, 1)"/> <!-- 判断是否是数字,替换成对应单词 --> <xsl:choose> <xsl:when test="$first-char = '0'">zero</xsl:when> <xsl:when test="$first-char = '1'">one</xsl:when> <xsl:when test="$first-char = '2'">two</xsl:when> <xsl:when test="$first-char = '3'">three</xsl:when> <xsl:when test="$first-char = '4'">four</xsl:when> <xsl:when test="$first-char = '5'">five</xsl:when> <xsl:when test="$first-char = '6'">six</xsl:when> <xsl:when test="$first-char = '7'">seven</xsl:when> <xsl:when test="$first-char = '8'">eight</xsl:when> <xsl:when test="$first-char = '9'">nine</xsl:when> <xsl:otherwise><xsl:value-of select="$first-char"/></xsl:otherwise> </xsl:choose> <!-- 递归处理剩余字符 --> <xsl:call-template name="replace-digits-with-words"> <xsl:with-param name="input-string" select="substring($input-string, 2)"/> </xsl:call-template> </xsl:if> </xsl:template>
使用这个模板时,只需要传入属性值即可:
<xsl:call-template name="replace-digits-with-words"> <xsl:with-param name="input-string" select="current()/@name"/> </xsl:call-template>
为什么你之前的代码不生效?
你之前写的$MyMap(current()/@name)是把整个属性值作为键去查map,比如当属性值是3RD_RACK时,map里没有这个键,所以返回空;只有当属性值是单个数字(比如3)时,才会返回three。这就是为什么你只能得到数字部分的原因。
内容的提问来源于stack exchange,提问作者Hayra
相关产品推荐
相关产品推荐

