1. 现状与局限性
集成 Mendix 应用程序与外界沟通时,可以导入 XML 文档并创建 Mendix 基于文档中包含的信息,XML 对象被识别。为此,需要两件事。首先,XML 架构文档(XSD 文件)描述了 XML 数据允许的样子,以便能够识别其中描述的对象。其次,将这些 XML 对象转换为 Mendix 需要对象。 Mendix 平台在 XML 到域映射文档中描述了这种转换,该文档是本文的主题。在此文档中,用户需要配置:
- 什么是 Mendix 需要创建对象
- 这些对象需要如何相互关联
- 这些实体的属性需要如何填充
最后,为了帮助用户构建此文档,有一个功能可以创建 Mendix 根据 XML 模式中定义的元素自动创建实体。
上述情况在实施过程中的主要限制已在 5.14 版中得到解决,并在本文中进行了讨论。这些限制包括:
- 选择的替代方案被视为引用该选择的实体的单独关联
- 选择元素的多重性丢失(所有不同的选择选项的多重性均为 1,即使 XML Schema 定义了一个列表)
- 选择元素未在映射中明确显示,因此不透明。
- 当自动生成映射实体时,现有实体不会被重复使用。
在本文的其余部分,我们将解释如何解决上述问题。因此,本文针对的是 Mendix 开发人员通常使用 XML 到域映射,而人们尤其使用带有 choice 元素的 XML 模式文档。首先,我们在第 2 节中引入一个带有 choice 元素的 XML 模式的明确示例来说明新功能。随后,在第 3 节中,我们通过在 Mendix 5.14 版之前的平台。然后,在第 4 节中,我们使用相同的示例来说明如何在 5.14 版中解决此问题。最后,在第 5 节中,我们通过在微流中利用新的 XML 到域映射中更丰富的类型信息来进一步说明更改的价值。
2. 我们的例子:人
我们考虑以下 XML 模式:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="https://www.w3.org/2001/XMLSchema" >
<xs:complexType name="employee">
<xs:sequence>
<xs:element name="firstname" type="xs:string"/>
<xs:element name="lastname" type="xs:string"/>
<xs:element name="salary" type="xs:int"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="customer">
<xs:sequence>
<xs:element name="firstname" type="xs:string"/>
<xs:element name="lastname" type="xs:string"/>
<xs:element name="company" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:element name="persons">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="employee" type="employee"/>
<xs:element name="customer" type="customer"/>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
此架构定义了一个元素“persons”。它包含一个反映每个“person”的选择元素列表(minOccurs=”0”,maxOccurs=”unbounded”)。此列表中的每个条目要么是“员工”,要么是“客户”(但不能同时是两者)。
这是有效 XML 消息的示例:
<?xml version="1.0" encoding="UTF-8"?>
<persons>
<employee>
<firstname>Piet </firstname>
<lastname>Pieters</lastname>
<salary>5</salary>
</employee>
<customer>
<firstname>Customer</firstname>
<lastname>Klant</lastname>
<company>Company</company>
</customer>
<employee>
<firstname>Other</firstname>
<lastname>Guy</lastname>
<salary>50</salary>
</employee>
</persons>
此处的人员列表包含 3 个条目:一名员工、一名客户和另一名员工。
3. 当前情况下的人物示例
在本节中,我们将展示如何在当前情况下基于此 XML 模式创建 XML 到域的映射。首先,创建一个新的 XML 模式文档,并选择我们在第 2 节中定义的 XML 模式。随后,创建一个新的 XML 到域映射,单击“选择元素”,然后在出现的弹出窗口中选择我们刚刚创建的 XML 模式作为模式源1。结果屏幕如图 1 所示。在该图中,我们可以看到 choice 元素未显示在架构元素树中,因此其 0-* 多重性也缺失。

图 1. 选择要包含在 5.14 版之前的 XML 到域映射中的 XSD 元素
当我们选择所有元素并单击“确定”时,映射的左侧已填充。如果随后单击“生成映射”,则会创建相关实体、属性和关联(在域模型中,参见图 2),并填充到 XML 到域映射的右侧。结果如图 3 所示。在此图中,我们可以看到左侧确实缺少选择选项。这样做的主要后果是,人员与一个包含员工和客户(混合在一起)的列表没有一个关联,正如人们从 XML 架构文档中的定义所期望的那样,而是两个 1:1 关联,一个与员工,一个与客户。这本质上是不同的,因此如果导入客户/员工列表,可能会导致数据丢失,因为实际上只有第一个映射到 Mendix 对象。这个问题已在 5.14 版中得到解决 Mendix 平台,我们将在下一节中进行说明。

图 2. 5.14 版本之前人员示例的自动生成的域模型

图 3. 在版本 5.14 之前的人员示例中配置 XML 到域映射中的映射
4. 将人物示例转换为新情况
在本节中,我们将展示如何解决上一节中描述的情况。我们从以前的情况开始,描述转换项目需要采取的步骤并反映由此产生的变化。我们这样做是为了让人们更容易升级。当然,在新情况下从头开始一个新项目是完全可行的。为此,只需按照第 3 节中描述的相同步骤进行操作,并使用本节中描述的附加步骤进行扩展。
当您在 3 版中打开我们在第 5.14 节中创建的项目时 Mendix 需要执行平台手动步骤来转换您的项目。在“错误”窗口中会出现以下错误消息: “映射元素是选择的选项。请重新选择架构元素并包含选择元素”。如果双击该消息,XML-to-Domain 文档将打开并选择相关元素(见图 4)。

