> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kasoftware.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Flat File 端口

> Flat File 端口可实现平面文件和 XML 文件的互相转换，支持位置分隔和字符分隔格式。

export const SlasTab = ({siteName = "知行之桥"}) => <>
    <p><em>与配置服务级别协议 (SLA) 相关的设置。</em></p>
    <p>
      SLA 允许配置预期流程中端口发送或接收的数据量，并设置预期达到该数据量的时间范围。当 SLA 未达到时，{siteName} 会发送电子邮件警告用户，并将 SLA 标记为 <em>存在风险</em>，这意味着如果 SLA 未能尽快达到，则会被标记为 <em>已违反</em>。这让用户有机会介入并确定 SLA 未达到的原因，并采取适当的措施。如果在风险时间段结束时仍未达到 SLA，则会将 SLA 标记为已违反，并再次通知用户。
    </p>
    <p>
      要定义 SLA，请启用 <strong>预期数据量</strong>，然后点击 <strong>设置</strong> 选项卡。
    </p>
    <img src="/public/images/sla_empty.png" alt="SLA Empty" />
    <ul>
      <li>如果端口具有单独的发送和接收操作，请使用单选按钮指定 SLA 适用的方向。</li>
      <li>在窗口的 <strong>预计至少</strong> 部分中：
        <ul>
          <li>设置预计处理的最小事务数量（交易量）</li>
          <li>使用 <strong>每个</strong> 字段指定时间范围</li>
          <li>指示 SLA 生效的时间。如果选择 <strong>开始于</strong>，请填写日期和时间字段。</li>
          <li>勾选希望 SLA 生效的星期几对应的复选框。如有必要，请使用下拉菜单选择 <strong>每天</strong>。</li>
        </ul>
      </li>
      <li>在窗口的 <strong>将状态设置为“有风险”</strong> 部分中，指定应将 SLA 标记为有风险的时间。
        <ul>
          <li>默认情况下，只有在违反 SLA 的情况下才会发送通知。要更改此设置，请勾选 <strong>发送“有风险”通知</strong>。</li>
        </ul>
      </li>
    </ul>
    <p>
      以下示例显示了为端口配置的 SLA，该端口预计在周一至周五每天接收 1000 个文件。如果尚未收到 1000 个文件，则会在时间段结束前 1 小时发送风险通知。
    </p>
    <img src="/public/images/sla_defined.png" alt="SLA Configuration Example" />
    <Note>
      如果有必要，可以关闭 SLA 通知。这在维护窗口期间非常有用。点击导航栏上的 <strong>设置</strong>，然后跳转到 <strong>通知 &gt; 通用通知</strong>。点击平板和铅笔图标进行编辑，并取消勾选 <strong>SLA 通知</strong> 设置。
    </Note>
  </>;

export const AlertsTab = ({siteNameShort = "知行之桥"}) => <>
    <p><em>与配置通知相关的设置。</em></p>
    <p>
      在执行服务级别协议 (SLA) 之前，需要设置电子邮件通知以接收通知。默认情况下，{siteNameShort} 使用 <a href="/26.2/self-hosted/zh/getting-started/administration/settings/alerts">通知</a> 选项卡上的全局设置。要为此端口使用其他设置，请启用 <strong>覆盖全局设置</strong>。
    </p>
    <p>
      默认情况下，错误通知处于启用状态，这意味着每当出现错误时都会发送电子邮件。要关闭错误通知，请取消选中 <strong>启用</strong> 复选框。
    </p>
    <p>
      输入 <strong>主题</strong>（必填），然后（可选）输入以逗号分隔的 <strong>收件人</strong> 电子邮件列表。
    </p>
  </>;

