【问题标题】:How to iterate/while a mapping variables from environment to message assembly in IBM Integration Bus (toolkit)?如何在 IBM Integration Bus(工具包)中迭代/同时将变量从环境映射到消息程序集?
【发布时间】:2018-05-31 20:32:38
【问题描述】:

我有一个 SOAP 节点,它从树结构中的 URL 检索信息。

然后我有一个计算节点来定义每个环境变量到 SOAP 检索的每个命名空间变量。

最后,我有一个映射节点,可以将内容移动到我的 XML 消息组装结构中。

它给我的错误是这个(在计算节点中):

我有这样的结构:

列表文档

Description
DocType
ListTypes
 Attribute
 Lenght
 Description
 Nature
 Required

列表文档

Description
DocType
ListTypes
 Attribute
 Lenght
 Description
 Nature
 Required

列表文档

Description
DocType
ListTypes
 Attribute
 Lenght
 Description
 Nature
 Required

问题是,当我定义变量时,我会像下面的代码一样在 COMPUTE NODE 中进行:

WHILE I < InputRoot.SOAP.Body.ns:obterTiposDocProcessosResponse.ns:return.ns75:processo.ns75:listaTiposDocumentos  
DO

  SET Environment.Variables.XMLMessage.return.process.listDocs.description = InputRoot.SOAP.Body.ns75:processo.ns75:listDocs.ns75:description;

  SET Environment.Variables.XMLMessage.return.process.listDocs.tipoDocumento = InputRoot.SOAP.Body.ns75:processo.ns75:listDocs.ns75:DocType;

  SET Environment.Variables.XMLMessage.return.process.listDocs.listTypes.attribute = InputRoot.SOAP.Body.ns75:processo.ns75:listDocs.ns75:listTypes.ns75:atribbute;

  SET Environment.Variables.XMLMessage.return.process.listDocs.listTypes.lenght = InputRoot.SOAP.Body.ns75:processo.ns75:listDocs.ns75:listTypes.ns75:lenght;

  SET Environment.Variables.XMLMessage.return.process.listDocs.listTypes.description = InputRoot.SOAP.Body.ns75:processo.ns75:listDocs.ns75:listTypes.ns75:description;

  SET Environment.Variables.XMLMessage.return.process.listDocs.listTypes.nature = InputRoot.SOAP.Body.ns75:processo.ns75:listDocs.ns75:listTypes.ns75:nature;

  SET Environment.Variables.XMLMessage.return.process.listDocs.listTypes.required = InputRoot.SOAP.Body.ns75:processo.ns75:listDocs.ns75:listTypes.ns75:required;    

  SET I = I+1;

END WHILE;

但是,在我的 XML 最终结构中,它只打印我的第一个 listDocs 的值,我想打印我所有的 listDocs 结构。

注意:在这样的情况下,它甚至不起作用。我必须删除 WHILE 才能打印第一个 listDocs 就像我上面说的那样。

有什么帮助吗?

我需要一段时间来循环结构。

【问题讨论】:

  • @JohnathanLeffler 感谢您再次删除标签 [esql],我在之前的编辑中将其替换为 [extended-sql] 标签,但没有注意到 OP 将其添加回来。程序员大师,正如标签 wiki 所说的“不要使用这个标签,因为它是模棱两可的”。请不要问这个问题,因为标签 [extended-sql] 是特定于 IIB 使用的“ESQL”的。

标签: mapping ibm-integration-bus extended-sql


【解决方案1】:

您应该尝试使用以下合成器:

DECLARE I INTEGER 1;
DECLARE J INTEGER;
J = CARDINALITY(InputRoot.SOAP.Body.ns:obterTiposDocProcessosResponse.ns:return.ns75:processo.ns75:listaTiposDocumentos[])
WHILE I <= J DO
   SET Environment.Variables.XMLMessage.return.process.listDocs.description = InputRoot.SOAP.Body.ns75:processo.ns75:listDocs[I].ns75:description;
   ....
END WHILE;

您只是错过了获取元素数量的CARDINALITY函数,以及定义表格的[],然后在访问元素时使用此[I]

注意:在我上面的示例中,环境将在循环的每次迭代中被覆盖,因此只会打印最后一条记录。如果要在输出中构造表,也可以在输出中使用 [I],或者可以使用以下代码将每条消息推送到输出终端(这意味着您有一条消息在输入中,3 条消息从输出端出来)

PROPAGATE TO TERMINAL 'Out';

例如,根据您的代码,如果您想根据包含多个元素的输入生成 3 条消息:

