レベル: 中級 Michael Rajkowski (mrajkow@us.ibm.com), Software Engineer, U2 Client Support, IBM
2007年 11月 02日 IBM U2 (IBM UniData® と IBM UniVerse®) は、すべてのデータをデータ型の検証をせずに保管します。そのため、同じフィールドが整数を含むこともあればストリングを含むこともあり、さらには内部データ構造を含むことさえあります。これはアプリケーションの開発者には便利かもしれませんが、U2 環境のデータを外部環境に統合する際には問題を起こす可能性があります。この記事では、スキーマに対してデータの妥当性を検証する方法と、更新トリガーによって無効なデータを防止する方法を説明します。
はじめに
皆さんは U2 環境のデータと他のソースのデータを統合したり、あるいは U2 環境のデータを外部環境に統合したりする必要はないでしょうか。U2 が XML をサポートしているおかげで、簡単な方法でデータの妥当性を検証することができます。
 |
ファイル情報 UniData と UniVerse は類似したファイルを持っており、そのファイルは UniData では STUDENT と呼ばれ、UniVerse では STUDENT.F と呼ばれます。UniVerse を使っている人は、この記事の例の中で使用しているファイル名の最後に「.F」を追加してください。また、ディレクトリーを _XML_ と呼ぶのは UniData を使用している場合であることに注意してください。UniVerse の場合にはディレクトリー名は &XML& です。 |
|
この記事は、検証ルーチンの設定方法と、検証ルーチンをファイル・トリガーにフックすることで、更新が行われても定義されたスキーマと一致しないデータは書き込まれないようにする方法とを説明します。
この記事では XML や XML スキーマを教えるわけではないことに注意してください。この記事の目的は、U2 の XML サポートを利用してデータ型の検証を行う方法を説明することです。
この記事で説明する手順を追うためには、U2 にログインする必要があります。UniData ユーザーは Demo アカウントにログインする必要があり、UniVerse ユーザーは HS.SALES アカウントにログインする必要があります。
U2 データベースにアクセスできない人は、Personal Edition のコピーをダウンロードすることができます (「参考文献」にリンクがあります)。
XML を使って検証する
データを調べる
まず、典型的な U2 のクエリー文のデータを見るところから始めましょう。リスト 1 は、STUDENT ファイルに対する単純な LIST 文の実行結果を示しています。U2 データベースや MultiValued データベースになじみがない方は、記事「IBM
U2: The big picture」(developerWorks、2005年8月) を参照してください。
リスト 1. U2 クエリーの出力の例
LIST STUDENT LNAME FNAME MAJOR MINOR ADVISOR SEMESTER COURSE_NBR COURSE_GRD
SAMPLE 1 13:06:49 Sep 24 2007 1
STUDENT..... Last Name...... First Name Major Minor Advisor. Term Crs # GD.
521-81-4564 Smith Harry CH PY Carnes FA93 CS130 A
CS100 B
PY100 B
SP94 CS131 B
CS101 B
PE220 A
1 record listed
|
出力を XML として表示する
コマンドラインの引数のおかげで、TOXML キーワードを含めれば上の文から XML を生成することができます。リスト 2 は生成される XML を示しています。
リスト 2. U2 のクエリーの XML 出力の例
LIST STUDENT LNAME FNAME MAJOR MINOR ADVISOR SEMESTER COURSE_NBR COURSE_GRD
SAMPLE 1 TOXML
<?xml version="1.0"?>
<ROOT>
<STUDENT _ID = "521814564" LNAME = "Smith" FNAME = "Harry" MAJOR = "CH" MINOR =
"PY" ADVISOR = "Carnes">
<CGA-MV SEMESTER = "FA93">
<CGA-MS COURSE_NBR = "CS130" COURSE_GRD = "A"/>
<CGA-MS COURSE_NBR = "CS100" COURSE_GRD = "B"/>
<CGA-MS COURSE_NBR = "PY100" COURSE_GRD = "B"/>
</CGA-MV>
<CGA-MV SEMESTER = "SP94">
<CGA-MS COURSE_NBR = "CS131" COURSE_GRD = "B"/>
<CGA-MS COURSE_NBR = "CS101" COURSE_GRD = "B"/>
<CGA-MS COURSE_NBR = "PE220" COURSE_GRD = "A"/>
</CGA-MV>
</STUDENT>
</ROOT>
|
スキーマを作成する
U2 の 1 つの特徴が、コマンドラインのクエリー言語を使ってスキーマを作成できる機能です。スキーマは、スキーマ単体で、あるいは XML ファイルと共に作成することができます。U2 の問い合わせ言語の完全な構文については U2 のマニュアルを参照してください。
 |