export const Message = () => <>
    <p><em>消息设置确定端口如何搜索消息并在处理后管理它们。</em></p>
    <table>
      <thead>
        <tr><th>设置</th><th>描述</th></tr>
      </thead>
      <tbody>
        
          <tr>
            <td><strong>保存到已发送文件夹</strong></td>
            <td>选中此项可将端口处理的文件复制到该端口的“已发送”文件夹中。</td>
          </tr>
        
        <tr>
          <td><strong>已发送文件夹方案</strong></td>
          <td>端口根据选定的时间间隔对 <strong>已发送</strong> 文件夹中的文件进行分组。例如，<strong>Weekly</strong> 选项指示端口每周创建一个新的子文件夹，并将本周发送的所有文件存储在该文件夹中。空白设置告诉端口将所有文件直接保存在 <strong>已发送</strong> 文件夹中。对于处理许多事务的端口，使用子文件夹可以帮助保持文件有序并提高性能。</td>
        </tr>
      </tbody>
    </table>
  </>;

export const MiscConnector = () => <>
    <p><em>特殊设置适用于特定用例。</em></p>
    <table>
      <thead>
        <tr>
          <th>设置</th>
          <th>描述</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><strong>其他设置</strong></td>
          <td>允许在以分号分隔的列表中配置隐藏的端口设置，例如 <code>setting1=value1;setting2=value2</code>。正常的端口用例和功能不需要使用这些设置。</td>
        </tr>
      </tbody>
    </table>
  </>;

export const Logging = () => <>
    <p><em>用于管理日志创建和存储的设置。</em></p>
    <table>
      <thead>
        <tr>
          <th>设置</th>
          <th>描述</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><strong>日志级别</strong></td>
          <td>指定要记录在端口日志目录中的信息类型：
            <ul>
              <li><b>None</b> - 不创建任何日志。</li>
              <li><b>Error</b> - 仅当端口遇到错误时才创建日志。</li>
              <li><b>Warning</b> - 仅当端口发出警告时才创建日志。</li>
              <li><b>Info</b> - 记录工作流的一般信息，包括任何错误和警告（如果适用）。</li>
              <li><b>Debug</b> - 记录成功和失败工作流的详细调试信息。</li>
              <li><b>Trace</b> - 记录成功和失败工作流的详细跟踪信息。</li>
            </ul>
            <strong>请注意：</strong><strong>Debug</strong> 和 <strong>Trace</strong> 级别的日志可能会记录敏感信息，包括消息内容和 SSL 证书。尽管连接属性（例如密码）被屏蔽了，但在与您的组织外部共享它们之前，请查看此级别的日志以避免泄漏敏感信息。</td>
        </tr>
        <tr>
          <td><strong>日志文件夹结构</strong></td>
          <td>指示端口根据选定的时间间隔将日志文件夹中的文件分组。例如，<strong>Weekly</strong> 选项指示端口每周创建一个新的子文件夹，并将该周的所有日志存储在该文件夹中。空白设置告诉端口将所有日志直接保存在日志文件夹中。对于处理许多事务的端口，使用子文件夹有助于保持日志的有序性并提高性能。</td>
        </tr>
        <tr>
          <td><strong>保留消息副本</strong></td>
          <td>指示端口在日志目录中保存最新消息副本的切换。请注意，端口每个子文件夹只保留一个消息，并且端口在再次运行时会覆盖以前保存的消息。</td>
        </tr>
      </tbody>
    </table>
  </>;

