IBM ACE中XML转CCB的ESQL映射报错(C1元素不匹配)排查
IBM ACE ESQL XML转CCB报错排查与修正
问题背景
使用IBM ACE编写ESQL实现XML到CCB(msg_DATA)的转换时,报错:逻辑定义与消息树不匹配。消息:msg_DATA 元素:C1。需求是:将XML中E2值为'COIL'的<B>节点下<E3>内的<s>节点内容,映射到对应A6节点下B3的C1-C4字段,同时完成其他字段的正确映射。
XML输入结构
<GM xmlns="xyz"> <H> <E1>aaaa</E1> <E2>bbbbb</E2> </H> <I> <E1>ccc</E1> <E2>ddd</E2> <E3>eeeee</E3> </I> <B> <E1>ff</E1> <E2>gg</E2> <E3>hhhh</E3> </B> <B> <E1>ii</E1> <E2>COIL</E2> <E3><Rp><e1>ar</e1><e2>pa</e2><e3>n</e3><s><es1>jh</es1><es2>il</es2><es3>ke</es3><es4>ps</es4></s><s><es1>it</es1><es2>am</es2><es3>eg</es3><es4>ha</es4></s><s><es1>li</es1><es2>na</es2> <es3>uv</es3><es4>wx</es4></s></Rp></E3> </B> <B> <E1>jj</E1> <E2>kk</E2> <E3>llll</E3> </B> </GM>
CCB目标结构
01 DATA 03 A. 05 A1 PIC X(10). 05 A2 PIC X(5). 05 A3 PIC X(5). 05 A4 PIC X(5). 05 A5 PIC X(5). 05 A6 OCCURS 3. 07 B1 PIC X(4). 07 B2 PIC X(4). 07 B3 OCCURS 3. 09 C1 PIC X(2). 09 C2 PIC X(2). 09 C3 PIC X(2). 09 C4 PIC X(2).
报错原因分析
sRef指针复用失效:原代码中sRef仅初始化一次,第一次循环处理完COIL对应的B节点后,指针已移到最后一个<s>节点的下一个位置,后续循环处理其他B节点时,LASTMOVE(sRef)返回假,但逻辑仍尝试赋值B3字段,导致消息树结构与CCB定义不匹配。- 无节点过滤逻辑:原代码给所有A6节点都赋值B3字段,但需求仅要求给E2=COIL的B节点对应的A6节点填充B3数据,其他A6节点不应生成B3子节点,违反了CCB的OCCURS定义。
- 字符长度风险:部分
<s>节点的字段(如第三个<s>的es2包含空格)可能超出CCB中PIC X(2)的长度限制,引发结构错误。
修正后的ESQL代码
CREATE COMPUTE MODULE POC_LOGIC_Mapping CREATE FUNCTION Main() RETURNS BOOLEAN BEGIN CALL CopyMessageHeaders(); SET OutputRoot.MQMD.CodedCharSetId = 1140; SET OutputRoot.MQMD.Encoding = 785; SET OutputRoot.Properties.MessageSet = 'K9IDEGS002001'; SET OutputRoot.Properties.MessageType = 'msg_DATA'; SET OutputRoot.Properties.MessageFormat = 'Binary1'; DECLARE ns1 NAMESPACE 'xyz'; DECLARE i INTEGER 1; DECLARE ms BLOB; DECLARE sNodes REFERENCE; -- 存储解析后的s节点集合 -- 映射顶层A1-A5字段 SET OutputRoot.MRM.A.A1 = coalesce(InputRoot.XMLNSC.ns1:GM.ns1:H.ns1:E1, ''); SET OutputRoot.MRM.A.A2 = coalesce(InputRoot.XMLNSC.ns1:GM.ns1:H.ns1:E2, ''); SET OutputRoot.MRM.A.A3 = coalesce(InputRoot.XMLNSC.ns1:GM.ns1:I.ns1:E1, ''); SET OutputRoot.MRM.A.A4 = coalesce(InputRoot.XMLNSC.ns1:GM.ns1:I.ns1:E2, ''); SET OutputRoot.MRM.A.A5 = coalesce(InputRoot.XMLNSC.ns1:GM.ns1:I.ns1:E3, ''); -- 提取COIL对应的B节点下的E3内容并解析 DECLARE obj1 REFERENCE TO InputRoot.XMLNSC.ns1:GM.ns1:B; X1: WHILE LASTMOVE(obj1) DO IF (obj1.ns1:E2 = 'COIL') THEN SET ms = CAST(obj1.ns1:E3 AS BLOB CCSID InputRoot.Properties.CodedCharSetId); -- 解析XML到临时节点,避免污染原输入树 DECLARE tempXML REFERENCE TO OutputRoot; CREATE LASTCHILD OF tempXML PARSE(ms, InputRoot.Properties.Encoding, InputRoot.Properties.CodedCharSetId); SET sNodes = tempXML.Rp.s; LEAVE X1; ELSE MOVE obj1 NEXTSIBLING; END IF; END WHILE; -- 遍历所有B节点,映射A6 FOR obj2 AS InputRoot.XMLNSC.ns1:GM.ns1:B[] DO SET OutputRoot.MRM.A.A6[i].B1 = coalesce(obj2.ns1:E1, ''); SET OutputRoot.MRM.A.A6[i].B2 = coalesce(obj2.ns1:E2, ''); -- 仅当当前B节点是COIL时,才映射B3字段 IF (obj2.ns1:E2 = 'COIL') THEN DECLARE j INTEGER 1; DECLARE sRef REFERENCE TO sNodes; -- 每次重新指向第一个s节点 WHILE LASTMOVE(sRef) AND j <= 3 DO -- 限制不超过B3的OCCURS次数 -- 截断字符到2位,符合PIC X(2)定义 SET OutputRoot.MRM.A.A6[i].B3[j].C1 = LEFT(coalesce(CAST(sRef.es1 AS CHARACTER), ''), 2); SET OutputRoot.MRM.A.A6[i].B3[j].C2 = LEFT(coalesce(CAST(sRef.es2 AS CHARACTER), ''), 2); SET OutputRoot.MRM.A.A6[i].B3[j].C3 = LEFT(coalesce(CAST(sRef.es3 AS CHARACTER), ''), 2); SET OutputRoot.MRM.A.A6[i].B3[j].C4 = LEFT(coalesce(CAST(sRef.es4 AS CHARACTER), ''), 2); SET j = j + 1; MOVE sRef NEXTSIBLING; END WHILE; END IF; SET i = i + 1; -- 超出A6的OCCURS次数则停止 IF i > 3 THEN LEAVE; END IF; END FOR; RETURN TRUE; END; END MODULE;
关键修正说明
- 临时节点解析:将解析的XML放到
OutputRoot下的临时节点,避免污染原输入消息树,同时确保sNodes始终指向有效的节点集合。 - 条件赋值B3:仅当当前处理的B节点E2值为'COIL'时,才生成B3子节点,严格匹配CCB结构定义。
- 重置
sRef指针:每次处理COIL节点时,重新指向第一个<s>节点,确保能正确遍历所有需要映射的节点。 - 字符长度控制:使用
LEFT函数截断字段到2位,避免超出PIC X(2)的长度限制,防止结构不匹配报错。 - 循环边界控制:添加A6和B3的OCCURS次数限制,避免超出CCB定义的最大重复次数。
内容的提问来源于stack exchange,提问作者ArpanMona
相关产品推荐
相关产品推荐

