> ## 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.

# 将 EDI 850 采购订单映射为 CSV

> 使用知行之桥的映射工具将 X12 850 采购订单转换为扁平 CSV 文件。

export const siteNameShort = "知行之桥";

export const siteName = "知行之桥";

## 概述

{siteName} 包含强大的数据转换工具，支持将 EDI 文档（如 X12、EDIFACT 等）映射到扁平文件结构，如逗号分隔值 (CSV) 文件。本指南重点介绍如何将 X12 850 文档（采购订单）映射为 CSV 格式。本文描述的方法同样适用于其他 EDI 文档的映射；但映射值之间的具体关系可能会有所不同。

本指南首先概述 {siteNameShort} 如何处理 EDI 映射，然后逐步讲解工作流的每个步骤。请参阅 [示例文件](#示例文件) 查看本指南中使用的 X12 850 输入和 CSV 输出文档。

### 视频资源

观看此视频，了解 {siteNameShort} 中的数据转换概览。

<iframe width="560" height="315" src="//player.bilibili.com/player.html?aid=870824036&bvid=BV1zV4y1h7Le&cid=1194675351&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" />

## {siteName} 中的 EDI 映射

### 与 XML 之间的相互转换

{siteNameShort} 使用 XML 作为数据转换和操作的中间格式。大多数映射项目的第一步是将源文件格式（本例中为 X12）转换为 XML，最后一步是将 XML 转换为目标格式（本例中为 CSV）。

由于与 XML 之间的转换是数据转换中至关重要的一步，{siteNameShort} 包含了许多专门用于 XML 转换的端口。本指南使用 [X12 端口](/26.2/self-hosted/zh/connectors/x12) 和 [CSV 端口](/26.2/self-hosted/zh/connectors/csv)。这些端口会自动将其文件格式转换为 XML。使用这些端口，源格式（X12 850 采购订单）和目标格式（具有所需列的 CSV 文件）都可以建模为 XML。

### 转换 XML

一旦源格式和目标格式都被建模为 XML，任务就是将一种 XML 结构转换为另一种。这通过 [XML Map 端口](/26.2/self-hosted/zh/connectors/xml-map/xml-map) 来完成。

XML Map 端口需要示例 **源** 和 **目标** 模板文件，分别代表起始和结束的 XML 结构。指定这些文件后，XML Map 端口的可视化设计器将填充这两个 XML 结构。

在 XML Map 端口的可视化设计器中，可以从源结构中拖放元素到目标结构中的元素上，以建立它们之间的映射关系。此映射步骤需要了解源文件数据，以便在输出文件中包含适当的元素。

XML Map 端口包含值格式化器、条件逻辑，甚至支持自定义脚本，以便在映射过程中操作和计算数据。

建立映射关系后，XML Map 端口可以自动将任何匹配源 XML 结构的文件转换为具有目标 XML 结构的文件。在本示例中，这意味着 X12 850 文档的 XML 模型会自动转换为 CSV 文件的 XML 模型。最后一步是使用 CSV 端口获取此 XML 模型并将其转换为实际的 CSV 文件。

### 扁平化采购订单

将 850 采购订单映射到 CSV 时，一个特定的概念挑战是需要 *扁平化* 采购订单。单个 850 文档可以包含多个订单，每个订单可以包含不同数量的行项目。相比之下，CSV 文件具有用于存储数据的静态列数。

由于 CSV 列数无法扩展以适应 850 中变化的订单数量，因此无法将一个 850 映射到 CSV 文件中的单条记录（行）。同样，由于 CSV 列数无法扩展以适应订单中变化的行项目数量，因此无法将一个订单映射到单行 CSV。CSV 中的每一行必须存储订单中单个行项目的数据，因为无论 850 中的行项目和订单数量多少，单个行项目都可以表示为一组静态值。扁平化 850 会将其多层且多变的结构简化为一组静态行项目。

XML Map 端口使用 `Foreach` 循环关系的概念在映射期间扁平化结构。在这种情况下，会 *为每一个* 850 中的行项目创建一个新的 CSV 行。在 XML Map 端口中建立这种关系，只需在可视化设计器中将一个元素（代表行项目的 `PO1` 元素）拖动到另一个元素（代表 CSV 记录的元素）上即可。使用 XML Map 端口扁平化结构很容易，但必须了解源和目标 XML 结构，以便建立适当的 Foreach 关系。

### 摘要

在 {siteNameShort} 中创建映射需要以下步骤：

* 使用特定于输入格式的端口（本例中为 X12 端口）将示例输入文件（如 X12 850 文档）转换为 XML
* 使用特定于输出格式的端口（本例中为 CSV 端口）将示例输出文件（如具有所需列的 CSV 文件）转换为 XML
* 将生成的 XML 文件用作 XML Map 端口的源文件和目标文件
* 在 XML Map 端口的可视化设计器中拖放元素，以建立源和目标 XML 结构之间的关系

结果是一个自动化工作流，它接受 X12 文档作为输入并返回 CSV 文件作为输出。

## 创建映射工作流

本节描述了在 {siteNameShort} 中创建一个工作流，将示例 850 采购订单映射到扁平 CSV 文件所需的步骤。

### 第 1 步：X12 端口

此映射工作流的第一步是将示例源文档（X12 850）转换为 XML。

这由 X12 端口完成，它将 X12 文档转换为 XML，并可以在转换期间选择性地验证 X12 交换头。在 X12 端口之前是一个触发端口（在以下示例中为 AS2），它接收 X12 850 文档并将其直接传递给 X12 端口。用例可能需要不同的触发端口，例如 SFTP。有关可能适合用例的端口类型的详细信息，请参阅 [端口类别](/26.2/self-hosted/zh/connectors/connectors#categories)。

点击导航栏上的 **工作流**，然后将触发端口（本例中为 AS2）和 X12 端口添加到工作区画布（参见 [设计工作流](/26.2/self-hosted/zh/flows/designing-a-flow) 了解说明）。最佳实践是在 **端口 ID** 字段中包含发送 X12 文档的交易伙伴名称（下图中为 Amazon）。连接 AS2 和 X12 端口。

<img src="https://mintcdn.com/qiao/Pa-LScG1ebkabWPi/public/images/edi_csv_1.png?fit=max&auto=format&n=Pa-LScG1ebkabWPi&q=85&s=273c3d08b8346149534f52c04186e9a2" alt="AS2 and X12 connectors on the workspace canvas" width="800" data-path="public/images/edi_csv_1.png" />

#### 配置 X12 端口

在 X12 端口的 [设置页面](/26.2/self-hosted/zh/connectors/x12#settings-tab) 上，将 **转换类型** 设置为 `X12-to-XML`。这使 X12 端口在将 X12 文档转换为 XML 格式时验证 X12 交换头（以确保 X12 文档已发送至预期方并被其接收）。

默认情况下，勾选了 **动态处理伙伴**。这意味着端口会自动从 EDI 交易中识别并跟踪交易伙伴关系。在这种情况下，不需要手动配置伙伴，因为端口会在许可限制内动态管理所有伙伴。端口还会根据配置的设置填充交换和功能组值。本指南使用默认设置。请参阅 [X12 端口设置](/26.2/self-hosted/zh/connectors/x12#connector-configuration) 了解取消勾选该项后需要执行的操作。

<Note>如果 **使用指示符** 设置为 `T-Test Data`，则不执行验证。</Note>

在本指南范围内无需进一步配置，但具体的用例可能需要。请查看 [X12 文档](/26.2/self-hosted/zh/connectors/x12) 了解完整详情。

#### 上传测试文件

导航到 X12 端口的 **交易** 页面，点击 **更多 > 上传测试文件**。

<img src="https://mintcdn.com/qiao/bVtjD3fvHFZBo1vE/public/images/map850-csv_upload_x12_test_file.png?fit=max&auto=format&n=bVtjD3fvHFZBo1vE&q=85&s=77cfd54ef83096e17ef2ebfd3db74fce" alt="Upload Test File option on the X12 connector Transactions tab" width="700" data-path="public/images/map850-csv_upload_x12_test_file.png" />

浏览包含映射所需 X12 段的示例 850 文档。可能需要联系交易伙伴以获取示例 X12 文档。用于编写本指南的 850 文档在 [此处](#x12-850)。

**上传测试文件** 会指示 X12 端口在内部保存上传文档的 XML 模型（而不是将 XML 作为输出文件推送到 **交易** 页面）。此 XML 模型稍后将由 XML Map 端口使用。

### 第 2 步：CSV 端口

下一步是将示例目标文档（具有适当列的 CSV 文件）转换为 XML。这使用 CSV 端口完成，它在 XML 和 CSV 之间转换文件。

在工作流中添加一个 CSV 端口实例。**不要** 将其连接到 X12 端口。另外添加一个终结端口实例（本例中为 [File](/26.2/self-hosted/zh/connectors/file)）。它充当工作流中的最后一个端口。连接 CSV 和 File 端口。

<img src="https://mintcdn.com/qiao/Pa-LScG1ebkabWPi/public/images/edi_csv_2.png?fit=max&auto=format&n=Pa-LScG1ebkabWPi&q=85&s=36d490b4f3b5ed42d092c09f8f3df28b" alt="CSV and File connectors on the workspace canvas" width="800" data-path="public/images/edi_csv_2.png" />

#### 配置 CSV 端口

打开 CSV 端口的 [设置](/26.2/self-hosted/zh/connectors/csv#connector-settings) 页面。此映射工作流所需的唯一 CSV 端口配置属性是 **包含列标题**。如果映射工作流生成的 CSV 文件顶部应有一行列标题名称，请启用此项。

#### 生成或上传示例文件

导航到 CSV 端口的 **示例文件** 页面，然后点击 **添加示例文件**。如果已经有一个包含适当列（以及标题，如果启用了 **包含列标题**）的示例 CSV 文件，请选择 **文件上传** 并浏览文件。或者，选择 **手动创建** 直接在应用程序中创建 CSV 文件。如果选择 **手动创建**，请为示例文件命名。点击 **下一步**。

<img src="https://mintcdn.com/qiao/bVtjD3fvHFZBo1vE/public/images/map850-csv_upload_csv_test_file.png?fit=max&auto=format&n=bVtjD3fvHFZBo1vE&q=85&s=be5940d70da48c2ce9542d24d7b3724c" alt="Add Sample File dialog for the CSV connector" width="600" data-path="public/images/map850-csv_upload_csv_test_file.png" />

如果浏览了现有文件，**查看文件** 页面将填充其内容。如果选择手动创建文件，请在此页面输入示例数据。

<img src="https://mintcdn.com/qiao/Pa-LScG1ebkabWPi/public/images/edi_csv_4.png?fit=max&auto=format&n=Pa-LScG1ebkabWPi&q=85&s=2a1b2a973c83180a96fb7d614ce7e6b4" alt="Sample CSV file contents" width="500" data-path="public/images/edi_csv_4.png" />

点击 **下一步**。**转换和预览** 会显示转换为 XML 的示例数据预览。对示例满意后，点击 **添加**。

用于编写本指南的 CSV 文件在 [此处](#csv)。

上传测试文件后，CSV 端口会保存其 XML 模型。此 XML 模型将在下一步中使用。

### 第 3 步：XML Map 端口

现在 X12 端口和 CSV 端口已经生成了源文档和目标文档的 XML 模型，使用 XML Map 端口将一种 XML 结构转换为另一种。

在工作流中添加一个 XML Map 端口实例，然后将 X12 端口连接到 XML Map 端口，将 XML Map 端口连接到 CSV 端口。

<img src="https://mintcdn.com/qiao/Pa-LScG1ebkabWPi/public/images/edi_csv_3.png?fit=max&auto=format&n=Pa-LScG1ebkabWPi&q=85&s=775dc8bda2e15065952d89de466d0bf3" alt="Full flow with X12, XML Map, and CSV connectors" width="800" data-path="public/images/edi_csv_3.png" />

#### 配置 XML Map 端口

在 XML Map 端口的 **XML 映射** 页面上，端口应预先从 X12 端口测试文件填充 **源**，并从 CSV 端口示例文件填充 **目标**。

<img src="https://mintcdn.com/qiao/bVtjD3fvHFZBo1vE/public/images/map850-csv_visual_designer.png?fit=max&auto=format&n=bVtjD3fvHFZBo1vE&q=85&s=50fa6c33ae7dc6c6075e8d5a35988b35" alt="XML Map connector visual designer" width="800" data-path="public/images/map850-csv_visual_designer.png" />

如果未显示，请验证测试文件是否已正确上传，以及端口是否已在工作流画布中连接。有关如何使用映射编辑器的详细说明，请参阅 [映射](/26.2/self-hosted/zh/mapping/mapping) 文档中的 [配置映射](/26.2/self-hosted/zh/mapping/mapping-config)。

#### 理解 XML 结构

在 XML Map 端口中创建正确的映射关系需要理解源结构和目标结构在 XML 中是如何表示的。

结构中有两种类型的 XML 元素（节点）。*父* 节点和 *叶* 节点定义了 XML 数据的层级结构，其中父节点对相关元素进行分组，叶节点代表要映射的实际数据值。使用父节点旁边的展开和收起按钮可以显示或隐藏其叶节点。有关更多信息，请参阅 [映射节点](/26.2/self-hosted/zh/mapping/mapping-config#mapping-nodes)。

* 在 850 XML 中，每个 EDI *循环* 和 *段* 都是父节点。每个单独的 EDI *元素* 都是叶节点。
* 在 CSV XML 中，根 *Items* 元素的每个直接子元素被称为 *记录* 元素：它代表 CSV 中的一个不同行。每个 *记录* 元素都是父节点，*记录* 元素的子元素都是 *列* 元素：它们各自代表一条记录的一个字段或一列。每个 *列* 元素都是叶节点。

在 XML Map 端口中，父节点只能映射到其他父节点，叶节点只能映射到其他叶节点。将 EDI 映射到 CSV 时的主要挑战是选择正确的 *循环* 或 *段* 元素（来自 EDI 源）拖动到 *记录* 元素（在 CSV 目标中）。然后，可以将 EDI *元素* 节点拖动到 *列* 节点上，以便用 EDI 文档中的特定值填充 CSV。

## 创建映射

在为 XML Map 端口配置了源和目标结构后，通过在设计器中拖放节点来创建映射。

映射主要通过两个步骤创建：

1. 在父节点之间创建 Foreach 循环关系
2. 在已建立的 Foreach 循环中映射叶节点之间的值

有关处理循环的更多详情和其他示例，请参阅 [映射循环](/26.2/self-hosted/zh/mapping/mapping-config#mapping-loops)。

### 创建 Foreach 循环

Foreach 关系意味着每当源中出现一个元素时，就应在目标中创建一个新的 XML 结构。例如，如果源中的 *ElementA* 映射到目标中的 *ElementB*，则输入文件中每次出现 *ElementA* 都会导致输出文件中产生一个 *ElementB* 实例（及其所有子元素）。

在本例中（如 [扁平化采购订单](#扁平化采购订单) 一节所述），源 850 中的每个行项目都应在目标 CSV 中生成一条新记录。要创建此关系，请将代表行项目的 **源** 元素拖动到代表 CSV 记录的 **目标** 元素上。在本例中，源元素是 *TX-00401-850*，目标元素是 *customers*：

<img src="https://mintcdn.com/qiao/bVtjD3fvHFZBo1vE/public/images/map850-csv_line_item_loop.png?fit=max&auto=format&n=bVtjD3fvHFZBo1vE&q=85&s=5d2f5ef981dd9efd0828cec16e59e5da" alt="Creating a Foreach loop in the XML Map connector" width="800" data-path="public/images/map850-csv_line_item_loop.png" />

如上图所示，*customers* 目标元素显示了映射到它的源 xpath。每当 XML 解析器在输入文件中找到与该 xpath 匹配的元素时，就会向输出文件中添加一个新的 *customers* 元素（包括 *customers* 元素的所有子元素，如果有）。

此 Foreach 循环是此映射所需的唯一循环。其他映射项目可能需要多个循环，包括嵌套循环或其他形式。

### 映射叶节点

建立 Foreach 关系后，可以映射循环中叶节点的值。映射叶节点决定了填充由 Foreach 循环创建的 XML 结构的值。

#### 简单叶节点映射

当源中的值应直接插入生成的输出时，只需将叶节点从源拖动到目标中的叶节点即可映射这些值。例如，*BEG03* 元素保存了 *PONumber* 的值，它对应于目标中的 *PONumber* 属性：

<img src="https://mintcdn.com/qiao/bVtjD3fvHFZBo1vE/public/images/map850-csv_first_leaf_mapping.png?fit=max&auto=format&n=bVtjD3fvHFZBo1vE&q=85&s=eb6088c4eba0784797cfce9344cae7c6" alt="Simple leaf node mapping for PONumber" width="800" data-path="public/images/map850-csv_first_leaf_mapping.png" />

<Note>这些元素的 xpath 是相对于 Foreach xpath 的。</Note>

#### 使用 Lookahead 语法的条件映射

850 文档包含多个 *N1Loop1* 元素，代表交换中的参与方及其角色（例如，收货方或付款方）。对于每个 *N1Loop1*，*N1Loop1/N1/N104* 元素保存标识该参与方的值（参与方名称或 ID），因此必须将这些值映射到输出 CSV。然而，无论参与方的角色如何，每个 *N104* 元素的 xpath 都是相同的，因此仅靠指向 *N104* 元素的 xpath 不足以映射正确的值。

参与方的角色保存在 *N1Loop1/N1/N101* 中，因此映射需要在将 *N104* 元素值映射到输出 CSV 之前查看 *N101* 元素。换句话说，*BillToPartyCode* 需要映射到：

`N1Loop1/N1/N104 WHERE N1Loop1/N1/N101 = 'BT'`

这种条件映射可以使用 `Lookahead` 语法完成。

首先，将包含源值的元素拖动到目标元素 (*BillToPartyCode*) 上：

<img src="https://mintcdn.com/qiao/bVtjD3fvHFZBo1vE/public/images/map850-csv_bill_to.png?fit=max&auto=format&n=bVtjD3fvHFZBo1vE&q=85&s=96ed981cd3d749d97afea5fa2463496c" alt="Dragging source element onto BillToPartyCode destination" width="800" data-path="public/images/map850-csv_bill_to.png" />

然后，将鼠标悬停在已映射的 *BillToPartyCode* 元素上，点击平板和铅笔图标以打开 **节点值** 编辑器：

<img src="https://mintcdn.com/qiao/bVtjD3fvHFZBo1vE/public/images/map850-csv_bill_to_expression_editor.png?fit=max&auto=format&n=bVtjD3fvHFZBo1vE&q=85&s=d0c75111d8af52e28170850df55d01a5" alt="Node Value editor for BillToPartyCode" width="800" data-path="public/images/map850-csv_bill_to_expression_editor.png" />

请注意，当前映射的 xpath 是 *N1Loop1/N1/N104*，要查看的 xpath 是 *N1Loop1/N1/N101*。Lookahead 语法的指定如下：

* 在当前 xpath 中找到作为要查看元素的最近父元素的元素（在本例中为 *N1* 元素）
* 在方括号 `[ ]` 中指定要查看元素的 xpath（在本例中为 `[N101]`）
* 添加一个等号表达式 `=` 以指示要检查此元素的值（在本例中为 `BT`）
* 用反斜杠转义方括号，使其不被作为 xpath 表达式的一部分进行评估

生成的 Lookahead 表达式如下所示：

<img src="https://mintcdn.com/qiao/bVtjD3fvHFZBo1vE/public/images/map850-csv_bill_to_lookahead.png?fit=max&auto=format&n=bVtjD3fvHFZBo1vE&q=85&s=0e08b4c4fdaddba74613923295f7cc88" alt="Lookahead expression for BillToPartyCode" width="800" data-path="public/images/map850-csv_bill_to_lookahead.png" />

对其余目标元素重复相同的过程。

#### 使用节点值编辑器进行修改和计算

除了 xpath 操作外，节点值编辑器还支持在映射期间修改或操作值的 [格式化器](/26.2/self-hosted/zh/scripting/value-formatters/formatters)。*ItemTotalCost* 元素需要映射为行项目的总成本，这在源元素中无法直接获得，但可以通过将项目数量乘以项目价格轻松计算得出。

作为起点，将项目价格映射到 *ItemTotalCost* 元素并打开节点值编辑器。

可以使用 *multiply* 格式化器将此起始值（单价）与项目数量相乘。格式化器语法的运作方式如下：

* 序列包含在方括号中（如当前 *ItemTotalCost* 表达式中所示）
* 序列从左到右进行评估
* 序列由竖线字符分隔（例如，`[value | formatter1() | formatter2() | formatter3()]`）

<Note>将源节点拖动到目标节点时生成的 *xpath()* 语法本身就是一种特殊的格式化器。</Note>

在 xpath 表达式右端（闭方括号内）添加一个竖线分隔符，为格式化器创建一个新空间。在此空间中，手动输入 *multiply()* 格式化器，或导航到节点值编辑器中的 **格式化器** 页面，搜索 'multiply'，然后点击相应的格式化器将其添加到表达式中。为了将起始值（项目价格）与项目数量相乘，需要将项目数量值指定为 *multiply* 格式化器的参数。由于此值需要从输入的 850 中获取，因此需要另一个 *xpath* 表达式，其 xpath 对应于项目数量 (*PO1/PO2*)：

<img src="https://mintcdn.com/qiao/bVtjD3fvHFZBo1vE/public/images/map850-csv_total_cost_multiply.png?fit=max&auto=format&n=bVtjD3fvHFZBo1vE&q=85&s=d891334f59ebc4f37ac74fb167345654" alt="Multiply formatter expression for ItemTotalCost" width="700" data-path="public/images/map850-csv_total_cost_multiply.png" />

生成的表达式通过将单价乘以项目数量，正确计算出行项目的总成本。

保存表达式后，映射即告完成。保存对 XML Map 端口的更改，即已配置好完整的工作流。

## 示例文件

本指南使用以下示例数据。

### X12 850

```text theme={null}
ISA*00*          *00*          *ZZ*AMAZONDS       *01*003025392      *160623*1448*U*00401*000000013*0*P*+~
GS*PO*AMAZONDS*ATFDS*20070911*2001*95*X*004010~
ST*850*0003~
BEG*00*DS*TesT0008516**20070805~
CUR*BT*USD~
N1*BT*Amazon.com.kydc,Inc.*92*KYDC~
N1*SF*WHSE*92*WHSE~
N1*ST*Charlie Dinkins~
N3*11254 Main St*Suite 112~
N4*Seattle*WA*98104*US*CC*United States~
TD5**92*UPS_GR_RES****ZZ*RES~
N1*LW*Amber Baker~
N3*123 Anderson Avenue~
N4*Seattle*WA*98103*US~
PO1*1*3*EA*18.04*NT*SK*1617*****BL*1*ZZ*Amazon.com~
PO1*2*2*EA*54.42*NT*SK*4927*****BL*1*ZZ*Amazon.com~
PO1*3*1*EA*18*NT*SK*9876*****BL*1*ZZ*Amazon.com~
CTT*3*6~
SE*15*0003~
GE*1*40~
IEA*1*000000040~
```

### CSV

```csv theme={null}
CustomerId,PONumber,PODate,BillToPartyCode,ShipFromCode,ShipToAddress,ShipToCity,ShipToZIP,LineItemNumber,ItemID,ItemQuantity,ItemPrice,ItemTotalCost
Sir Charles,128F195,20190805,AbRes,W22,2408 Creek St,Springfield,52213,1,BouncyRubberBall,4,2.49,9.96
Lady Jane,128F196,20190805,AbRes,W22,2408 Creek St,Springfield,52213,2,SquishyNerfBall,2,4.29,8.58
```