export const MacrosExamples = ({extraMacros = []}) => <>
    <p>
      某些宏（例如 %Ext% 和 %ShortDate%）不需要参数，但其他宏则需要。所有带有参数的宏都使用以下语法：<code>%Macro:argument%</code>
    </p>

    <p>以下是带有参数的宏的一些示例：</p>

    <ul>
      <li>%Header:headername%：其中 <code>headername</code> 是消息上消息头的名称。</li>
      <li>%Header:mycustomheader% 解析为输入消息上设置的 <code>mycustomheader</code> 消息头的值。</li>
      <li>%Header:ponum% 解析为输入消息上设置的 <code>ponum</code> 消息头的值。</li>
      <li>%RegexFilename:pattern%：其中 <code>pattern</code> 是正则表达式模式。例如，<code>%RegexFilename:^([\w][A-Za-z]+)%</code> 匹配并解析为文件名中的第一个单词，并且不区分大小写（<code>test_file.xml</code> 解析为 <code>test</code>）。</li>
      <li>%Vault:vaultitem%：其中 <code>vaultitem</code> 是 <a href="/26.2/self-hosted/zh/getting-started/administration/settings/global-settings-vault">vault</a> 中项目的名称。例如，<code>%Vault:companyname%</code> 解析为存储在保管库中的 <code>companyname</code> 项的值。</li>
      <li>%DateFormat:format%：其中 <code>format</code> 是可接受的日期格式（有关详细信息，请参阅 <a href="/26.2/self-hosted/zh/scripting/value-formatters/date-formatters#sample-date-formats">示例日期格式</a>）。例如，<code>%DateFormat:yyyy-MM-dd-HH-mm-ss-fff%</code> 解析为文件上的日期和时间戳。</li>
      {extraMacros.filter(item => item.example).map(item => <li key={`ex-${item.name}`}>{item.example}</li>)}
    </ul>

    <p>还可以创建更复杂的宏，如以下示例所示：</p>

    <ul>
      <li>将多个宏组合在一个文件名中：<code>%DateFormat:yyyy-MM-dd-HH-mm-ss-fff%%EXT%</code></li>
      <li>包括宏之外的文本：<code>MyFile_%DateFormat:yyyy-MM-dd-HH-mm-ss-fff%</code></li>
      <li>在宏中包含文本：<code>%DateFormat:'DateProcessed-'yyyy-MM-dd_'TimeProcessed-'HH-mm-ss%</code></li>
    </ul>
  </>;

export const MacrosTable = ({siteName = "知行之桥", extraMacros = []}) => <>
    <p>
      在文件命名策略中使用宏可以提高组织效率和对数据的上下文理解。通过将宏合并到文件名中，可以动态地包含相关信息，例如标识符、时间戳和消息头信息，从而为每个文件提供有价值的上下文。这有助于确保文件名反映对组织重要的详细信息。
    </p>

    <p>{siteName} 支持这些宏，它们都使用以下语法：<code>%Macro%</code>。</p>

    <table>
      <thead>
        <tr><th>宏</th><th>描述</th></tr>
      </thead>
      <tbody>
        <tr><td>ConnectorID</td><td>替换为端口的 ConnectorID。</td></tr>
        <tr><td>Ext</td><td>替换为端口当前正在处理的文件的文件扩展名。</td></tr>
        <tr><td>Filename</td><td>替换为端口当前正在处理的文件的文件名（包括扩展名）。</td></tr>
        <tr><td>FilenameNoExt</td><td>替换为端口当前正在处理的文件的文件名（不带扩展名）。</td></tr>
        <tr><td>MessageId</td><td>计算端口输出的消息的 MessageId。</td></tr>
        <tr><td>RegexFilename:<em>pattern</em></td><td>将正则表达式模式应用于端口当前正在处理的文件的文件名。</td></tr>
        <tr><td>Header:<em>headername</em></td><td>替换为端口正在处理的当前消息的目标消息头（<code>headername</code>）的值。</td></tr>
        <tr><td>LongDate</td><td>以常规格式计算系统的当前日期时间（例如，2024 年 1 月 24 日星期三）。</td></tr>
        <tr><td>ShortDate</td><td>以 yyyy-MM-dd 格式计算系统的当前日期时间（例如 2024-01-24）。</td></tr>
        <tr><td>DateFormat:<em>format</em></td><td>以指定格式（<code>format</code>）计算系统的当前日期时间。有关可用的日期时间格式，请参阅 <a href="/26.2/self-hosted/zh/scripting/value-formatters/date-formatters#date-formats-with-literal-characters">示例日期格式</a>。</td></tr>
        <tr><td>Vault:<em>vaultitem</em></td><td>计算指定保管库项目的值。</td></tr>
        {extraMacros.map(item => <tr key={item.name}>
            <td>{item.name}</td>
            <td>{item.description}</td>
          </tr>)}
      </tbody>
    </table>
  </>;

