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

BizTalk:为无分隔符位置式平面文件构建XSD

基于位置式平面文件构建BizTalk XSD实现XML转换

样例平面文件数据

0000000020220709200012000000  000000000  000000000  000000000  000000000             
002029832022070922162607090111057992132                                 F        
00210018202207091911210709033S061991911DS0649919111S067891911           F   
9999999900000000000020000000  000000000  000000000  000000000  000000000      

字段位置定义

列名起始位置结束位置备注
Area08固定长度8位
Date916固定长度8位
行内记录数2728决定该行包含多少个Change值,固定长度2位
Change 13135固定长度5位,原文结束位置25为笔误,按样例数据修正
Change 24246比Change 1偏移11位,固定长度5位
Change 35357比Change 2偏移11位,固定长度5位

期望XML输出

<Lookup_Value_Set>
     <Record>
          <Area>00202983</Area>
          <Date>20220709</Date>
          <Change>05799</Change>
     </Record>
     <Record>
          <Area>00210018</Area>
          <Date>20220709</Date>
          <Change>06199</Change>
     </Record>
     <Record>
          <Area>00210018</Area>
          <Date>20220709</Date>
          <Change>06499</Change>
     </Record>
</Lookup_Value_Set>

遇到的错误

Decoding of the flat file failed: 'Unexpected data found while looking for: '\n' The current definition being parsed is Lookup_Value_Set. The stream offset where the error occured is 75

环境信息

  • 文件来自Linux系统,行分隔符为LF(\n)而非CRLF
  • 每行固定100字符,数据仅填充至第73位
  • 使用BizTalk命名空间xmlns="http://schemas.microsoft.com/BizTalk/2003"

解决方案与XSD样例

核心解决要点

  1. 行分隔符配置:明确指定LF为行分隔符,同时按固定100字符长度定义行结构,避免数据未填满整行导致的匹配错误
  2. 首尾行跳过:通过skip_first_rows和skip_last_rows属性直接跳过首尾行,无需额外筛选逻辑
  3. 可变Change字段处理:利用内嵌脚本将单行内的多个Change值拆分为独立的Record节点,匹配期望输出格式