DECLARE I INTEGER 1;
DECLARE J INTEGER;
J = CARDINALITY(InputRoot.SOAP.Body.ns:obterTiposDocProcessosResponse.ns:return.ns75:processo.ns75:listaTiposDocumentos[])
WHILE I <= J DO
   SET Environment.Variables.XMLMessage.return.process.listDocs.description = InputRoot.SOAP.Body.ns75:processo.ns75:listDocs[I].ns75:description;
   SET Environment.Variables.XMLMessage.return.process.listDocs.tipoDocumento = InputRoot.SOAP.Body.ns75:processo.ns75:listDocs[I].ns75:DocType;
   SET Environment.Variables.XMLMessage.return.process.listDocs.listTypes.attribute = InputRoot.SOAP.Body.ns75:processo.ns75:listDocs[I].ns75:listTypes.ns75:atribbute;
   SET Environment.Variables.XMLMessage.return.process.listDocs.listTypes.lenght = InputRoot.SOAP.Body.ns75:processo.ns75:listDocs[I].ns75:listTypes.ns75:lenght;
   SET Environment.Variables.XMLMessage.return.process.listDocs.listTypes.description = InputRoot.SOAP.Body.ns75:processo.ns75:listDocs[I].ns75:listTypes.ns75:description;
   SET Environment.Variables.XMLMessage.return.process.listDocs.listTypes.nature = InputRoot.SOAP.Body.ns75:processo.ns75:listDocs[I].ns75:listTypes.ns75:nature;
   SET Environment.Variables.XMLMessage.return.process.listDocs.listTypes.required = InputRoot.SOAP.Body.ns75:processo.ns75:listDocs[I].ns75:listTypes.ns75:required;
   PROPAGATE TO TERMINAL 'Out';
END WHILE;
RETURN FALSE;

对于您的全局信息,RETURN TRUE 是将 ESQL 代码中内置的消息“推送”到输出终端的指令。如果使用 PROPAGATE 指令(效果相同),则应返回 FALSE 以避免在循环记录后发送空消息。另一种方法是在另一个终端上传播(即:'out1'),并保持返回为真。在这种情况下,一旦所有消息都已传播,您将拥有从 out1 终端输出的所有记录,以及从输出终端输出的消息(由于返回 true)(这在许多情况下可能很有用)

【讨论】:

  • 您好,谢谢您的回复按照您所说的将代码放在每个输出中的 [I] 在 listDocs 前面,它不打印任何记录,而不是第一条记录(因为它打印时没有而),没有别的,它是空的......
  • 好的,所以...你说得对,我只需要做一些调整。现在我遇到的问题是它只打印最后一个......我在哪里放置传播?里面呢?你能准确地通过代码吗?对不起,我没有得到那部分
  • 您好,是的,传播指令基本上会生成一个新的输出,所以它应该在 I = I + 1; 之前(或之后)之前(或之后),我刚刚更新了我的答案代码
  • 这不适用于传播我在一段时间内按照您所说的(在 SET 之后或之前)执行指令,但我将 Body.getdocstructuretype 作为输出但他一直给出错误(仅接受 INTEGER 或 CHARACTER)...但我的输出结构不是来自该类型...
  • 你知道其他打印方式吗?而不仅仅是最后的结果?或者解决这个问题?谢谢
【解决方案2】:

因此,理解 IIB 和 ESQL 的关键是您正在查看从节点构建的内存树。

每个节点都有指向 PARENT、NEXTSIBLING、PREVSIBLING、FIRSTCHILD 和 LASTCHILD 节点的指针/引用。

节点还具有 FIELDNAME、FIELDNAMESPACE、FIELDTYPE 和 FIELDVALUE 属性。

最后但并非最不重要的是,您正在通过导航输入树来构建输出树。您正在使用的环境树是一种特殊的持久树,您可以读取和写入。

所以在您的代码中 InputRoot.SOAP.Body.ns75:processo.ns75:listDocs 可以被认为是导航到 ns75:listDocs 节点的指令的简写.点“。”告诉 ESQL 解释器当前节点的子节点的名称。如果你告诉某人如何导航节点,它会是这样的。

  1. InputRoot 开始。 InputRoot 是一个特殊的节点,您可以在 ESQL 模块代码中自动使用它。
  2. 导航到 InputRoot 的第一个名为 SOAP 的子节点
  3. 导航到 SOAP 的第一个名为 Body 的子节点
  4. 导航到 Body 的第一个子节点,该节点名为 listDocs 并且位于 ns75 命名空间中。

在没有下标的情况下,ESQL 假定您希望第一个与指定名称匹配的节点 ns75:listDocsns75:listDocs[1] 都指同一个节点。

这解释了您的代码中发生了什么。您总是导航到 InputRootEnvironment 树中的同一个 listDocs[1] 节点。

@Jerem 的代码至少在输入树中的 listDocs 节点之间导航,从而改进了您所做的工作。