TO 節に関する興味深い事実 この例の TO 節に与えられている名前が「studentSchema」であることに注意してください。_XML_ ディレクトリーを見ると studentSchema.xsd ファイルが見つかるはずです。 |
|
下記のコマンドを使ってスキーマと xml ファイルを作成します。
LIST STUDENT LNAME FNAME MAJOR MINOR ADVISOR SEMESTER COURSE_NBR
COURSE_GRD TOXML SCHEMAONLY TO studentSchema
スキーマに対して XML 文書の妥当性を検証する
U2 のクエリー文から XML 文書を作成する方法とクエリー文からスキーマを生成する方法がわかったので、このスキーマで XML の妥当性を検証する方法を調べてみましょう。
 |
重要な情報 UniData を使っている場合には、I オプションを付けてコンパイルすることを忘れないでください。 |
|
下記のリスト (リスト 3) は、このスキーマで XML の妥当性を検証する簡単な U2 の基本プログラムです。(このコードは「ダウンロード」セクションの CHECKDATA という名前のファイルに含まれています。)
リスト 3. CHECKDATA プログラム
001: *
002: * For UniData use the following include.
003: $INCLUDE INCLUDE XML.H
004: *
005: * For UniVerse use the following include.
006: *$INCLUDE UNIVERSE.INCLUDE XML.H
007: *
008: ***
009: PRINT "Enter the select Criteria for the STUDENT file":;INPUT OPT
010: *
011: CMD = "LIST STUDENT LNAME FNAME MAJOR MINOR ADVISOR SEMESTER COURSE_NBR CORSE_GRD "
012: PRINT "Use XMLEXECUTE to get the XML: ":
013: STATUS = XMLEXECUTE( CMD:OPT, '', XML.DOC, XSD.DOC)
014: GOSUB CHECK.ERROR
015: *
016: XSD.NAME = "studentSchema.xsd"
017: *
018: PRINT "Validate the XML against the schema: ":
019: STATUS = XDOMValidate( XML.DOC, XML.FROM.STRING, XSD.NAME, XML.FROM.FILE)
020: GOSUB CHECK.ERROR
021: PRINT "IT IS VALID"
022: *
|
 |
プログラムを実行する 入力で SAMPLE 1 と入力する必要があります。すると、すべての項目が XML 文書の中に入ります。 |
|
リスト 3 のプログラムをコンパイルして実行すると、下記が表示されます。
リスト 4. CHECKDATA プログラムを実行する
:RUN BP CHECKDATA
Enter the select Criteria for the STUDENT file?SAMPLE 1
Use XMLEXECUTE to get the XML: COMMAND SUCCESS
Validate the XML against the schema: COMMAND SUCCESS
IT IS VALID
|
スキーマを制限する
リスト 4 では、XML は妥当な XML ですが、それはこの例に対するスキーマの制限があまり厳しくないためです (すべての属性はストリング型として定義されており、要素の個数に関する最小、最大の制限はありません)。
リスト 5. studentSchema.xsd の抜粋
<xsd:element name="STUDENT">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="CGA-MV" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="_ID" type="xsd:string"/>
<xsd:attribute name="LNAME" type="xsd:string"/>
<xsd:attribute name="FNAME" type="xsd:string"/>
<xsd:attribute name="MAJOR" type="xsd:string"/>
<xsd:attribute name="MINOR" type="xsd:string"/>
<xsd:attribute name="ADVISOR" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
|
 |