完整XSD代码

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns="http://schemas.microsoft.com/BizTalk/2003"
           xmlns:msxsl="urn:schemas-microsoft-com:xslt"
           xmlns:user="http://schemas.microsoft.com/BizTalk/2003/user"
           targetNamespace="http://schemas.microsoft.com/BizTalk/2003"
           attributeFormDefault="unqualified"
           elementFormDefault="qualified">

  <xs:annotation>
    <xs:appinfo>
      <schemaEditorExtension:schemaInfo namespaceAlias="b" extensionClass="Microsoft.BizTalk.FlatFileExtension.FlatFileExtension" standardName="Flat File" xmlns:schemaEditorExtension="http://schemas.microsoft.com/BizTalk/2003/SchemaEditorExtensions"/>
      <b:schemaInfo standard="Flat File" codepage="65001" default_pad_char=" " pad_char_type="char" count_positions_by_byte="false" parser_optimization="speed" lookahead_depth="3" suppress_empty_nodes="false" generate_empty_nodes="true" allow_early_termination="false" early_terminate_optional_fields="false" allow_message_breakup_of_infix_root="false" compile_parse_tables="false" root_reference="Lookup_Value_Set"/>
    </xs:appinfo>
  </xs:annotation>

  <xs:element name="Lookup_Value_Set">
    <xs:annotation>
      <xs:appinfo>
        <b:recordInfo structure="delimited" child_delimiter_type="hex" child_delimiter="0x0A" child_order="postfix" sequence_number="1" preserve_delimiter_for_empty_data="true" suppress_trailing_delimiters="false" skip_first_rows="1" skip_last_rows="1"/>
      </xs:appinfo>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:element maxOccurs="unbounded" name="LineRecord">
          <xs:annotation>
            <xs:appinfo>
              <b:recordInfo structure="positional" sequence_number="1" count_positions_by_byte="false"/>
            </xs:appinfo>
          </xs:annotation>
          <xs:complexType>
            <xs:sequence>
              <!-- Area字段:0-8位,长度8 -->
              <xs:element name="Area">
                <xs:annotation>
                  <xs:appinfo>
                    <b:fieldInfo justification="left" pos_length="8" sequence_number="1"/>
                  </xs:appinfo>
                </xs:annotation>
                <xs:simpleType>
                  <xs:restriction base="xs:string">
                    <xs:length value="8"/>
                  </xs:restriction>
                </xs:simpleType>
              </xs:element>
              <!-- Date字段:9-16位,长度8 -->
              <xs:element name="Date">
                <xs:annotation>
                  <xs:appinfo>
                    <b:fieldInfo justification="left" pos_length="8" sequence_number="2"/>
                  </xs:appinfo>
                </xs:annotation>
                <xs:simpleType>
                  <xs:restriction base="xs:string">
                    <xs:length value="8"/>
                  </xs:restriction>
                </xs:simpleType>
              </xs:element>
              <!-- 跳过18-26位,共9位 -->
              <xs:element name="Skip1">
                <xs:annotation>
                  <xs:appinfo>
                    <b:fieldInfo justification="left" pos_length="9" sequence_number="3" suppress_node="true"/>
                  </xs:appinfo>
                </xs:annotation>
                <xs:simpleType>
                  <xs:restriction base="xs:string"/>
                </xs:simpleType>
              </xs:element>
              <!-- 行内记录数字段:27-28位,长度2 -->
              <xs:element name="RecordCount" type="xs:int">
                <xs:annotation>
                  <xs:appinfo>
                    <b:fieldInfo justification="left" pos_length="2" sequence_number="4"/>
                  </xs:appinfo>
                </xs:annotation>
              </xs:element>
              <!-- 跳过29-30位,共2位 -->
              <xs:element name="Skip2">
                <xs:annotation>
                  <xs:appinfo>
                    <b:fieldInfo justification="left" pos_length="2" sequence_number="5" suppress_node="true"/>
                  </xs:appinfo>
                </xs:annotation>
                <xs:simpleType>
                  <xs:restriction base="xs:string"/>
                </xs:simpleType>
              </xs:element>
              <!-- Change组:最多3个,每个占11位(5位值+6位跳过) -->
              <xs:element maxOccurs="3" name="ChangeGroup">
                <xs:annotation>
                  <xs:appinfo>
                    <b:recordInfo structure="positional" sequence_number="6"/>
                  </xs:appinfo>
                </xs:annotation>
                <xs:complexType>
                  <xs:sequence>
                    <xs:element name="Change">
                      <xs:annotation>
                        <xs:appinfo>
                          <b:fieldInfo justification="left" pos_length="5" sequence_number="1"/>
                        </xs:appinfo>
                      </xs:annotation>
                      <xs:simpleType>
                        <xs:restriction base="xs:string">
                          <xs:length value="5"/>
                        </xs:restriction>
                      </xs:simpleType>
                    </xs:element>
                    <xs:element name="SkipChange">
                      <xs:annotation>
                        <xs:appinfo>
                          <b:fieldInfo justification="left" pos_length="6" sequence_number="2" suppress_node="true"/>
                        </xs:appinfo>
                      </xs:annotation>
                      <xs:simpleType>
                        <xs:restriction base="xs:string"/>
                      </xs:simpleType>
                    </xs:element>
                  </xs:sequence>
                </xs:complexType>
              </xs:element>
              <!-- 跳过剩余字符至100位,共42位 -->
              <xs:element name="SkipRest">
                <xs:annotation>
                  <xs:appinfo>
                    <b:fieldInfo justification="left" pos_length="42" sequence_number="7" suppress_node="true"/>
                  </xs:appinfo>
                </xs:annotation>
                <xs:simpleType>
                  <xs:restriction base="xs:string"/>
                </xs:simpleType>
              </xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

  <!-- 内嵌脚本:将单行多Change拆分为独立Record节点 -->
  <xs:annotation>
    <xs:appinfo>
      <msxsl:script language="C#" implements-prefix="user">
        <msxsl:assembly name="System.Xml"/>
        <msxsl:using namespace="System.Xml"/>
        public XmlNodeList SplitRecords(XmlNode lineRecord)
        {
          XmlDocument doc = new XmlDocument();
          XmlElement root = doc.CreateElement("Records");
          string area = lineRecord.SelectSingleNode("Area").InnerText;
          string date = lineRecord.SelectSingleNode("Date").InnerText;
          int count = int.Parse(lineRecord.SelectSingleNode("RecordCount").InnerText);
          XmlNodeList changes = lineRecord.SelectNodes("ChangeGroup/Change");
          
          for(int i=0; i<count; i++)
          {
            XmlElement record = doc.CreateElement("Record");
            // 构造Area节点
            XmlElement areaEl = doc.CreateElement("Area");
            areaEl.InnerText = area;
            // 构造Date节点
            XmlElement dateEl = doc.CreateElement("Date");
            dateEl.InnerText = date;
            // 构造Change节点
            XmlElement changeEl = doc.CreateElement("Change");
            changeEl.InnerText = changes[i].InnerText;
            
            record.AppendChild(areaEl);
            record.AppendChild(dateEl);
            record.AppendChild(changeEl);
            root.AppendChild(record);
          }
          return root.ChildNodes;
        }
      </msxsl:script>
    </xs:appinfo>
  </xs:annotation>

</xs:schema>

关键配置说明

  1. 行分隔符与首尾行控制:在根节点Lookup_Value_Set的recordInfo中,通过child_delimiter="0x0A"指定LF为行分隔符,skip_first_rows="1"和skip_last_rows="1"直接跳过首尾行
  2. 位置字段处理:所有字段通过pos_length定义长度,无需保留的字段设置suppress_node="true",避免生成冗余XML节点
  3. 可变Record生成:内嵌C#脚本读取行内记录数,将每行的多个Change值拆分为独立的Record节点,完全匹配期望输出格式
  4. 固定行长度适配:最后设置SkipRest字段填充剩余字符至100位,确保行分隔符匹配准确,解决解码时的换行符查找错误

调试建议

  • 用十六进制编辑器确认文件行尾确实为0x0A(LF)
  • 验证所有字段长度总和+跳过部分的长度等于100字符
  • 先单独测试中间行数据,排除首尾行干扰后再整体验证

内容的提问来源于stack exchange,提问作者Ananda Prasad Bandaru

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 22:45:33