大規模な XML メッセージの処理

入力ビット・ストリームが構文解析され、 論理ツリーが作成されるとき、通常、 対応するビット・ストリームに比べて XML メッセージのツリー表記の方が大きくなります (場合によっては、 はるかに大きくなります)。 その理由は、次のとおりです。
  • 複数のオブジェクトをリンクするポインターが追加されるため
  • 文字データが Unicode に変換され、サイズが倍増する可能性があるため
  • ビット・ストリームでは暗黙であることの多いフィールド名が含まれるため
  • ブローカーの操作に関連した制御データの存在

大規模なメッセージ・ツリーを操作するために大きなストレージが必要になるかもしれません。 繰り返し構造からなる大きなメッセージを扱うメッセージ・フローを設計するとき、ESQL ステートメントをコーディングすれば、 ブローカーのストレージ・ロードを軽減することができます。 このステートメントはメッセージへのランダム・アクセスと順次アクセスの両方をサポートしますが、一度にメッセージ全体にアクセスする必要がないことを想定します。

このような ESQL ステートメントによって、 ブローカーはメッセージを限定的に構文解析して、 メッセージ・ツリー内の単一レコードを表す部分だけを一度にストレージ内に保持します。 処理で 1 つのレコードから次のレコードに移るときに情報を保持しなければならない場合 (例えば、 注文に含まれる各品目の繰り返し構造から合計価格を計算する場合)、 いくつかの ESQL 変数を宣言し、 初期化して保持することができます。あるいは、 メッセージ・ツリー内の他の場所 (例えば LocalEnvironment) に値を保存する方法もあります。

この技法によってブローカーによるメモリー使用量が減少し、 入出力ビット・ストリームの全体と、 ただ 1 つのレコードのツリーを保持する容量だけが必要になります。 たとえメッセージ内で繰り返しの回数が少なくても、 メモリーが節約されます。 ブローカーは限定的に構文解析するだけでよく、 メッセージ・ツリー内の指定された部分だけをビット・ストリームの対応する部分との間で解析します。

Compute ノードでこれらの技法を使用するには、 以下のような一般的な手順に従ってください。
  • 入力メッセージの本文を、 出力メッセージ内の特別なフォルダーにビット・ストリームとしてコピーします。 これによって、入力メッセージの変更可能なコピーが作成されます。 これは構文解析されないため、最小限のメモリーを使用します。
  • 入力メッセージの検査はいっさい行わないようにします。 これにより、メッセージを構文解析する必要がなくなります。
  • ループおよび参照変数を使って、一度に 1 レコードずつメッセージをステップスルーします。 各レコードごとに、以下を行います。
    • 通常の変換によって、 対応する出力サブツリーを 2 番目の特別なフォルダー内に作成します。
    • ASBITSTREAM 関数を使って、 出力サブツリーのビット・ストリームを生成します。さらに、 最終的なビット・ストリーム内の位置に対応するツリー内の位置を占める BitStream エレメントに、 これを保存します。
    • 現在の入出力レコード・メッセージ・ツリーの操作が終わったら、 DELETE ステートメントを使って入出力レコード・メッセージ・ツリーを削除します。
    • すべてのレコードの処理が終わったら、 特別なフォルダーを切り離して、 出力ビット・ストリーム内に表示されないようにします。
実際のメッセージ処理の必要に合わせて、 上記の手法を独自に変えることもできます。 以下の ESQL は 1 つの実装例です。複雑な XML メッセージの変換では、ESQL の例を示しましたが、 以下の例はそれを書き直したものです。ネストされた繰り返し構造を含むメッセージを変換するために、単一の SET ステートメントとネストされた複数の SELECT 関数を使用します。
-- 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;
This produces the following output message:
<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>
0</Statement>
<GrandTotal>2.54144E+2</GrandTotal>
</Data>
関連概念
メッセージ・フローの概要
ESQL の概要
関連タスク
メッセージ・フローの設計
メッセージ・フローの内容の定義
ESQL ファイルの管理
複雑な XML メッセージの変換
関連資料
Compute ノード
DELETE ステートメント
ASBITSTREAM 関数
サンプル・メッセージ
特記事項 | 商標 | ダウンロード | ライブラリー | サポート | フィードバック
Copyright IBM Corporation 1999, 2006 Last updated: 5 01, 2006
ac16740_