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 <= $currentLevel"> <xsl:break/> </xsl:if> <!-- 收集下级节点的最终CALLOUT值 --> <xsl:if test="$childLevel > $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
相关产品推荐
相关产品推荐