検証を中断する どの項目も負の ID を持っていないため、デモのために negativeInteger 型を使って検証を中断しています。 |
|
リスト 5 を見るとわかるように、すべての属性はストリング型として定義されています。そのため、「123」は「何らかのテキスト」と同じように有効です。このスキーマを制限するために、_ID 属性の型を「negativeInteger」に変更しましょう。
<xsd:attribute name="_ID"
type="xsd:negativeInteger"/>
リスト 6. CHECKDATA を再度実行する
RUN BP CHECKDATA
Enter the select Criteria for the STUDENT file?SAMPLE 1
Use XMLEXECUTE to get the XML: COMMAND SUCCESS
Validate the XML against the schema: COMMAND FAILED
29 Error at file 'U2XMLMemoryBufferID', line 4, column 105.
Message: Datatype error: Type:InvalidDatatypeFacetException,
Message:Value '+521814564' must be less than or equal to MaxInclusive '-1' .
:
|
データのクレンジング
検証ルーチンを作成する
検証の方法は理解できたので、検証機能を使って何をするのかを決めなければなりません。1 つしなければならないことは、ファイルの中の全データを検証することです。先ほどの例では何も選択基準を使いませんでしたが、それとは異なる方法として、プログラムを使って各項目に対して XML ストリングを生成し、検証できない項目を表示する方法があります。
プログラミングを単純にするために、そのプログラム自体のサブルーチンに検証ロジックを移動し、fullSchema.xsd に対して妥当性の検証をするための XML を渡します。
これは全項目の検証を行い、その結果を画面に表示する単純なプログラムです。
リスト 7 には、新しいサブルーチンを使って STUDENT ファイルの全項目を検証するプログラムが含まれています。
このサブルーチンは validateStudentItem と呼ばれ、ダウンロード・ファイルに含まれています (「ダウンロード」を参照)。
リスト 7. validateStudentFile プログラム
001: *
002: * For UniData use the following include.
003: $INCLUDE INCLUDE XML.H
004: *
005: * For UniVerse use the following include.
006: *$INCLUDE UNIVERSE.INCLUDE XML.H
007: **
008: OPEN "STUDENT" TO STUDENT.FILE ELSE STOP "Can not open STUDENT"
009: SELECT STUDENT.FILE TO 1
010: DONE = 0
011: CMD = "LIST STUDENT LNAME FNAME MAJOR MINOR ADVISOR SEMESTER COURSE_NBR COURSE_GRD "
012: LOOP
013: READNEXT ID FROM 1 ELSE DONE = 1
014: UNTIL DONE
015: OPT = " WITH @ID = '":ID:"'"
016: STATUS = XMLEXECUTE( CMD:OPT, '', XML.DOC, XSD.DOC)
017: CALL validateStudentItem( XML.DOC, STATUS, ERRORTEXT )
018: IF STATUS THEN
019: PRINT ID, "Item is not valid"
020: PRINT ; PRINT ERRORTEXT ; PRINT ; PRINT "---------"
021: END
022: REPEAT
|
有効なデータのみが U2 データベースに入るように、最後に 1 つのステップが必要です。そのステップとは、スキーマから判断して有効ではない変更を防ぐステップです。この検証を実現するために、上記で使用した validateStudentItem を更新トリガーと統合し、有効な項目のみが更新されるように更新を制限します。
トリガーを使って検証する
更新トリガーは、データが更新される前に呼び出されます。そのトリガーが、そのデータを書き込むことが適切ではないことを示唆している場合には、更新は行われません。
これを念頭に置いた上で、スキーマに対して項目の妥当性を検証してその検証が有効である限り更新を許可するトリガーを作成します。
トリガーが呼び出された時には、書き込み対象のデータはデータベースの中にはありません。XMLEXECUTE コマンドは、少し変更しないと XML を生成することができません。
トリガーは、項目のコピーを作業ファイルに保存する必要があります。そうすると、XMLEXECUTE コマンドに送られるコマンドのストリングとオプションを少し変更すれば XML を生成することができます。
リスト 8. studentValidationTrigger の抜粋
020: ** Get the XML for the item in process
021: CMD = 'LIST WORK_FILE USING DICT STUDENT LNAME FNAME MAJOR MINOR ADVISOR SE
MESTER COURSE_NBR COURSE_GRD WITH @ID LIKE "':recordId:'"'
022: STATUS = XMLEXECUTE(CMD, "RECORD":@VM:"STUDENT", XML.DOC, XSD.DOC)
|
上記のリスト 8 を見ると、LIST コマンドに USING 節が使われていることの他、このレコードの要素名を STUDENT に変更する必要があったことがわかります。デフォルトで、U2 はファイル名を使います。レコード名を変更しない場合は、レコード名は「WORK_FILE」になるはずです。
このトリガー・プログラムをコンパイルし、カタログに登録し、そして更新されたトリガー・アクションとして STUDENT ファイルに追加したら、ロギング用にいくつかのファイルを設定する必要があります。
トリガーに対するエラー・ログ
WORK_FILE の中には STUDENT ファイルに対して有効ではない項目があるかもしれないため、その情報と発生したエラーを保存するための方法が必要です。この例では、XML_ERRORS と XML_LOG という、さらに 2 つのファイルを使います。トリガー・プログラムをテストする前に、これらのファイルを作成してください。
XML_LOG ファイルには WORK_FILE の中の項目から生成される XML が含まれ、XML_ERRORS ファイルは検証に失敗した結果、生成されるテキスト・メッセージです。
リスト 9. トリガーをテストする
:AE STUDENT 123.456
Top of New "123.456" in "STUDENT".
*--: FI
Error from trigger: Error at file 'U2XMLMemoryBufferID', line 4, column 26. Mess
age: Datatype error: Type:InvalidDatatypeFacetException, Message:Value '+123.456
' with fraction digits '3' exceeds fraction digit facet of '0' .
Error at file 'U2XMLMemoryBufferID', line 4, column 26. Message: Required attrib
ute 'FNAME' was not provided
Error at file 'U2XMLMemoryBufferID', line 4, column 26. Message: Required attrib
ute 'LNAME' was not provided
[AE] UniBasic WRITE failed, STATUS=2, check triggers.
Quit "123.456" in file "STUDENT" not created.
: |
これによって、データベースに入力されるデータは、必ず定義された型を持つことになります。
これでファイルに対してデータ型をチェックできるようになったので、無効なデータを処理できるようにアプリケーションを変更する必要があります。
最後の注意
これでファイルに対してデータ型をチェックできるようになったので、無効なデータを処理できるようにアプリケーションを変更する必要があります。
WRITE の ON ERROR 分岐は、トリガーによって書き込みが回避された時に使われます。この分岐を使ってエラーを処理し、適切なアクションを取るようなコードを作成する必要があります。
ダウンロード | 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|
| U2 basic code and schema file | udtExample.zip | 4KB | HTTP |
|---|
参考文献 学ぶために
製品や技術を入手するために
議論するために
著者について  | 
|  | Michael Rajkowski は IBM の U2 Client Support Group のソフトウェア・エンジニアです。彼は MultiValued データベースに 20 年以上の経験を持っています。彼は NYIT でコンピューター・サイエンスの学位を、また Dowling College で MBA (専門分野は総合品質管理) を取得しています。 |
記事の評価
|