从Seeburger迁移自定义位置式平面文件架构至BizTalk遇问题求助
BizTalk处理位置式平面文件末尾可选字段无填充的解决方案
问题场景
我在将Seeburger的位置式平面文件架构迁移到BizTalk时碰到了麻烦:
- 原Seeburger定义的标准消息格式(用
-标识填充符):Field1----Field2-------Field3----Field4--[CR][LF] - 字段规则:
- Field1:最小/最大长度10字符
- Field2:最小/最大长度13字符
- Field3:最小/最大长度10字符
- Field4:最小/最大长度8字符
- 所有字段均为可选
但实际收到的消息经常出现末尾字段不带填充符的情况,比如:
Field1----Field2-------Field3----Field4[CR][LF]
或
Field1----Field2-------Field3[CR][LF]
Seeburger能正常解析这类消息,但BizTalk会因为末尾字段长度不符合架构定义而校验失败,试过几种方法都没解决。
可行解决方案
1. 自定义接收管道组件补全填充符
写一个简单的自定义管道组件,在BizTalk解析之前预处理消息,补全末尾的填充符:
- 按
[CR][LF]拆分每条记录 - 根据架构总长度(10+13+10+8=41字符,不含终止符),用指定填充符补全每条记录到总长度
- 拼接处理后的记录再传给解析器
C#代码示例:
public IBaseMessage Execute(IPipelineContext pContext, IBaseMessage pInMsg) { var originalStream = pInMsg.BodyPart.GetOriginalDataStream(); var messageContent = new StreamReader(originalStream).ReadToEnd(); var records = messageContent.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); var processedRecords = new List<string>(); const int totalRecordLength = 41; const char padChar = '-'; foreach (var record in records) { processedRecords.Add(record.Length < totalRecordLength ? record.PadRight(totalRecordLength, padChar) : record); } var processedContent = string.Join("\r\n", processedRecords) + "\r\n"; var newStream = new MemoryStream(Encoding.UTF8.GetBytes(processedContent)); pInMsg.BodyPart.Data = newStream; pContext.ResourceTracker.AddResource(newStream); return pInMsg; }
写完后把组件部署到BizTalk,添加到接收管道的Decode阶段即可。
2. 调整BizTalk平面文件架构属性
如果不想写代码,可以尝试修改架构的字段设置:
- 把末尾可选字段(比如Field4、Field3)的Minimum Length设为0,Justification设为
Left,Pad Character设为对应的填充符 - 将记录的Structure改为
Delimited,段终止符设为[CR][LF],同时给每个字段设置正确的Position和Maximum Length - 开启字段的Allow Early Termination属性(部分BizTalk版本支持),允许字段在遇到段终止符时提前结束,不用填满最大长度
这个方法需要多测试几种缺失场景,确保解析结果和预期一致。
3. 用XSLT预处理消息
在接收管道里加一个XSLT转换组件,提前补全填充符:
- 按行读取原始消息
- 对每行判断长度,不足总长度的补全填充符
- 输出处理后的文本
XSLT示例:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="utf-8"/> <xsl:param name="totalLength" select="41"/> <xsl:param name="padChar" select="'-'"/> <xsl:template match="/"> <xsl:apply-templates select="text()"/> </xsl:template> <xsl:template match="text()"> <xsl:call-template name="processLines"> <xsl:with-param name="lines" select="tokenize(., '\r\n')"/> </xsl:call-template> </xsl:template> <xsl:template name="processLines"> <xsl:param name="lines"/> <xsl:if test="$lines"> <xsl:variable name="currentLine" select="$lines[1]"/> <xsl:choose> <xsl:when test="string-length($currentLine) < $totalLength"> <xsl:value-of select="concat($currentLine, string-join(for $i in 1 to ($totalLength - string-length($currentLine)) return $padChar, ''))"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$currentLine"/> </xsl:otherwise> </xsl:choose> <xsl:if test="count($lines) > 1"> <xsl:text> </xsl:text> </xsl:if> <xsl:call-template name="processLines"> <xsl:with-param name="lines" select="$lines[position() > 1]"/> </xsl:call-template> </xsl:if> </xsl:template> </xsl:stylesheet>
内容的提问来源于stack exchange,提问作者cbi
相关产品推荐
相关产品推荐

