因此,对大型消息树进行操作可能会需要大量存储。如果您设计一个消息流,处理由重复结构组成的大型消息,则可以编码特定的 ESQL 语句,帮助减少代理上的存储负载。这些语句同时支持对消息的随机和有序访问,但前提是您不需要一次访问整个消息。
这些 ESQL 语句使代理对消息执行有限的解析,并且仅保存消息树中某一部分,该部分每次反映存储器内的一个记录。如果处理操作要求您按记录逐一保留信息(例如,计算订单中各项的重复结构的总价格),您既可以声明、初始化、保留 ESQL 变量,也可以将值保存在消息树的其他部分,如 LocalEnvironment。
此技术将把代理使用的内存减少到保存完整输入和输出位流,加上用于单条记录的树所需的大小。甚至是在消息中遇到少量重复时,它也能节省内存。代理使用部分解析和将指定部分的消息树解析为相应部分的位流,或从部分位流解析为部分消息树的能力。
您可以变化使用这些技术来适应消息所需的处理。下面的 ESQL 提供了一个实施的示例,它重写了处理大型 XML 消息中的 ESQL 示例,该示例使用具有嵌套 SELECT 函数的单个 SET 语句转换了包含嵌套重复结构的消息。
该 ESQL 从属于称为 LargeMessageExanple 的消息集,已创建该消息集,定义 Invoice 输入格式和 Statement 输出格式的消息。已创建称为 AllInvoices 的消息,该消息包含一个称为 Invoice 的全局元素(可以重复一次或多次)和一条称为 Data 的消息,它包含一个称为 Statement 的全局元素,可以重复一次或多次。
这些元素和属性的定义已经被赋予正确的数据类型,因此,不再需要 XML 示例中 ESQL 使用的 CAST 语句。在消息集中已创建了称为 XML1 的 XML 物理格式,这使您能够使用 MRM 解析与这些消息相应的 XML 消息。
当使用 ASBITSTREAM 函数序列化 Statement 树时,Message Set、Message Type 和 Message Format 将被指定为参数。Message Type 参数包含从消息到被序列化元素的路径,在本例中,该路径为 Data/Statement,因为 Statement 元素时 Data 消息的直接子代。
<AllInvoices> .... </AllInvoices>
输出消息与处理大型 XML 消息中的输出消息相同。
CREATE COMPUTE MODULE LargeMessageExampleFlow_Compute CREATE FUNCTION Main() RETURNS BOOLEAN BEGIN CALL CopyMessageHeaders(); -- Create a special folder in the output message to hold the input tree -- Note : SourceMessageTree is the root element of an MRM parser CREATE LASTCHILD OF OutputRoot.MRM DOMAIN 'MRM' NAME 'SourceMessageTree'; -- Copy the input message to a special folder in the output message -- Note : This is a root to root copy which will therefore not build trees SET OutputRoot.MRM.SourceMessageTree = InputRoot.MRM; -- Create a special folder in the output message to hold the output tree CREATE FIELD OutputRoot.MRM.TargetMessageTree; -- Prepare to loop through the purchased items DECLARE sourceCursor REFERENCE TO OutputRoot.MRM.SourceMessageTree.Invoice; DECLARE targetCursor REFERENCE TO OutputRoot.MRM.TargetMessageTree; DECLARE resultCursor REFERENCE TO OutputRoot.MRM; DECLARE grandTotal FLOAT 0.0e0; -- Create a block so that it's easy to abandon processing ProcessInvoice: BEGIN -- If there are no Invoices in the input message, there is nothing to do IF NOT LASTMOVE(sourceCursor) THEN LEAVE ProcessInvoice; END IF; -- Loop through the invoices in the source tree InvoiceLoop : LOOP -- Inspect the current invoice and create a matching Statement SET targetCursor.Statement = THE ( SELECT 'Monthly' AS Type, 'Full' AS Style, I.Customer.FirstName AS Customer.Name, I.Customer.LastName AS Customer.Surname, I.Customer.Title AS Customer.Title, (SELECT FIELDVALUE(II.Title) AS Title, II.UnitPrice * 1.6 AS Cost, II.Quantity AS Qty FROM I.Purchases.Item[] AS II WHERE II.UnitPrice > 0.0 ) AS Purchases.Article[], (SELECT SUM( II.UnitPrice * II.Quantity * 1.6 ) FROM I.Purchases.Item[] AS II ) AS Amount, 'Dollars' AS Amount.Currency FROM sourceCursor AS I WHERE I.Customer.LastName <> 'White' ); -- Turn the current Statement into a bit stream -- The SET parameter is set to the name of the message set -- containing the MRM definition -- The TYPE parameter contains the path from the from the message -- to element being serialized -- The FORMAT parameter contains the name of the physical format -- name defined in the message DECLARE StatementBitStream BLOB CAST(ASBITSTREAM(targetCursor.Statement OPTIONS FolderBitStream SET 'LargeMessageExample' TYPE 'Data/Statement' FORMAT 'XML1') AS BLOB); -- If the SELECT produced a result (that is, it was not filtered -- out by the WHERE clause), process the Statement IF StatementBitStream IS NOT NULL THEN -- create a field to hold the bit stream in the result tree -- The Type of the element is set to MRM.BitStream to indicate -- to the MRM Parser that this is a bitstream CREATE LASTCHILD OF resultCursor Type MRM.BitStream NAME 'Statement' VALUE StatementBitStream; -- Add the current Statement's Amount to the grand total SET grandTotal = grandTotal + targetCursor.Statement.Amount; END IF; -- Delete the real Statement tree leaving only the bit stream version DELETE FIELD targetCursor.Statement; -- Step onto the next Invoice, removing the previous invoice and any -- text elements that might have been interspersed with the Invoices REPEAT MOVE sourceCursor NEXTSIBLING; DELETE PREVIOUSSIBLING OF sourceCursor; UNTIL (FIELDNAME(sourceCursor) = 'Invoice') OR (LASTMOVE(sourceCursor) = FALSE) END REPEAT; -- If there are no more invoices to process, abandon the loop IF NOT LASTMOVE(sourceCursor) THEN LEAVE InvoiceLoop; END IF; END LOOP InvoiceLoop; END ProcessInvoice; -- Remove the temporary source and target folders DELETE FIELD OutputRoot.MRM.SourceMessageTree; DELETE FIELD OutputRoot.MRM.TargetMessageTree; -- Finally add the grand total SET resultCursor.GrandTotal = grandTotal; -- Set the output MessageType property to be 'Data' SET OutputRoot.Properties.MessageType = 'Data'; RETURN TRUE; END; CREATE PROCEDURE CopyMessageHeaders() BEGIN DECLARE I INTEGER 1; DECLARE J INTEGER CARDINALITY(InputRoot.*[]); WHILE I < J DO SET OutputRoot.*[I] = InputRoot.*[I]; SET I = I + 1; END WHILE; END; END MODULE;