XSLT 3.0构造map时如何处理重复键避免转换中断
XSLT 3.0 重复键处理方案
你原参考代码无法实现重复键判断的核心原因:<xsl:map>块执行过程中,外层的$mapping变量尚未完成实例化,循环内部无法访问已写入的map条目做存在性校验,直接写判断逻辑会出现变量未定义的问题,或始终判定为空。
标准合规实现:基于xsl:iterate累加构造
xsl:iterate是XSLT 3.0正式规范支持的迭代语法,支持在迭代过程中携带累加状态参数,完全满足逐行校验重复键、输出提示、跳过重复条目的需求,不需要依赖任何后续版本的扩展特性,实现代码如下:
<xsl:function name="myns:loadMapping" as="map(*)"> <xsl:param name="inputFile" as="xs:string"/> <xsl:param name="fileEncoding" as="xs:string"/> <xsl:iterate select="unparsed-text-lines($inputFile, $fileEncoding)"> <!-- 迭代累加器:初始为空map,每轮迭代更新为最新的键值对集合 --> <xsl:param name="currentMap" as="map(xs:string, xs:string)" select="map{}"/> <xsl:variable name="currentLine" select="normalize-space(.)"/> <xsl:choose> <!-- 跳过空行、注释行、不含等号的无效行 --> <xsl:when test="$currentLine = '' or starts-with($currentLine, '#') or not(contains($currentLine, '='))"> <xsl:next-iteration> <xsl:with-param name="currentMap" select="$currentMap"/> </xsl:next-iteration> </xsl:when> <xsl:otherwise> <xsl:variable name="entryKey" select="substring-before($currentLine, '=')"/> <xsl:variable name="entryValue" select="substring-after($currentLine, '=')"/> <xsl:choose> <!-- 检测到重复键,输出提示,保留首个出现的条目不覆盖 --> <xsl:when test="map:contains($currentMap, $entryKey)"> <xsl:message select="'Warning: Duplicate key found in mapping file: ' || $entryKey || ', please check your input content.'"/> <xsl:next-iteration> <xsl:with-param name="currentMap" select="$currentMap"/> </xsl:next-iteration> </xsl:when> <!-- 无重复,将新条目追加到map传入下一轮迭代 --> <xsl:otherwise> <xsl:next-iteration> <xsl:with-param name="currentMap" select="map:put($currentMap, $entryKey, $entryValue)"/> </xsl:next-iteration> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> <!-- 所有行处理完成后返回最终构建的map --> <xsl:on-completion> <xsl:sequence select="$currentMap"/> </xsl:on-completion> </xsl:iterate> </xsl:function>
其他可选方案说明
- 如果不需要定位具体重复键、仅需避免转换中止,可以直接使用
map:merge函数,通过duplicates参数指定重复键处理策略,无需逐行判断:
其中<xsl:variable name="mapping" as="map(xs:string, xs:string)" select=" map:merge( unparsed-text-lines($inputFile, $fileEncoding) [normalize-space(.) != '' and not(starts-with(normalize-space(.), '#')) and contains(., '=')] ! map:entry(substring-before(normalize-space(.), '='), substring-after(normalize-space(.), '=')), map{'duplicates': 'use-first'} ) "/>duplicates支持的标准取值包括use-first(保留第一个出现的键值)、use-last(保留最后一个出现的键值)、combine(将重复键对应的值合并为序列),该方案性能更好,但无法在遇到重复键时输出自定义提示信息。 - XSLT 3.0提供的
xsl:try/xsl:catch语法可以捕获XTDE3365重复键错误,但捕获后无法获取map构造中途的部分结果,只能整体返回空值或默认map,无法实现「遇错提示但继续处理有效条目」的需求,不适用于当前场景。
内容的提问来源于stack exchange,提问作者Sebastien
相关产品推荐
相关产品推荐

