You need to enable JavaScript to run this app. XSLT 1.0下空CALLOUT索引化及关联字段填充实现咨询
优惠活动
大模型
产品
解决方案
定价
更多

XSLT 1.0下空CALLOUT索引化及关联字段填充实现咨询

实现结论

所有需求均可通过XSLT 1.0原生语法实现,无需依赖扩展函数或升级版本

核心实现思路

1. 空CALLOUT的索引填充

  • 现有代码缺陷:仅定位同组外的下一个非空CALLOUT,未限定ESN+GRAPHIC_NAME分组范围,也无法统计连续空值的序号生成.1/.2类后缀
  • 实现逻辑:
    • 复用现有xsl:key按ESN+GRAPHIC_NAME分组,避免跨组取值
    • 对每个空CALLOUT节点,在同组内定位「后方第一个非空CALLOUT节点」作为锚点
    • 统计锚点之前的连续空CALLOUT的顺序序号(从1开始),最终CALLOUT为锚点值.序号
  • 示例:同组内连续两条空CALLOUT,后续锚点值为3,那么两条空值的CALLOUT分别为3.1、3.2

2. YCSPOSNO_PI的字母后缀生成

  • 现有代码缺陷:XSLT 1.0无原生字母递增能力,未统计锚点前的空值总数生成对应字母后缀
  • 实现逻辑:
    • 定义固定字母映射表常量ABCDEFGHIJKLMNOPQRSTUVWXYZ,通过序号截取对应位置的字符实现字母递增
    • 锚点的基础CALLOUT值为其原始非空值,统计同组内该锚点前的连续空值总数
    • 派生的索引化CALLOUT后缀从A开始顺序取值,原始非空CALLOUT的后缀为「空值总数+1」对应的字母
  • 示例:锚点值3前有2条连续空CALLOUT,两条派生值的后缀分别为A、B,原始值3的后缀为C,最终拼接为3A、3B、3C

3. EXPLA的下级层级CALLOUT拼接

  • 现有代码缺陷:未实现层级判断逻辑,无法正确收集当前节点的所有下级层级节点
  • 实现逻辑:
    • 仅为派生的索引化CALLOUT生成EXPLA,原始非空CALLOUT的EXPLA留空
    • 同组内从当前节点向后遍历,只要节点LEVEL_NO大于当前LEVEL_NO,就将其最终CALLOUT值收集
    • 遇到任意节点LEVEL_NO小于等于当前LEVEL_NO时立即停止收集,符合层级重置规则
    • 收集的CALLOUT值用+拼接,最终格式为当前CALLOUT = 下级CALLOUT拼接结果
  • 示例:当前节点LEVEL_NO为1,后续依次是LEVEL_NO2(CALLOUT3.2)、LEVEL_NO3(CALLOUT4)、LEVEL_NO2(CALLOUT5),最终EXPLA为3.1 = 3.2+5