export const Performance = () => <>
    <p><em>与端口资源分配相关的设置。</em></p>
    <table>
      <thead>
        <tr>
          <th>设置</th>
          <th>描述</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><strong>最大工作线程数</strong></td>
          <td>此端口上处理文件时从线程池中消耗的最大工作线程数。如果设置，则会覆盖 <a href="/26.2/self-hosted/zh/getting-started/administration/settings/advanced-settings">高级设置</a> 页面的 <a href="/26.2/self-hosted/zh/getting-started/administration/settings/performance-settings">性能设置</a> 部分的默认设置。</td>
        </tr>
        <tr>
          <td><strong>最大文件数</strong></td>
          <td>分配给端口的每个线程发送的最大文件数。如果设置，则会覆盖 <a href="/26.2/self-hosted/zh/getting-started/administration/settings/advanced-settings">高级设置</a> 页面的 <a href="/26.2/self-hosted/zh/getting-started/administration/settings/performance-settings">性能设置</a> 部分的默认设置。</td>
        </tr>
      </tbody>
    </table>
  </>;

export const siteNameShort = "知行之桥";

export const siteName = "知行之桥";

Flat File 端口可以实现平面文件和 XML 文件的互相转换。

## 核心功能

* 为定长（位置分隔）和字符分隔格式提供双向平面文件/XML 解析
* 支持多种行类型，具备控制字段识别功能
* 自动层级检测，并为"主-详"（Master-Detail）关系提供 XML 嵌套支持
* 提供完善的字段映射，具备自定义数据类型处理功能

## 概述

每个 Flat File 端口配置一个特定的平面文件格式，从而实现与 XML 格式的互相转换。Flat File 端口有两个主要的模式：

* Position Delimited，端口配置有任意的字段名称、索引（即位置）和长度，表明数据在平面文件中每一行出现的位置。

* Character Delimited，端口配置有分隔平面文件中字段值的字符。