图 4. 转换后需要手动步骤来转换项目
如消息所述,我们需要重新选择架构元素来解决一致性错误。为此,单击 “选择元素…” 将出现如图5所示的对话框。

图 5. 转换后重新选择架构元素
在架构元素树中,我们看到现在有一个针对 XML 选择元素的显式元素 “(选择)”。请注意,此元素的多重性已正确设置为 0..*。打开此窗口时已自动选择选择元素,因此单击“确定”保存设置并继续配置映射。
如图 6 所示, “(选择)” 映射元素已插入到导入映射文档中。此额外映射元素的含义如下:选择的所有替代方案(在本例中为员工和客户)应该具有共同点,因为它们是某些事物的替代方案。在本例中,它们之间的共同点是它们都是一个人。因此,在新情况下,选择的所有替代方案都应从更通用的实体(人)继承,并且该实体应被拖到映射上。真正理解这一点的含义很重要。对于示例,这意味着人员实体具有人员类型的列表,而员工和客户是特定类型的人员,因此可以出现在列表中。
图 6 中有四个一致性错误。前两个错误通过为员工和客户选择正确的泛化实体来解决。后面两个错误与以下事实有关:在原始情况下(没有明确的选择元素),选择项本身(员工和客户)与映射中的人员有关联。这不再允许,因为这应该在选择元素中配置。要解决此问题,请双击员工和客户,将出现一条消息,说明将删除关联。单击“确定”以确认这一点。

图 6. 选择新(选择)元素后的 XML 到域映射文档
解决前两个一致性错误可以通过手动为员工和客户创建一个泛化类并在映射文档中选择它来完成。另一种方法是使用“自动映射”按钮为您完成此操作。如果您单击此按钮,将显示图 7 中所示的消息,解释已完成的操作。

图 7. 自动生成映射、实体、关联和属性时的变化概述
在这里,您可以看到映射中的大多数实体和关联都保留了以前的情况。对于 choice 元素,创建了一个名为 ChoiceBase 的类,employee 和 customer 已成为此类的特化,并且 ChoiceBase 与 persons 实体相关联。与之前的情况相比,这是一个很大的改进 “自动映射...” 函数在以前的版本中创建实体、属性和关联,因为它每次运行时都会重新创建所有实体、属性和关联,从而导致域模型不断增长,其中充满了不再需要的实体。
最终的领域模型如图8所示。

图 8. 人员示例的自动生成的域模型
请注意,我们可以对这个自动生成的模型进行一些改进。首先,ChoiceBase 是一个非常通用的术语,因为我们实际上了解我们自己的领域模型,所以我们可以使其更加具体。例如,我们可以将实体重命名为 “人”。如果我们这样做,重命名 “ChoiceBase_persons” 关联。接下来我们可以移动 “名” 和 “姓” 属性从雇员和客户实体转移到此 Person 实体,因为两个专业化都包含这些属性。最后,我们可以删除雇员和人员以及客户和人员之间的关联,因为随着 Person 实体的引入,它们不再需要。这是因为它们从 Person 实体继承了与人员的关联。完成所有这些更改后,域模型将如图 9 所示。

图 9. 针对人员示例自动生成的域模型的手动改进
进行这些更改后,我们注意到 XML 到域映射中出现了四个新的一致性错误。这些一致性错误之所以存在,是因为我们移动了 “名” 和 “姓” 属性从专业化实体(员工和客户)映射到泛化实体(人员),我们需要手动重新映射这些属性。为此,请转到 XML 到域映射,双击客户和员工,然后手动或单击 “按名称映射属性” 按钮。完成此操作后,所有一致性错误均已解决,并且 XML 到域映射文档看起来如图 10 所示。

图 10. 人员示例的 XML 到域映射文档的最终版本
5. 使用新的 XML 到域映射
在前面几节中,我们解释了如何为带有选择元素的 XML 模式创建和配置 XML 到域的映射,最后我们通过一个示例来说明如何在微流中使用此映射,以此结束本文。在此示例中,我们计算导入的 XML 文件中所有员工的工资总额,同时忽略客户(未定义工资)。
为此,我们创建了图 11 所示的微流程。具体操作如下:首先,我们选择一个 Filedocument 作为输入参数。随后,我们拖入一个 “导入 XML 文档” 操作,选择 Filedocument 作为输入,选择我们定义的 XML 到域映射作为映射,并选择将输出存储在 persons 变量中。接下来,我们拖入一个检索操作,在该操作中,我们将检索 personList 上的 “Person_persons” 关联 persons 变量。之后,我们创建一个变量来存储所有工资总额并将其初始化为零。然后,我们迭代 personList 中的所有项目,并根据项目是 Person 的具体子类型采取不同的操作(使用继承拆分)。当 Person 是员工时,我们将其转换为员工并将其工资添加到总额中。如果 Person 是客户,我们会忽略它。迭代完所有项目后,我们将所有工资总额写入日志。
图 11. 使用人员示例的 XML 到域映射来汇总 XML 文件中所有客户的工资的微流程
致谢
本文由 Pieter van Balen 和 Kevin Dullemond 共同撰写。