处理大型 XML 消息

当解析输入位流和创建的逻辑树时,XML 消息的树表示通常比较大,在有些情况下比相应的位流大很多。其原因包含:
  • 将对象链接到一起的指针增加
  • 将字符数据转换为 Unicode 格式;这可能是双倍大小
  • 包含位流中可能已经隐含的字段名
  • 存在与代理的操作相关联的控制数据

使用大型消息树可能需要大量存储。如果您设计一个消息流,处理由重复结构组成的大型消息,则可以编码 ESQL 语句,帮助减少代理上的存储负载。这些语句同时支持对消息的随机和有序访问,但前提是您不需要一次访问整个消息。

这些 ESQL 语句使代理对消息执行有限的解析,并且仅保存消息树中某一部分,该部分每次反映存储器内的一个记录。如果处理操作要求您按记录逐一保留信息(例如,计算订单中各项的重复结构的总价格),您既可以声明、初始化、保留 ESQL 变量,也可以将值保存在消息树的其他部分,如 LocalEnvironment。

此技术将把代理使用的内存减少为保留完整输入和输出位流,加上用于一个记录的树所需的量,并且甚至当在消息中遇到少量重复的情况下也节省内存。代理使用部分解析和将指定部分的消息树解析为相应部分的位流,或从部分位流解析为部分消息树的能力。

要在 Compute 节点上使用这些技术,请应用以下一般技术:
  • 将输入消息的主体作为位流复制到输出消息中的某个特定文件夹中。这会创建没有解析的输入消息的可修改副本,因此,耗用的内存量最少。
  • 避免对输入消息进行任何检查。这将避免对解析消息的需要。
  • 使用循环和引用变量单歩遍历消息,一次遍历一条记录。对于每个记录:
    • 使用常规转换在第二个特定文件夹中构建对应的输出子树。
    • 使用 ASBITSTREAM 函数为存储在 BitStream 元素中的输出子树生成位流,该元素放置在树中与在最终位流中要求它所在的位置相对应的位置处。
    • 完成当前输入和输出记录消息树的操作时,使用 DELETE 语句删除它们。
    • 完成处理所有的记录后,拆离特殊的文件夹,这样它们就不会在输出位流中出现了。
您可以变化使用这些技术来适应消息所需的处理。下面的 ESQL 提供了一个实施的示例,它重写了转换复杂 XML 消息中的 ESQL 示例。该示例使用具有嵌套 SELETE 函数的单个 SET 语句来转换包含嵌套、重复结构的消息。
-- Copy the MQMD header
  SET OutputRoot.MQMD = InputRoot.MQMD;

  -- Create a special folder in the output message to hold the input tree
  -- Note : SourceMessageTree is the root element of an XML parser
  CREATE LASTCHILD OF OutputRoot.XML.Data DOMAIN 'XML' 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.XML.Data.SourceMessageTree = InputRoot.XML;

  -- Create a special folder in the output message to hold the output tree
  CREATE FIELD OutputRoot.XML.Data.TargetMessageTree;

  -- Prepare to loop through the purchased items
  DECLARE sourceCursor REFERENCE TO OutputRoot.XML.Data.SourceMessageTree.Invoice;
  DECLARE targetCursor REFERENCE TO OutputRoot.XML.Data.TargetMessageTree;
  DECLARE resultCursor REFERENCE TO OutputRoot.XML.Data;
  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 (XML.Attribute)Type,
            'Full' AS (0x03000000)Style[1],
            I.Customer.FirstName AS Customer.Name,
            I.Customer.LastName AS Customer.Surname,
            I.Customer.Title AS Customer.Title,
                   (SELECT
              FIELDVALUE(II.Title) AS Title,
                                  CAST(II.UnitPrice AS FLOAT) * 1.6 AS Cost,
                         II.Quantity                     AS Qty
                         FROM I.Purchases.Item[] AS II
                         WHERE  II.UnitPrice > 0.0              )        AS Purchases.Article[],
                   (SELECT
              SUM( CAST(II.UnitPrice AS FLOAT) *
                                   CAST(II.Quantity AS FLOAT) *
                                   1.6                          )
                         FROM I.Purchases.Item[] AS II      )                AS Amount,
                   'Dollars'                                   AS Amount.(XML.Attribute)Currency
          FROM sourceCursor AS I
          WHERE I.Customer.LastName <> 'White'
        );

      -- Turn the current Statement into a bit stream
      DECLARE StatementBitStream BLOB        CAST(ASBITSTREAM(targetCursor.Statement OPTIONS FolderBitStream) 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
        CREATE LASTCHILD OF resultCursor
           Type XML.BitStream
           NAME 'StatementBitStream'
          VALUE StatementBitStream;

        -- Add the current Statement's Amount to the grand total
        -- Note that the cast is necessary because of the behavior of the XML syntax element
        SET grandTotal = grandTotal + CAST(targetCursor.Statement.Amount AS FLOAT);
      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.XML.Data.SourceMessageTree;
  DELETE FIELD OutputRoot.XML.Data.TargetMessageTree;

  -- Finally add the grand total
  SET resultCursor.GrandTotal = grandTotal;
这会产生以下输出消息:
<Data>
 <Statement Type="Monthly" Style="Full">
  <Customer>
   <Name>Andrew</Name>
   <Surname>Smith</Surname>
   		 		 <Title>Mr</Title>
  </Customer>
  <Purchases>
   <Article>
    <Title>The XML Companion </Title>
    <Cost>4.472E+1</Cost>
    <Qty>2</Qty>
   </Article>
   <Article>
    <Title>A Complete Guide to DB2 Universal Database</Title>
    <Cost>6.872E+1</Cost>
    <Qty>1</Qty>
   </Article>
   <Article>
    <Title>JAVA 2 Developers Handbook</Title>
    <Cost>9.5984E+1</Cost>
    <Qty>1</Qty>
   </Article>
  </Purchases>
    <Amount Currency="Dollars">2.54144E+2</Amount>
 </Statement>
 <GrandTotal>2.54144E+2</GrandTotal>
</Data>
相关概念
消息流概述
ESQL 概述
相关任务
设计消息流
定义消息流内容
管理 ESQL 文件
转换复杂 XML 消息
相关参考
Compute 节点
DELETE 语句
ASBITSTREAM 函数
示例消息
声明 | 商标 | 下载 | 书库 | 支持 | 反馈
Copyright IBM Corporation 1999, 2006 最后一次更新时间:2006/08/14
ac16740_