更多详情请查阅[定义平面文件格式](#定义平面文件格式)部分。

<Note>如果还需要一个数字控制字段，请按照[非标准 XML 控制字段](#非标准-xml-控制字段)中的说明进行设置。</Note>

Flat File 端口支持定义多种平面文件中不同类型的行。例如，平面文件中可能有一个 "header" 行，代表订单的日期，有多个 "item" 行，代表订单中的行项目。

定义多种行类型的关键是指定**控制字段**；控制字段值决定了在平面文件中特定的行类型（例如，header 行可能有一个控制字段值为 "HEAD"，item 行可能有一个控制字段值为 "ITEM"）。更多配置多种行类型的详情请查阅[多种行类型](#多种行类型)部分。

平面文件格式配置完后，端口会转换与此格式匹配的文件到 XML。最终的 XML 结构在 [XML 格式](#xml-格式)部分有详细解释。Flat File 端口也可以将匹配这种结构的 XML 转换为定义的平面文件格式。

某些平面文件在不同行有隐含的上下级关系。关于更多在转换平面文件为 XML 时而保留上下级关系的详情，请查阅[多行层级关系](#多行层级关系)部分。

## 端口配置

### 文件详情选项卡

| 设置        | 描述                                                                                                  |
| --------- | --------------------------------------------------------------------------------------------------- |
| **端口 ID** | 端口的静态唯一标识符。                                                                                         |
| **端口类型**  | 显示端口名称及其功能描述。                                                                                       |
| **端口描述**  | 一个可选字段，用于对端口及其在工作流中的角色进行自由说明。                                                                       |
| **文件类型**  | **Position Delimited** — 平面文件中的字段显示在每一行的特定位置。**Character Delimited** — 平面文件中的字段由**分隔符**字段定义的特定字符分隔。 |
| **分隔符**   | 如果**文件类型**设置为 **Character Delimited**，则指定平面文件中分隔各个字段的字符。                                            |

#### 控制字段：位置分隔

*和控制字段有关的设置，决定了在平面文件格式中定义的不同的行类型。*

| 设置         | 描述                                                                                                |
| ---------- | ------------------------------------------------------------------------------------------------- |
| **多行模式**   | 平面文件是否包括多种行类型。更多信息请查阅[多种行类型](#多种行类型)部分。                                                           |
| **起始索引**   | 如果**多行模式**启用，该值就是行中**控制字段**开始的索引。例如，如果某一行中的第一个字段是控制字段，那么起始索引就是 0。                                 |
| **控制字段长度** | （可选）如果**多行模式**启用，这个值定义了从**起始索引**开始读取**控制字段**的长度。                                                  |
| **当前列标题**  | 如果不启用**多行模式**，这个设置决定了平面文件中的第一行是否应该被解析为列标题（即每个字段的名称而不是实际的数据）。启用此设置，就会使端口在将文件从 XML 转换为平面文件时生成一个标题行。 |

#### 控制字段：字符分隔

*和控制字段有关的设置，决定了在平面文件格式中定义的不同的行类型。*

| 设置              | 描述                                                                                                |
| --------------- | ------------------------------------------------------------------------------------------------- |
| **多行模式**        | 平面文件是否包括多种行类型。更多信息请查阅[多种行类型](#多种行类型)部分。                                                           |
| **字段索引**        | 如果**多行模式**启用，该值就是行中（索引从 0 开始）**控制字段**的索引。例如，如果某一行中的第二个字段定义了行的类型（即第二个字段是控制字段），那么字段索引就是 1。          |
| **生成字段／行类型名称**  | 如果**多行模式**启用，那么该设置提供了一个选项，在平面文件中 *不* 指定字段和行的名称和索引。当启用这个设置，端口将会自动为下面**行类型**中没有明确定义的字段和行生成 XML 元素。  |
| **当前列标题**       | 如果不启用**多行模式**，这个设置决定了平面文件中的第一行是否应该被解析为列标题（即每个字段的名称而不是实际的数据）。启用此设置，就会使端口在将文件从 XML 转换为平面文件时生成一个标题行。 |
| **使用自动生成的字段名称** | 如果**多行模式**没有启用，这个设置决定了端口是否生成通用字段名称。不启用该选项，在**行类型**部分手动指定字段名称。                                     |

#### 行类型

该部分允许以平面文件格式定义字段名和位置。更多定义平面格式的详情请查阅[定义平面文件格式](#定义平面文件格式)部分。

如果**文件类型**是 *Position Delimited* 且**多行模式**启用，使用**添加行类型**按钮定义。每个行类型有一个**控制字段值**，来标识行类型。例如，header 行可能有值为 *HEAD* 的控制字段值，item 行可能有值为 *ITEM* 的控制字段值。

如果**文件类型**设置为 *Character Delimited*，**多行模式**启用，**生成字段／行类型名称**启用，那么为平面文件中存在的所有字段和行类型提供名称和索引就不是必需的。在这种情况下，端口将会为任何未定义的字段或行类型自动生成 XML 元素。取消**生成字段／行类型名称**以手动指定字段名称。

### 设置选项卡

#### 配置

*与端口核心配置相关的设置。*

| 设置             | 描述                                                                                                                     |
| -------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **端口 ID**      | 端口的静态唯一标识符。                                                                                                            |
| **端口类型**       | 显示端口名称及其功能描述。                                                                                                          |
| **端口描述**       | 一个可选字段，用于对端口及其在工作流中的角色进行自由说明。                                                                                          |
| **填充字符**       | 当创建平面文件但字段值不能填满整个字段长度时，这个字段会被用来填满剩余部分。                                                                                 |
| **无效的XML名称前缀** | 某些字段名对于 XML 元素时无效的（例如，以数字开头的字段像 "123ABC"），所以在从平面文件生成 XML 时必须设置一个前缀。同样的，当从 XML 转换平面文件时，端口会查找该前缀并去除它。                    |
| **行分隔符**       | 指定端口在写入文件时用于行结束的控制字符。选项为 **LF**（默认）和 **CRLF**。                                                                         |
| **嵌套行类型**      | 该设置仅在从平面文件转换到 XML 文件时，且在平面文件中有多种行类型时才相关。如果**多行模式**启用，端口将会根据平面文件的控制字段行增加层级关系到最终的 XML。更多关于该自动层级关系请查阅[多行层级关系](#多行层级关系)部分。 |
| **行尾填充**       | 默认设置下，端口会在遇到异常的行尾时抛出错误。当启用时，该设置告知端口填充行而不是抛出错误。                                                                         |
| **始终使用单元格分割符** | 如果**文件类型**设置为 *Character Delimited*，打开此设置以使端口始终使用单元格分隔符（`"`）包装所有值，关闭此设置后端口仅会包装含有分隔符的值。                                 |
| **本地文件命名规则**   | 用于为端口输出消息分配文件名的规则。可以在文件名中使用宏动态包含标识符和时间戳等信息。更多信息，请参见[宏](#宏)。                                                            |

### 高级页面

#### 消息

<Message />

#### 日志

<Logging />

#### 其他设置

| 设置       | 描述                                                                                                                                     |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| **处理延迟** | **事务**选项卡中文件处理延迟的时间（秒）。这是一个旧版设置。最佳做法是[使用 File 端口](../flows/designing-a-flow#interacting-with-the-local-file-system)来管理本地文件系统，而不是使用此设置。 |

#### 其他设置

<MiscConnector />

### 自动化页面

| 设置     | 描述               |
| ------ | ---------------- |
| **发送** | 到达端口的文件是否自动进行处理。 |

#### 性能

<Performance />

### 告警选项卡

<AlertsTab />

### SLA 选项卡

<SlasTab />

## 定义平面文件格式

配置 Flat File 端口的第一步就是定义平面文件的格式。本部分介绍具有单行类型的格式，换句话说，平面文件中的每一行都具有相同的字段集。对于有多个不同行类型的平面文件，请查阅[多种行类型](#多种行类型)部分。

### Character Delimited 的单行格式

对于 *Character Delimited* 的平面文件，定义格式很简单：通过**分隔符**属性指定平面文件中分隔不同字段的字符。

**当前列标题**字段说明了平面文件中的第一行是否是标题行；换句话说，它包含了字段名称而不是实际数据。如果这些列标题存在，端口将会使用这些标题名称作为最终转换成的 XML 中的 XML 元素名。同样的，端口也会使用 XML 元素名称在从 XML 转换为平面文件时生成一个标题行。

如果列标题不存在，端口支持通过在**行类型**中添加字段，手动指定每一个字段的名称。这些字段名称按照索引顺序应用，意味着**行类型**中的第一个条目将会是平面文件行中第一个字段的名称，以此类推。

端口也可以通过启用**使用自动生成的字段名称**来自动生成通用的字段名称。

### Position Delimited 的单行格式

对于 *Position Delimited* 的平面文件，定义格式需要指定在格式中每个字段的位置。端口设置中**行类型**部分为平面文件中存在的行增加任意数量的字段。每个字段必须使用名称和其在平面文件中出现的位置进行标识。

**当前列标题**字段表明了平面文件中的第一行是否为标题行；换句话说，它包括了字段名称而不是实际数据。字段名称仍然需要在**行类型**部分中配置，且这个设置简单地保证了标题行不被识别为实际数据。

### 非标准 XML 控制字段

平面文件数据可能包含完全数字或以数字开头的控制字段的行。虽然这在平面文件数据中很正常，但在将该平面文件数据转换为 XML 时却带来了挑战，因为 XML 元素不能以数字开头。它们必须以字母或下划线开头。为了在平面文件端口中适应这种情况，如果控制字段以数字开头，{siteNameShort} 会自动在输出 XML 中的该值前面添加两个下划线 (\_\_)。此外，还会向该元素添加一个 `lineType` 属性，其值对应于原始控制字段值。例如，以下平面文件数据包括两种线型，控制字段分别为 `000` 和 `111`：

```
000 12345     01222025 NC Yes
000 02468     01242025 MD Yes
111 82390     01202025 FL No
111 67524     01132025 CO No
```

此数据的平面文件配置如下所示：

<img src="https://mintcdn.com/qiao/bVtjD3fvHFZBo1vE/public/images/flat_file_control_fields.png?fit=max&auto=format&n=bVtjD3fvHFZBo1vE&q=85&s=11943629560f57dd7426bf8ce3ffe286" width="600" data-path="public/images/flat_file_control_fields.png" />

当使用此配置通过端口运行此平面文件数据时，输出如下所示：

```xml theme={null}
<Items>
	<__000 lineType="000">
		<ID>12345</ID>
		<Date>01222025</Date>
		<State>NC</State>
		<Paid>Yes</Paid>
	</__000>
	<__000 lineType="000">
		<ID>02468</ID>
		<Date>01242025</Date>
		<State>MD</State>
		<Paid>Yes</Paid>
	</__000>
	<__111 lineType="111">
		<ID>82390</ID>
		<Date>01202025</Date>
		<State>FL</State>
		<Paid>No</Paid>
	</__111>
	<__111 lineType="111">
		<ID>67524</ID>
		<Date>01132025</Date>
		<State>CO</State>
		<Paid>No</Paid>
	</__111>
</Items>
```

请注意，每种线型都带有两个下划线前缀，并且 XML 元素具有与原始控制字段值相对应的 `lineType` 属性。这允许平面文件数据和 XML 完全双向，这意味着当输出 XML 作为输入传递到平面文件端口时，输出是包含正确线型定义且不带任何下划线的平面文件数据。

这也意味着，如果要从 XML 转到平面文件，并且需要以数字开头（或全部为数字）的线型控制字段，则需要在文档到达平面文件端口之前，在文档映射中的相应 XML 元素上实现 `lineType` XML 属性。

## 多种行类型

如果平面文件格式包括了多种行类型，**多行模式**属性应该被启用。平面文件中标识行类型的字段被称为**控制字段**。

### Character Delimited 的多种行类型

当**文件类型**为 *Character Delimited*，**字段索引**设置决定了**控制字段**出现在平面文件中每一行的位置。该索引从 0 开始，意味着如果**控制字段**是行中的第 5 个值，那么**字段索引**就应该是 4。

对于可能出现在**控制字段**的每个值，在端口设置**行类型**单击**添加行类型**按钮。标识行类型的值应该在该行的**控制字段值**中设置。

一旦每个可能的行类型通过特定的**控制字段值**被添加和标识，在每行中将出现的字段应根据索引顺序指定。

如果**生成字段／行类型名称**启用，为在平面文件中存在的所有字段或行类型（只有**控制字段**必需）提供名称和索引是不必要的。在这种情况下，端口将会为任何未定义的字段或行类型自动生成 XML 元素。

### Position Delimited 的多种行类型

当**文件类型**是 *Position Delimited*，**起始索引**设置决定了**控制字段**在平面文件中每一行出现（开始）的位置。这个索引从 0 开始，意味着如果**控制字段**从行中第 15 个字符开始，那么**起始索引**就应该是 14。

对于可能出现在**控制字段**的每个值，在端口设置**行类型**单击**添加行类型**按钮。标识行类型的值应该在该行的**控制字段值**中设置。

一旦每个可能的行类型通过特定的**控制字段值**被添加和标识，在每行中将出现的字段应根据所处（开始）的位置指定。

### 多行示例

例如，某个平面文件包括两种类型的行，一个 shipment 行和一个 package 行。shipment 行包括发货的日期、时间和地址信息，package 行类型包括了发货的项目信息。每一行的第一个字段是 "SHIP" 或 "PCKG" 来表明该行是什么类型。

针对这种情况，**多行**模式应该被启用，且**字段索引**（或**起始索引**）应设置为 0，表明**控制字段**是该行中的第一个字段。然后，在**行类型**部分应该配置有两种行类型；一种**控制字段值**为 "SHIP"，包括 shipment 行的每个字段（例如发货日期，交付日期，收货地址等），一种**控制字段值**为 "PCKG"，包括 package 行的每个字段（例如项目名称，项目重量等）。

## XML 格式

在平面文件转换为 XML 文件之后，结果应有如下的 XML 结构：

* 位于文件根部的 *Items* 元素
* 平面文件中的每一行有一个与该行**控制字段值**相同的元素（如果未定义**控制字段值**，则是"行"）
* 行中的每个字段是**控制字段值**元素的子元素

例如，如果平面文件有 "SHIP" 和 "PCKG" 行，那么输出的 XML 会和此格式相似：

```xml theme={null}
<Items>
  <SHIP>
    <ShipmentId>12B992</ShipmentId>
    <Date>20200228</Date>
    <ShipTo>14 Wallaby Way</ShipTo>
  </SHIP>
  <PCKG>
    <ShipmentId>12B992</ShipmentId>
    <ItemName>Goggles</ItemName>
    <ItemWeight>3.98</ItemWeight>
  </PCKG>
  <PCKG>
    <ShipmentId>12B992</ShipmentId>
    <ItemName>Fins</ItemName>
    <ItemWeight>1.07</ItemWeight>
  </PCKG>
</Items>
```

转换 XML 文件为平面文件，输入的 XML 必须与上面的结构匹配（包括字段名称必须与端口配置中定义的字段匹配的限制）。

当转换 XML 为平面文件时，端口将在最终的平面文件中为每个 *row* 元素创建一个新行。对于 *row* 元素的每个子元素，端口将会将其与端口配置中**字段名称**匹配，并将该元素放到合适的**字段索引**。

## 多行层级关系

有多种行类型的平面文件通常在行类型中有隐含的层级结构。例如，一行包括订单的信息（例如客户名称，订单日期等），下面几行代表订单中的每个订单行（例如项目名称，项目数量等）。行项目"属于"订单，构成层级关系。

这些关系有时称为"主-明细"关系；意味着第一个行类型（订单）是主，下面几行（行项目）是关于主行的"明细"信息。在 XML 中，这通常表现为"父子"关系。

Flat File 端口在转换平面文件为 XML 时可以保留这些层级关系。如果在[高级页面](#高级页面)启用了**嵌套行类型**设置，端口将自动缩进"明细"行，使它们成为"主"行类型的子元素。

以下是将**嵌套行类型**设为 true，转换一个有层级关系的平面文件的示例。在示例之后的部分将解释端口决定层级关系使用的逻辑。

### 多行层级关系示例

以输入以下平面文件为例：

```
M,CustomerA,05022020,true
D,itemA,4,2.09
D,itemB,9,15.23
M,CustomerB,05032020,false
D,itemC,1,5.99
D,itemE,1,3.99
```

平面文件中有两个行类型，`M` 和 `D`：

* `M`，或者说是主，包括一个订单的信息：客户名称，订单日期，以及一个"重要客户"的标识
* `D`，或者说明细，包括了之前订单的订单行信息：项目名称，项目数量，项目价格

因为 `D` 行类型"属于" `M` 行类型，两者为层级关系，那么在转换平面文件为 XML 时，需要将层级关系保留下来。要查看其格式，请在转换上文平面文件为 XML 时，启用**嵌套行类型**，采取以下示例输出：

```xml theme={null}
<Items>
  <M>
    <CustomerName>CustomerA</CustomerName>
    <OrderDate>05022020</OrderDate>
    <HighValueCustomer>true</HighValueCustomer>
    <D>
      <ItemName>itemA</ItemName>
      <ItemQuantity>4</ItemQuantity>
      <ItemPrice>2.09</ItemPrice>
    </D>
    <D>
      <ItemName>itemB</ItemName>
      <ItemQuantity>9</ItemQuantity>
      <ItemPrice>15.23</ItemPrice>
    </D>
  </M>
  <M>
    <CustomerName>CustomerB</CustomerName>
    <OrderDate>05032020</OrderDate>
    <HighValueCustomer>false</HighValueCustomer>
    <D>
      <ItemName>itemC</ItemName>
      <ItemQuantity>1</ItemQuantity>
      <ItemPrice>5.99</ItemPrice>
    </D>
    <D>
      <ItemName>itemE</ItemName>
      <ItemQuantity>1</ItemQuantity>
      <ItemPrice>3.99</ItemPrice>
    </D>
  </M>
</Items>
```

可以看到 `D` 记录为 `M` 记录的子元素，准确反映了源数据中存在的层级结构。

### 多行层级关系逻辑

Flat File 端口使用源平面文件中行的顺序决定行项目之间的层级关系。当**嵌套行类型**启用，端口将遵循以下逻辑：

* 端口遇到的第一个行类型通常被当作层级结构的最上级（即不会在生成的 XML 中缩进）
* 在第一个行类型之后，当端口遇到一个新的行，它假设这个行类型是前一个行类型的下的层级（即它归属于前一个行且在 XML 中缩进）
* 当端口遇到一个之前遇到过的行类型，将返回到该行类型的层级，并关闭所有等于或低于此等级的 XML 元素。

因此，源平面文件必须根据所需的层级结构按行排列。

## 宏

<MacrosTable />

### 示例

<MacrosExamples />