补全后的可运行XSLT代码
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:ns="urn:las:pp:ss1:tar" exclude-result-prefixes="ns">
    <xsl:output indent="yes" method="xml"/>
    <!-- 按ESN+GRAPHIC_NAME分组的索引 -->
    <xsl:key name="groupByGraphic" match="Record" use="concat(ESN, '#', GRAPHIC_NAME)"/>
    <!-- 字母映射表,用于生成递增后缀 -->
    <xsl:variable name="letterMap" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>

    <xsl:template match="/">
        <!-- 取每个分组的第一个Record作为分组头 -->
        <xsl:apply-templates select="ns:MT_FlatFile_Lists_Cu/Cu_Records/Record[generate-id(.) = generate-id(key('groupByGraphic', concat(ESN, '#', GRAPHIC_NAME))[1])]" mode="groupHead"/>
    </xsl:template>

    <!-- 分组头模板,生成YCSMST01外层结构 -->
    <xsl:template match="Record" mode="groupHead">
        <xsl:variable name="groupKey" select="concat(ESN, '#', GRAPHIC_NAME)"/>
        <YCSMST01>
            <IDOC BEGIN="1">
                <EDI_DC40 SEGMENT="1">
                    <SNDPOR/>
                    <SNDPRT/>
                    <SNDPRN/>
                    <SNDLAD/>
                </EDI_DC40>
                <!-- 处理当前分组下的所有Record -->
                <xsl:apply-templates select="key('groupByGraphic', $groupKey)" mode="processRecord"/>
            </IDOC>
        </YCSMST01>
    </xsl:template>

    <!-- 单条Record核心处理模板 -->
    <xsl:template match="Record" mode="processRecord">
        <xsl:variable name="currentGroup" select="concat(ESN, '#', GRAPHIC_NAME)"/>
        <xsl:variable name="groupRecords" select="key('groupByGraphic', $currentGroup)"/>
        <xsl:variable name="currentPos" select="position()"/>

        <!-- 定位当前节点对应的锚点(后方第一个非空CALLOUT节点) -->
        <xsl:variable name="anchorNode" select="($groupRecords[position() > $currentPos and CALLOUT != ''])[1]"/>
        <!-- 计算当前空值在连续序列中的序号 -->
        <xsl:variable name="emptySeq" select="count($groupRecords[position() >= $currentPos and position() < position($anchorNode) and CALLOUT = '']) + 1"/>
        <!-- 判断当前是否为派生的索引化CALLOUT -->
        <xsl:variable name="isDerived" select="CALLOUT = ''"/>
        <!-- 生成最终CALLOUT值 -->
        <xsl:variable name="finalCallout">
            <xsl:choose>
                <xsl:when test="$isDerived">
                    <xsl:value-of select="concat($anchorNode/CALLOUT, '.', $emptySeq)"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="CALLOUT"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>

        <!-- 生成YCSPOSNO_PI字母后缀 -->
        <xsl:variable name="anchorPos" select="position($anchorNode)"/>
        <xsl:variable name="totalEmptyBeforeAnchor" select="count($groupRecords[position() >= $currentPos and position() < $anchorPos and CALLOUT = ''])"/>
        <xsl:variable name="letterSeq">
            <xsl:choose>
                <!-- 派生节点的序号为自身空值顺序 -->
                <xsl:when test="$isDerived">
                    <xsl:value-of select="$emptySeq"/>
                </xsl:when>
                <!-- 原始锚点节点的序号为总空值数+1 -->
                <xsl:otherwise>
                    <xsl:value-of select="$totalEmptyBeforeAnchor + 1"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:variable>
        <xsl:variable name="posNo" select="concat($anchorNode/CALLOUT, substring($letterMap, $letterSeq, 1))"/>

        <!-- 生成EXPLA字段 -->
        <xsl:variable name="currentLevel" select="LEVEL_NO"/>
        <xsl:variable name="childCallouts">
            <xsl:if test="$isDerived">
                <xsl:for-each select="$groupRecords[position() > $currentPos]">
                    <xsl:variable name="childLevel" select="LEVEL_NO"/>
                    <!-- 遇到层级<=当前值时停止收集 -->
                    <xsl:if test="$childLevel &lt;= $currentLevel">
                        <xsl:break/>
                    </xsl:if>
                    <!-- 收集下级节点的最终CALLOUT值 -->
                    <xsl:if test="$childLevel &gt; $currentLevel">
                        <xsl:variable name="childAnchor" select="($groupRecords[position() > position() and CALLOUT != ''])[1]"/>
                        <xsl:variable name="childEmptySeq" select="count($groupRecords[position() >= position() and position() < position($childAnchor) and CALLOUT = '']) + 1"/>
                        <xsl:variable name="childFinalCallout">
                            <xsl:choose>
                                <xsl:when test="CALLOUT = ''">
                                    <xsl:value-of select="concat($childAnchor/CALLOUT, '.', $childEmptySeq)"/>
                                </xsl:when>
                                <xsl:otherwise>
                                    <xsl:value-of select="CALLOUT"/>
                                </xsl:otherwise>
                            </xsl:choose>
                        </xsl:variable>
                        <xsl:value-of select="concat('+', $childFinalCallout)"/>
                    </xsl:if>
                </xsl:for-each>
            </xsl:if>
        </xsl:variable>
        <xsl:variable name="finalExpla">
            <xsl:if test="$isDerived and $childCallouts != ''">
                <xsl:value-of select="concat($finalCallout, ' = ', substring($childCallouts, 2))"/>
            </xsl:if>
        </xsl:variable>

        <!-- 输出最终业务节点 -->
        <YCSMOTOR_STKL01 SEGMENT="1">
            <YCSSTKLID>
                <xsl:value-of select="concat(ESN, '#', substring-before(GRAPHIC_NAME, '.'))"/>
            </YCSSTKLID>
            <CALLOUT>
                <xsl:value-of select="$finalCallout"/>
            </CALLOUT>
            <YCSPOSNO_PI>
                <xsl:value-of select="$posNo"/>
            </YCSPOSNO_PI>
            <EXPLA>
                <xsl:value-of select="$finalExpla"/>
            </EXPLA>
        </YCSMOTOR_STKL01>
    </xsl:template>
</xsl:stylesheet>

注意:若使用的XSLT 1.0处理器不支持<xsl:break>扩展,可将下级节点收集逻辑替换为纯XPath谓词筛选:$groupRecords[position() > $currentPos and LEVEL_NO > $currentLevel and not(preceding-sibling::Record[position() > $currentPos][LEVEL_NO <= $currentLevel])],无需循环即可实现层级截断效果。

内容的提问来源于stack exchange,提问作者Asorium

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.12 04:36:03