You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 01:27:17