Natural のシンプルな XML パーサー

次のトピックについて説明します。


パーサーの説明と例

Natural のシンプルな XML パーサーでは、標準の Natural プログラムを使用して XML ドキュメントを解析できます。 パーサーは、ドキュメントの次の部分が解析されると、イベントを送信するか、内部サブルーチンのコールバックを実行します。 インラインサブルーチンの "CALLBACK" は、xpath 同様の構文に現在の要素、テキスト、コメントの名前を指定して呼び出されます。 パーサーエンジンは、コピーコード "PARSER_X" として組み込まれます。 解析中に、ドキュメント形式が無効などのエラーが発生すると、"PARSER_ERROR" インラインサブルーチンが呼び出され、パーサーは "ESCAPE SUBROUTINE" でキャンセルされます(「パーサーの制限事項」も参照)。

オペランド 6 のエラーメッセージテキストとオペランド 7 のエラー番号の値を -9000 以下に変更することによって、エラー処理を拡張できます。 これにより、"PARSER_ERROR" インラインサブルーチンが呼び出され、(サブ)プログラムは "ESCAPE SUBROUTINE" でキャンセルされます。 他の値が -8000 以下の場合は、パーサーのみが "ESCAPE SUBROUTINE" でキャンセルされます。

パーサーの主な変数は、ローカルデータエリア "PARSER-X" で定義されます。

パーサーコピーコードでは、次のオペランドを使用します。

オペランド フォーマット/長さ 説明
1 A 解析される XML ファイル
2 A 要素構造を表す ex-XPATH
3 A1

XPATH の内容のタイプ:

? 処理命令
D DOCTYPE
! コメント
C CDATA セクション
T 開始タグ
@ 属性
/ 終了タグ
4 A 解析されたデータ
5 L 解析されたデータが空の場合、TRUE
6 A エラーメッセージのテキスト
7 I4 エラー番号

XPATH データの戻り値:

ex-Xpath XML 構造
? <? ... ?>
!DOCTYPE <!DOCTYPE ... >
!DOCTYPE[ <!DOCTYPE .. [...]>
![CDATA[ <![CDATA[ ... ]]>
!-- <!-- -->
! <! .. >
doc <doc>

doc
doc/foo
doc/foo/$
doc/foo//
doc//

<doc><foo>text</foo></doc>

doc
doc/@a1
doc//

<doc a1="a" />

doc
doc/@a1
doc/@a2
doc/$
doc//

<doc a1="a" a2="b">text</doc>

doc
doc/$
doc/foo
doc/foo/$
doc/foo//
doc/$
doc//

<doc>

<foo>text</foo>



</doc>

doc
doc/![CDATA[
doc//

<doc><![CDATA[ ... ]]></doc>

doc
doc/!--
doc//

<doc><!-- ... --></doc>

プログラム例:

* ----------------------------------------------------------------------
* CLASS  NATURAL XML TOOLKIT - UTILITIES
*
*         PARSER
*
* DESCRIPTION
*               Parse given XML
*
*
* AUTHOR        SAG   01.2006
*
* VERSION       6.2.
*
* (c) Copyright Software AG 2006. All rights reserved.
*
* ----------------------------------------------------------------------
*
DEFINE DATA LOCAL
1 XML_PARSER_INPUT             (A) DYNAMIC
1 XML_PARSER_ERROR_TEXT        (A253)
1 XML_PARSER_RESPONSE          (I4)
LOCAL USING PARSER-X           /* parser internal data - do not change
LOCAL
1 XML_PARSER_XPATH             (A) DYNAMIC
1 XML_PARSER_XPATH_TYPE        (A1)
1 XML_PARSER_CONTENT           (A) DYNAMIC
1 XML_PARSER_CONTENT_IS_EMPTY  (L)
*
1 ANFANG                       (T)
* OUT                          (A) DYNAMIC
1 OUT                          (A126)
*
END-DEFINE
*
FORMAT (0) LS=128 PS=40
*
DEFINE WORK FILE 12 "E:\EMPLOYEE1.XML" TYPE "UNFORMATTED"
READ WORK FILE 12 XML_PARSER_INPUT
END-WORK
CLOSE WORK FILE 12
*
*
* ------------------------------------------------- INCLUDE THE PARSER
INCLUDE PARSER_X 'XML_PARSER_INPUT' /* XML file to be parsed
  'XML_PARSER_XPATH'                /* XPATH to represent element...
  'XML_PARSER_XPATH_TYPE'           /* Type of callback
  'XML_PARSER_CONTENT'              /* Content of element found 
  'XML_PARSER_CONTENT_IS_EMPTY'     /* Is TRUE if element is empty
  'XML_PARSER_ERROR_TEXT'           /* error Message
  'XML_PARSER_RESPONSE'             /* Error NR; 0 = OK
*
*
DEFINE SUBROUTINE CALLBACK
IF XML_PARSER_CONTENT_IS_EMPTY THEN
  IF XML_PARSER_XPATH_TYPE NE "T" AND XML_PARSER_XPATH_TYPE NE "/" THEN
    COMPRESS XML_PARSER_XPATH "(NULL)" INTO OUT WITH DELIMITER "="
  ELSE
    OUT := XML_PARSER_XPATH
  END-IF
ELSE
  COMPRESS XML_PARSER_XPATH XML_PARSER_CONTENT INTO OUT WITH DELIMITER "="
END-IF
WRITE OUT
END-SUBROUTINE
/*
DEFINE SUBROUTINE PARSER_ERROR
OUT := XML_PARSER_ERROR_TEXT
WRITE OUT
END-SUBROUTINE
END

Employee データに対する Tamino からの結果ドキュメントでは、このプログラムの結果は次のようになります。

<?xml version="1.0" encoding="ISO-8859-1" ?>
<Employee xmlns:ino="http://namespaces.softwareag.com/tamino/response2" ino:id="560"
Personnel-ID="20006900">
<Full-Name>
<First-Name>JOE</First-Name>
<Name>ATHERTON</Name>
</Full-Name>
<Mar-Stat>S</Mar-Stat>
<Sex>M</Sex>
<Birth>1941-02-21</Birth>
<Full-Address>
<Address-Line>11603 HUNTERS GREEN</Address-Line>
<Address-Line>SYRACUSE</Address-Line>
<Address-Line>NY</Address-Line>
<City>SYRACUSE</City>
<Zip>13201</Zip>
<Post-Code>13201</Post-Code>
<Country>USA</Country>
</Full-Address>
<Telephone>
<Phone>173-9859</Phone>
<Area-Code>315</Area-Code>
</Telephone>
<Dept>TECH10</Dept>
<Job-Title>ANALYST</Job-Title>
<Income>
<Curr-Code>USD</Curr-Code>
<Salary>43000</Salary>
</Income>
<Income>
<Curr-Code>USD</Curr-Code>
<Salary>39500</Salary>
</Income>
<Income>
<Curr-Code>USD</Curr-Code>
<Salary>36700</Salary>
</Income>
<Income>
<Curr-Code>USD</Curr-Code>
<Salary>34400</Salary>
</Income>
<Income>
<Curr-Code>USD</Curr-Code>
<Salary>32600</Salary>
</Income>
<Leave-Data>
<Leave-Due>19</Leave-Due>
<Leave-Taken>4</Leave-Taken>
</Leave-Data>
<Leave-Booked>
<Leave-Start>19980112</Leave-Start>
<Leave-End>19980112</Leave-End>
</Leave-Booked>
<Leave-Booked>
<Leave-Start>19980605</Leave-Start>
<Leave-End>19980605</Leave-End>
</Leave-Booked>
<Leave-Booked>
<Leave-Start>19980916</Leave-Start>
<Leave-End>19980916</Leave-End>
</Leave-Booked>
<Lang>ENG</Lang>
</Employee>

注意:
ドキュメント全体に改行はありません。

上記の Natural プログラムの結果は次のようになります。

?=xml version="1.0" encoding="ISO-8859-1"
Employee
Employee/@xmlns:ino=http://namespaces.softwareag.com/tamino/response2
Employee/@ino:id=560
Employee/@Personnel-ID=20006900
Employee/Full-Name
Employee/Full-Name/First-Name
Employee/Full-Name/First-Name/$=JOE
Employee/Full-Name/First-Name//
Employee/Full-Name/Name
Employee/Full-Name/Name/$=ATHERTON
Employee/Full-Name/Name//
Employee/Full-Name//
Employee/Mar-Stat
Employee/Mar-Stat/$=S
Employee/Mar-Stat//
Employee/Sex
Employee/Sex/$=M
Employee/Sex//
Employee/Birth
Employee/Birth/$=1941-02-21
Employee/Birth//
Employee/Full-Address
Employee/Full-Address/Address-Line
Employee/Full-Address/Address-Line/$=11603 HUNTERS GREEN
Employee/Full-Address/Address-Line//
Employee/Full-Address/Address-Line
Employee/Full-Address/Address-Line/$=SYRACUSE
Employee/Full-Address/Address-Line//
Employee/Full-Address/Address-Line
Employee/Full-Address/Address-Line/$=NY
Employee/Full-Address/Address-Line//
Employee/Full-Address/City
Employee/Full-Address/City/$=SYRACUSE
Employee/Full-Address/City//
Employee/Full-Address/Zip
Employee/Full-Address/Zip/$=13201
Employee/Full-Address/Zip//
Employee/Full-Address/Post-Code
Employee/Full-Address/Post-Code/$=13201
Employee/Full-Address/Post-Code//
Employee/Full-Address/Country
Employee/Full-Address/Country/$=USA
Employee/Full-Address/Country//
Employee/Full-Address//
Employee/Telephone
Employee/Telephone/Phone
Employee/Telephone/Phone/$=173-9859
Employee/Telephone/Phone//
Employee/Telephone/Area-Code
Employee/Telephone/Area-Code/$=315
Employee/Telephone/Area-Code//
Employee/Telephone//
Employee/Dept
Employee/Dept/$=TECH10
Employee/Dept//
Employee/Job-Title
Employee/Job-Title/$=ANALYST
Employee/Job-Title//
Employee/Income
Employee/Income/Curr-Code
Employee/Income/Curr-Code/$=USD
Employee/Income/Curr-Code//
Employee/Income/Salary
Employee/Income/Salary/$=43000
Employee/Income/Salary//
Employee/Income//
Employee/Income
Employee/Income/Curr-Code
Employee/Income/Curr-Code/$=USD
Employee/Income/Curr-Code//
Employee/Income/Salary
Employee/Income/Salary/$=39500
Employee/Income/Salary//
Employee/Income//
Employee/Income
Employee/Income/Curr-Code
Employee/Income/Curr-Code/$=USD
Employee/Income/Curr-Code//
Employee/Income/Salary
Employee/Income/Salary/$=36700
Employee/Income/Salary//
Employee/Income//
Employee/Income
Employee/Income/Curr-Code
Employee/Income/Curr-Code/$=USD
Employee/Income/Curr-Code//
Employee/Income/Salary
Employee/Income/Salary/$=34400
Employee/Income/Salary//
Employee/Income//
Employee/Income
Employee/Income/Curr-Code
Employee/Income/Curr-Code/$=USD
Employee/Income/Curr-Code//
Employee/Income/Salary
Employee/Income/Salary/$=32600
Employee/Income/Salary//
Employee/Income//
Employee/Leave-Data
Employee/Leave-Data/Leave-Due
Employee/Leave-Data/Leave-Due/$=19
Employee/Leave-Data/Leave-Due//
Employee/Leave-Data/Leave-Taken
Employee/Leave-Data/Leave-Taken/$=4
Employee/Leave-Data/Leave-Taken//
Employee/Leave-Data//
Employee/Leave-Booked
Employee/Leave-Booked/Leave-Start
Employee/Leave-Booked/Leave-Start/$=19980112
Employee/Leave-Booked/Leave-Start//
Employee/Leave-Booked/Leave-End
Employee/Leave-Booked/Leave-End/$=19980112
Employee/Leave-Booked/Leave-End//
Employee/Leave-Booked//
Employee/Leave-Booked
Employee/Leave-Booked/Leave-Start
Employee/Leave-Booked/Leave-Start/$=19980605
Employee/Leave-Booked/Leave-Start//
Employee/Leave-Booked/Leave-End
Employee/Leave-Booked/Leave-End/$=19980605
Employee/Leave-Booked/Leave-End//
Employee/Leave-Booked//
Employee/Leave-Booked
Employee/Leave-Booked/Leave-Start
Employee/Leave-Booked/Leave-Start/$=19980916
Employee/Leave-Booked/Leave-Start//
Employee/Leave-Booked/Leave-End
Employee/Leave-Booked/Leave-End/$=19980916
Employee/Leave-Booked/Leave-End//
Employee/Leave-Booked//
Employee/Lang
Employee/Lang/$=ENG
Employee/Lang//
Employee//

パーサーの制限事項

パーサーでは、以下は処理されません。

  • タグの合成(処理命令を含む)。 開始タグのみは終了タグと一致する必要があります(処理命令を含む)。

    例:

    <.doc></.doc> <!-- invalid character in tag -->
    <doc><? ?></doc> <!-- invalid whitespace -->
    <doc>&#RE;</doc> <!-- invalid character in tag -->
    
  • 文字またはエンティティの参照

    例:

    <doc>& no refc</doc> <!-- missing semicolon --> <doc a1=v1></doc>
    <!-- string literal expected -->
    
  • CDATA セクションの正確な処理

    例:

    <doc><![CDATA [ stuff]]></doc> <!-- must be CDATA[ -->
    
  • エンティティ/処理命令の内容

    例:

    <doc>]]></doc> <!-- ]] not allowed -->
  • タグ/属性の数

  • ヘッダー情報

  • Unicode 文字セット(ISO-8859-1 をサポート)