0

我有一个 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

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

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 结构。

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

有什么帮助吗?

我需要帮助来循环结构,一段时间或一段时间。

4

2 回答 2

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)(这在许多情况下可能很有用)

于 2018-05-28T13:00:28.423 回答
0

因此,理解 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. 导航到名为Body的SOAP的第一个子节点
  4. 导航到Body的第一个名为listDocs且位于ns75命名空间中的子节点。

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

这解释了您的代码中发生了什么。您总是在InputRootEnvironment Trees中导航到相同的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 的答案,您还需要在语句的左侧使用下标。选择描述字段作为示例,您需要按如下方式更改代码。

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,这将导致循环的每一次迭代都沿着树遍历InputRootSOAPBodyns75: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. 要反向处理列表,请将[<]下标与MOVE的PREVIOUSSIBLING选项结合起来。

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

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,它们非常强大,在性能方面是您最简单的选择之一。

于 2018-05-31T12:06:47.380 回答