对于循环的每次迭代,下标 [I] 都会递增,因此它会选择不同的 listDocs 节点。 listDocs 节点是兄弟节点,因此代码将访问 listDocs 节点的第一个、第二个和第三个实例。

InputRoot.SOAP.Body.ns75:processo.ns75:listDocs[1] <-- Iteration I=1
InputRoot.SOAP.Body.ns75:processo.ns75:listDocs[2] <-- Iteration I=2
InputRoot.SOAP.Body.ns75:processo.ns75:listDocs[3] <-- Iteration I=3

要更正@Jerem 的答案,您还需要在语句的左侧使用下标。选择 description 字段作为示例,您需要按如下方式更改代码。

SET Environment.Variables.XMLMessage.return.process.listDocs[I].listTypes.description = InputRoot.SOAP.Body.ns75:processo.ns75:listDocs[I].ns75:listTypes.ns75:description;

使用下标被视为一种表现。假设您有 10,000 个 listDocs,这将导致循环的每一次迭代都沿着树遍历 InputRootSOAP Body, ns75:processo 节点,然后穿过 listDocs 兄弟节点,直到找到 ns75:listDocs[I] 节点。

这意味着当我们开始处理 ns75:listDocs[10000] 时,它将不得不一遍又一遍地遍历所有其他 listDocs 节点, 实际上我们可以计算它会走过 (4 x 10,000) + ((10,000 x (10,000 + 1)) / 2) = 50,045,000 个节点

所以这是救援的参考,也是您问题的答案。试试这样的循环。

DECLARE ns75 NAMESPACE 'http://something.or.other.from.your.wsdl';
DECLARE InListDocsRef REFERENCE TO 
InputRoot.SOAP.Body.ns75:processo.ns75:listDocs;
WHILE LASTMOVE(InListDocsRef) DO
    DECLARE EnvListDocsRef REFERENCE TO Environment;
    CREATE LASTCHILD OF Environment.Variables.XMLMessage.return.process AS EnvListDocsRef NAME 'listDocs';

    SET EnvListDocsRef.description           = InListDocsRef.ns75:description;
    SET EnvListDocsRef.tipoDocumento         = InListDocsRef.ns75:DocType;
    SET EnvListDocsRef.listTypes.attribute   = InListDocsRef.ns75:listTypes.ns75:atribbute;
    SET EnvListDocsRef.listTypes.lenght      = InListDocsRef.ns75:listTypes.ns75:lenght;
    SET EnvListDocsRef.listTypes.description = InListDocsRef.ns75:listTypes.ns75:description;
    SET EnvListDocsRef.listTypes.nature      = InListDocsRef.ns75:listTypes.ns75:nature;
    SET EnvListDocsRef.listTypes.required    = InListDocsRef.ns75:listTypes.ns75:required;    

    MOVE InListDocsRef NEXTSIBLING REPEAT NAME;
END WHILE;

上面的代码只遍历了 4 + 10,000 个节点,即 10,000 个节点与 50,000,000 个节点。

关于设置引用的其他一些有用的知识是:

  1. 要指向最后一个元素,您可以使用 [ 的下标。因此,要指向聚合 MyList 中的最后一个 ListItem,您需要编写 Environment.MyList.ListItem[
  2. 您可以使用星号 * 设置对树中您不知道名称的元素的引用,例如Environment.MyAggregate.* 指向 MyAggregate 的第一个孩子,无论其名称如何。
  3. 您也可以使用星号 * 选择一个元素,而不管它的命名空间如何 InListDocsRef.*:listTypes.*:description
  4. 对于匿名命名空间元素,使用 *:* 但要非常小心 **:* 不是同一个东西,第一个表示不命名空间任何元素,第二个表示任何命名空间任何元素。
  5. 要反向处理列表,请将 [ 下标与 MOVEPREVIOUSSIBLING 选项结合起来。

因此,用于反转列表的一段代码可能类似于:

DECLARE MyReverseListItemWalkingRef REFERENCE TO Environment.MyList.ListItem[<];
WHILE LASTMOVE(MyReverseListItemWalkingRef) DO
    CREATE LASTCHILD OF OuputRoot.ReversedList.Item NAME 'Description' VALUE MyReverseListItemWalkingRef.Desc;

    MOVE MyReverseListItemWalkingRef PREVIOUSSIBLING REPEAT NAME;
END WHILE;

了解如何使用 REFERENCES,它们非常强大,是您在性能方面最简单的选择之一。

【讨论】:

  • 您是否尝试过调试器或用户跟踪。如果您无法轻松找到这些内容,请粘贴错误或异常列表的内容
  • 你有这个服务的 WSDL
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-30
  • 1970-01-01
  • 1970-01-01
  • 2015-05-18
  • 1970-01-01
  • 1970-01-01
  • 2022-09-23
相关资源
最近更新 更多