The following examples are included:
Using the XML Toolkit, a copycode can be generated that can be used to convert a Natural group structure into an XML document.
The callback copycode takes the following operands:
Operand | Format/Length | Description | from PARSER-X | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | A | ex-XPATH to represent element structure | operand2 | ||||||||||||||
2 | A1 |
Type of the XPATH content:
|
operand3 | ||||||||||||||
3 | A | Parsed Data | operand4 | ||||||||||||||
4 | L | Is TRUE if Parsed Data is empty | operand5 | ||||||||||||||
5 | I4 | Counter Variable 1st Dimension | |||||||||||||||
6 | I4 | Counter Variable 2nd Dimension | |||||||||||||||
7 | I4 | Counter Variable 3rd Dimension |
* ---------------------------------------------------------------------- * Parameter Definition * * &1& 'XML' /* XML Document * &2& '#CX' /* Counter Variable 1st Dimension * &3& '#CY' /* Counter Variable 2nd Dimension * &4& '#CZ' /* Counter Variable 3rd Dimension * ---------------------------------------------------------------------- * DTD E-\SAG\nat\NATAPPS\FUSER\XMLTK\RES\empl.dtd COMPRESS &1& '<EMPLOYEE' ' PERSONNEL-ID="'EMPLOYEE.PERSONNEL-ID '"' '>' INTO &1& LEAVING NO /* now the children COMPRESS &1& '<FULL-NAME' '>' INTO &1& LEAVING NO /* now the children COMPRESS &1& '<FIRST-NAME' '>' EMPLOYEE.FIRST-NAME '</FIRST-NAME>' INTO &1& LEAVING NO COMPRESS &1& '<NAME' '>' EMPLOYEE.NAME '</NAME>' INTO &1& LEAVING NO /* COMPRESS &1& '</FULL-NAME>' INTO &1& LEAVING NO COMPRESS &1& '<FULL-ADDRESS' '>' INTO &1& LEAVING NO /* now the children FOR &2& = 1 TO EMPLOYEE.C@ADDRESS-LINE COMPRESS &1& '<ADDRESS-LINE' '>' EMPLOYEE.ADDRESS-LINE(&2&) '</ADDRESS-LINE>' INTO &1& LEAVING NO END-FOR COMPRESS &1& '<CITY' '>' EMPLOYEE.CITY '</CITY>' INTO &1& LEAVING NO COMPRESS &1& '<ZIP' '>' EMPLOYEE.ZIP '</ZIP>' INTO &1& LEAVING NO COMPRESS &1& '<COUNTRY' '>' EMPLOYEE.COUNTRY '</COUNTRY>' INTO &1& LEAVING NO /* COMPRESS &1& '</FULL-ADDRESS>' INTO &1& LEAVING NO COMPRESS &1& '<TELEPHONE' '>' INTO &1& LEAVING NO /* now the children COMPRESS &1& '<PHONE' '>' EMPLOYEE.PHONE '</PHONE>' INTO &1& LEAVING NO COMPRESS &1& '<AREA-CODE' '>' EMPLOYEE.AREA-CODE '</AREA-CODE>' INTO &1& LEAVING NO /* COMPRESS &1& '</TELEPHONE>' INTO &1& LEAVING NO COMPRESS &1& '<JOB-TITLE' '>' EMPLOYEE.JOB-TITLE '</JOB-TITLE>' INTO &1& LEAVING NO FOR &2& = 1 TO EMPLOYEE.C@INCOME COMPRESS &1& '<INCOME' '>' INTO &1& LEAVING NO /* now the children COMPRESS &1& '<SALARY' '>' EMPLOYEE.SALARY(&2&) '</SALARY>' INTO &1& LEAVING NO FOR &3& = 1 TO EMPLOYEE.C@BONUS(&2&) COMPRESS &1& '<BONUS' '>' EMPLOYEE.BONUS(&2&,&3&) '</BONUS>' INTO &1& LEAVING NO END-FOR /* COMPRESS &1& '</INCOME>' INTO &1& LEAVING NO END-FOR /* COMPRESS &1& '</EMPLOYEE>' INTO &1& LEAVING NO
<?xml version="1.0" encoding="ISO-8859-1"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="EMPLOYEE"> <xs:complexType> <xs:sequence> <xs:element ref="FULL-NAME"/> <xs:element ref="FULL-ADDRESS"/> <xs:element ref="TELEPHONE"/> <xs:element ref="JOB-TITLE"/> <xs:element ref="INCOME" minOccurs="0" maxOccurs="6"/> </xs:sequence> <xs:attribute name="PERSONNEL-ID" use="optional"> <xs:simpleType> <xs:restriction base="xs:string"/> </xs:simpleType> </xs:attribute> </xs:complexType> </xs:element> <xs:element name="FULL-NAME"> <xs:complexType> <xs:sequence> <xs:element ref="FIRST-NAME"/> <xs:element ref="NAME"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="FIRST-NAME"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="20"/> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="NAME"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="20"/> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="FULL-ADDRESS"> <xs:complexType> <xs:sequence> <xs:element ref="ADDRESS-LINE" minOccurs="0" maxOccurs="6"/> <xs:element ref="CITY"/> <xs:element ref="ZIP"/> <xs:element ref="COUNTRY"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="ADDRESS-LINE"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="20"/> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="CITY"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="20"/> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="ZIP"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="20"/> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="COUNTRY"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="3"/> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="TELEPHONE"> <xs:complexType> <xs:sequence> <xs:element ref="AREA-CODE"/> <xs:element ref="PHONE"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="AREA-CODE"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="6"/> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="PHONE"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="15"/> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="JOB-TITLE"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="25"/> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="INCOME"> <xs:complexType> <xs:sequence> <xs:element ref="SALARY"/> <xs:element ref="BONUS" minOccurs="0" maxOccurs="4"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="SALARY"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="9"/> </xs:restriction> </xs:simpleType> </xs:element> <xs:element name="BONUS"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:maxLength value="9"/> </xs:restriction> </xs:simpleType> </xs:element> </xs:schema>
DEFINE DATA PARAMETER 1 EMPLOYEE 2 ATTRIBUTES_OF_EMPLOYEE 3 PERSONNEL-ID(A8) * 2 FULL-NAME 3 FIRST-NAME(A20) 3 NAME(A20) * 2 FULL-ADDRESS 3 C@ADDRESS-LINE(I4) 3 ADDRESS-LINE(A20/1:6) 3 CITY(A20) 3 ZIP(A20) 3 COUNTRY(A3) * 2 TELEPHONE 3 AREA-CODE(A6) 3 PHONE(A15) * 2 JOB-TITLE(A25) * 2 C@INCOME(I4) 2 INCOME(1:6) 3 SALARY(A9) 3 C@BONUS(I4) 3 BONUS(A9/1:4) END-DEFINE
Using the XML Toolkit, a subroutine can be generated that can be used to convert a Natural group structure into an XML Schema.
* ---------------------------------------------------------------------- * Generated from NATURAL XML TOOLKIT * * 'EMPLP' * * DESCRIPTION * XML Parser implementation * using PARSE XML statement for * datastructure 'EMPL' * * ---------------------------------------------------------------------- * DEFINE DATA PARAMETER 1 #XML_INPUT (A) DYNAMIC BY VALUE PARAMETER USING EMPL * LOCAL 1 #XML_PATH (A) DYNAMIC 1 #XML_VALUE (A) DYNAMIC * LOCAL 1 #CX (I4) 1 #CY (I4) 1 #CZ (I4) END-DEFINE * * ------------------------------------------------- INCLUDE THE PARSER PARSE XML #XML_INPUT INTO PATH #XML_PATH VALUE #XML_VALUE * * DTD SYSEXXT EMPL DECIDE ON FIRST #XML_PATH VALUE 'EMPLOYEE' RESET EMPLOYEE VALUE 'EMPLOYEE/@PERSONNEL-ID' /* #IMPLIED EMPLOYEE.PERSONNEL-ID := #XML_VALUE VALUE 'EMPLOYEE/FULL-NAME' IGNORE VALUE 'EMPLOYEE/FULL-NAME/FIRST-NAME' IGNORE VALUE 'EMPLOYEE/FULL-NAME/FIRST-NAME/$' EMPLOYEE.FIRST-NAME := #XML_VALUE VALUE 'EMPLOYEE/FULL-NAME/NAME' IGNORE VALUE 'EMPLOYEE/FULL-NAME/NAME/$' EMPLOYEE.NAME := #XML_VALUE VALUE 'EMPLOYEE/FULL-ADDRESS' IGNORE VALUE 'EMPLOYEE/FULL-ADDRESS/ADDRESS-LINE' /* optional multiple ADD 1 TO EMPLOYEE.C@ADDRESS-LINE EXPAND ARRAY EMPLOYEE.ADDRESS-LINE TO (1:EMPLOYEE.C@ADDRESS-LINE) VALUE 'EMPLOYEE/FULL-ADDRESS/ADDRESS-LINE/$' #CX := EMPLOYEE.C@ADDRESS-LINE EMPLOYEE.ADDRESS-LINE(#CX) := #XML_VALUE VALUE 'EMPLOYEE/FULL-ADDRESS/CITY' IGNORE VALUE 'EMPLOYEE/FULL-ADDRESS/CITY/$' EMPLOYEE.CITY := #XML_VALUE VALUE 'EMPLOYEE/FULL-ADDRESS/ZIP' IGNORE VALUE 'EMPLOYEE/FULL-ADDRESS/ZIP/$' EMPLOYEE.ZIP := #XML_VALUE VALUE 'EMPLOYEE/FULL-ADDRESS/COUNTRY' IGNORE VALUE 'EMPLOYEE/FULL-ADDRESS/COUNTRY/$' EMPLOYEE.COUNTRY := #XML_VALUE VALUE 'EMPLOYEE/TELEPHONE' IGNORE VALUE 'EMPLOYEE/TELEPHONE/AREA-CODE' IGNORE VALUE 'EMPLOYEE/TELEPHONE/AREA-CODE/$' EMPLOYEE.AREA-CODE := #XML_VALUE VALUE 'EMPLOYEE/TELEPHONE/PHONE' IGNORE VALUE 'EMPLOYEE/TELEPHONE/PHONE/$' EMPLOYEE.PHONE := #XML_VALUE VALUE 'EMPLOYEE/JOB-TITLE' IGNORE VALUE 'EMPLOYEE/JOB-TITLE/$' EMPLOYEE.JOB-TITLE := #XML_VALUE VALUE 'EMPLOYEE/INCOME' /* optional multiple ADD 1 TO EMPLOYEE.C@INCOME EXPAND ARRAY EMPLOYEE.INCOME TO (1:EMPLOYEE.C@INCOME) VALUE 'EMPLOYEE/INCOME/SALARY' IGNORE VALUE 'EMPLOYEE/INCOME/SALARY/$' #CX := EMPLOYEE.C@INCOME EMPLOYEE.SALARY(#CX) := #XML_VALUE VALUE 'EMPLOYEE/INCOME/BONUS' /* optional multiple #CX := EMPLOYEE.C@INCOME ADD 1 TO EMPLOYEE.C@BONUS(#CX) EXPAND ARRAY EMPLOYEE.BONUS TO (*:*,1:EMPLOYEE.C@BONUS(#CX)) VALUE 'EMPLOYEE/INCOME/BONUS/$' #CX := EMPLOYEE.C@INCOME #CY := EMPLOYEE.C@BONUS(#CX) EMPLOYEE.BONUS(#CX,#CY) := #XML_VALUE NONE IGNORE END-DECIDE * END-PARSE * END
* ---------------------------------------------------------------------- * Generated from NATURAL XML TOOLKIT * * 'EMPL2S' * * DESCRIPTION * XML serialize implementation for * 'EMPL' datastructure * * ---------------------------------------------------------------------- * DEFINE DATA PARAMETER 1 #XML_SERIALZE_OUTPUT (A) DYNAMIC PARAMETER USING EMPL LOCAL 1 #CX (I4) 1 #CY (I4) 1 #CZ (I4) END-DEFINE * #XML_SERIALZE_OUTPUT := '<?xml version="1.0" encoding="ISO-8859-1"?>' * * DTD SYSEXXT EMPL COMPRESS #XML_SERIALZE_OUTPUT '<EMPLOYEE' ' PERSONNEL-ID="'EMPLOYEE.PERSONNEL-ID '"' '>' INTO #XML_SERIALZE_OUTPUT LEAVING NO /* now the children COMPRESS #XML_SERIALZE_OUTPUT '<FULL-NAME' '>' INTO #XML_SERIALZE_OUTPUT LEAVING NO /* now the children COMPRESS #XML_SERIALZE_OUTPUT '<FIRST-NAME' '>' EMPLOYEE.FIRST-NAME '</FIRST-NAME>' INTO #XML_SERIALZE_OUTPUT LEAVING NO COMPRESS #XML_SERIALZE_OUTPUT '<NAME' '>' EMPLOYEE.NAME '</NAME>' INTO #XML_SERIALZE_OUTPUT LEAVING NO /* COMPRESS #XML_SERIALZE_OUTPUT '</FULL-NAME>' INTO #XML_SERIALZE_OUTPUT LEAVING NO COMPRESS #XML_SERIALZE_OUTPUT '<FULL-ADDRESS' '>' INTO #XML_SERIALZE_OUTPUT LEAVING NO /* now the children FOR #CX = 1 TO EMPLOYEE.C@ADDRESS-LINE COMPRESS #XML_SERIALZE_OUTPUT '<ADDRESS-LINE' '>' EMPLOYEE.ADDRESS-LINE(#CX) '</ADDRESS-LINE>' INTO #XML_SERIALZE_OUTPUT LEAVING NO END-FOR COMPRESS #XML_SERIALZE_OUTPUT '<CITY' '>' EMPLOYEE.CITY '</CITY>' INTO #XML_SERIALZE_OUTPUT LEAVING NO COMPRESS #XML_SERIALZE_OUTPUT '<ZIP' '>' EMPLOYEE.ZIP '</ZIP>' INTO #XML_SERIALZE_OUTPUT LEAVING NO COMPRESS #XML_SERIALZE_OUTPUT '<COUNTRY' '>' EMPLOYEE.COUNTRY '</COUNTRY>' INTO #XML_SERIALZE_OUTPUT LEAVING NO /* COMPRESS #XML_SERIALZE_OUTPUT '</FULL-ADDRESS>' INTO #XML_SERIALZE_OUTPUT LEAVING NO COMPRESS #XML_SERIALZE_OUTPUT '<TELEPHONE' '>' INTO #XML_SERIALZE_OUTPUT LEAVING NO /* now the children COMPRESS #XML_SERIALZE_OUTPUT '<AREA-CODE' '>' EMPLOYEE.AREA-CODE '</AREA-CODE>' INTO #XML_SERIALZE_OUTPUT LEAVING NO COMPRESS #XML_SERIALZE_OUTPUT '<PHONE' '>' EMPLOYEE.PHONE '</PHONE>' INTO #XML_SERIALZE_OUTPUT LEAVING NO /* COMPRESS #XML_SERIALZE_OUTPUT '</TELEPHONE>' INTO #XML_SERIALZE_OUTPUT LEAVING NO COMPRESS #XML_SERIALZE_OUTPUT '<JOB-TITLE' '>' EMPLOYEE.JOB-TITLE '</JOB-TITLE>' INTO #XML_SERIALZE_OUTPUT LEAVING NO FOR #CX = 1 TO EMPLOYEE.C@INCOME COMPRESS #XML_SERIALZE_OUTPUT '<INCOME' '>' INTO #XML_SERIALZE_OUTPUT LEAVING NO /* now the children COMPRESS #XML_SERIALZE_OUTPUT '<SALARY' '>' EMPLOYEE.SALARY(#CX) '</SALARY>' INTO #XML_SERIALZE_OUTPUT LEAVING NO FOR #CY = 1 TO EMPLOYEE.C@BONUS(#CX) COMPRESS #XML_SERIALZE_OUTPUT '<BONUS' '>' EMPLOYEE.BONUS(#CX,#CY) '</BONUS>' INTO #XML_SERIALZE_OUTPUT LEAVING NO END-FOR /* COMPRESS #XML_SERIALZE_OUTPUT '</INCOME>' INTO #XML_SERIALZE_OUTPUT LEAVING NO END-FOR /* COMPRESS #XML_SERIALZE_OUTPUT '</EMPLOYEE>' INTO #XML_SERIALZE_OUTPUT LEAVING NO END
* ---------------------------------------------------------------------- * CLASS NATURAL XML TOOLKIT * * * DESCRIPTION * Serialize a given Data structure. * * * AUTHOR SAG * * * (c) Copyright Software AG. All rights reserved. * * ---------------------------------------------------------------------- * DEFINE DATA LOCAL USING EMPL /* add generated data structure LOCAL 1 XML (A) DYNAMIC * 1 OUT (A72) 1 II (I4) * 1 OUTDYN (A) DYNAMIC 1 OBJLEN (I4) 1 OBJEND (I4) 1 OBJSTART (I4) 1 OBJLINE (I4) * 1 #CX (I4) 1 #CY (I4) 1 #CZ (I4) END-DEFINE * EMPLOYEE.PERSONNEL-ID := 4711 * EMPLOYEE.FIRST-NAME := "ADKINSON" EMPLOYEE.NAME := "MARTHA" * EMPLOYEE.C@ADDRESS-LINE := 2 EMPLOYEE.ADDRESS-LINE(1) := "8603 GARLAND COURT" EMPLOYEE.ADDRESS-LINE(2) := "FRAMINGHAM" EMPLOYEE.ADDRESS-LINE(2) := "MA" EMPLOYEE.CITY := "FRAMINGHAM" EMPLOYEE.ZIP := "17010" EMPLOYEE.COUNTRY := "USA" * EMPLOYEE.AREA-CODE := "617" EMPLOYEE.PHONE := "210-4703" * EMPLOYEE.JOB-TITLE := "MANAGER" EMPLOYEE.C@INCOME := 2 EMPLOYEE.SALARY(1) := 47000 EMPLOYEE.C@BONUS(1) := 2 EMPLOYEE.BONUS(1,1) := 10500 EMPLOYEE.BONUS(1,2) := 7875 * EMPLOYEE.SALARY(2) := 47000 EMPLOYEE.C@BONUS(2) := 1 EMPLOYEE.BONUS(2,1) := 35700 * INCLUDE EMPL-C "XML" "#CX" "#CY" "#CZ" /* add generated Serialize * FOR II = 1 TO *LENGTH(XML) STEP 72 OUT := SUBSTR(XML,II) WRITE OUT END-FOR * NEWPAGE * /* WRITE COMPLETE (A) DYNAMIC VARIABLE IF POSSIBLE USE CR AND IGNORE LF OBJSTART := 1 * EXAMINE xml FOR "><" REPLACE WITH ">" - H'0A' -"<" EXAMINE xml FOR H'0A' GIVING POSITION OBJEND * REPEAT WHILE OBJEND NE 0 /* IF OBJSTART GT 0 THEN ADD OBJSTART TO OBJEND END-IF /* OBJLEN := OBJEND - OBJSTART -1 /* IF OBJLEN > 0 THEN OUTDYN := SUBSTRING(xml, OBJSTART, OBJLEN) /* FOR OBJLINE = 1 TO *LENGTH(OUTDYN) STEP 72 OUT := SUBSTR (OUTDYN,OBJLINE) WRITE OUT END-FOR ELSE WRITE " " END-IF /* OBJSTART := OBJEND IF OBJSTART GT *LENGTH(xml) ESCAPE BOTTOM END-IF /* EXAMINE SUBSTRING(xml,OBJSTART) FOR H'0A' GIVING POSITION OBJEND END-REPEAT * END
DEFINE DATA PARAMETER 1 EMPLOYEE 2 ATTRIBUTES_OF_EMPLOYEE 3 PERSONNEL-ID(A8) * 2 FULL-NAME 3 FIRST-NAME(A20) 3 NAME(A20) * 2 FULL-ADDRESS 3 C@ADDRESS-LINE(I4) 3 ADDRESS-LINE(A20/1:*) 3 CITY(A20) 3 ZIP(A20) 3 COUNTRY(A3) * 2 TELEPHONE 3 AREA-CODE(A6) 3 PHONE(A15) * 2 JOB-TITLE(A25) * 2 C@INCOME(I4) 2 INCOME(1:*) 3 SALARY(A9) 3 C@BONUS(I4) 3 BONUS(A9/1:*) END-DEFINE
Using the XML Toolkit, a Natural Data Area, or more precisely a Local Data Area, Parameter Data Area or Global Data Area, can be generated that represents a given Document Type Definition.
Generation Rules:
Each Empty Element without Attributes (<!ELEMENT br EMPTY>) is generated as a Natural variable of Type B1. This is necessary, because empty Natural groups are not allowed.
Each Empty Element with Attributes (<!ELEMENT br EMPTY><!ATTLIST br width CDATA #IMPLIED>) is generated as a Natural group.
Each Element with content (<!ELEMENT b (#PCDATA)> )is generated as a Natural variable of type A253.
Each Sequence of Elements (<!ELEMENT spec (front, body*, back?)>) or Choice of Elements (<!ELEMENT div1 (p | list | note)>) is generated as a Natural group.
Each clasped Sequence or Choice (<!ELEMENT address ( (street, housenumber), (zip, city) )>) is generated as a special group with the name prefix "##PSEUDO". This gives the possibility to represent the context or possible multiplicities.
Each Attribute (<!ATTLIST br width CDATA #IMPLIED>) of an Element is generated as variable of Type A253 belonging to a group with the name prefix "ATTRIBUTES_OF_" followed by the name of the element.
Multiple Elements are always generated as arrays of Dimension 1:v. The upper bound of the generated array has to be changed manually.
If an Element is defined multiple (<!ELEMENT spec (front, body*)>), an additional counter field C@BODY, is generated to specify the number of available elements.
All names used inside the DTD are converted into upper case, because Natural names are not case sensitive. Duplicate names inside a generated group will be a extended with an suffix to make the names unique.
Special Characters not valid for Natural names are converted into valid Natural names. For the conversion settings, see the option dialog of the XML Toolkit.
Elements with Mixed content data (<!ELEMENT p (#PCDATA | a | ul | b | i | em)*>) are not supported.
DTDs that result in Natural data structures can not be used within Natural, because Natural only supports data structures with a maximum of three dimensions.
<!ELEMENT EMPLOYEE (FULL-NAME , FULL-ADDRESS , TELEPHONE ,JOB-TITLE, INCOME* )> <!ATTLIST EMPLOYEE PERSONNEL-ID CDATA #REQUIRED > <!ELEMENT FULL-NAME (FIRST-NAME , NAME )> <!ELEMENT FIRST-NAME (#PCDATA )> <!ELEMENT NAME (#PCDATA )> <!ELEMENT FULL-ADDRESS (ADDRESS-LINE* , CITY , ZIP , COUNTRY )> <!ELEMENT ADDRESS-LINE (#PCDATA )> <!ELEMENT CITY (#PCDATA )> <!ELEMENT ZIP (#PCDATA )> <!ELEMENT COUNTRY (#PCDATA )> <!ELEMENT TELEPHONE (PHONE , AREA-CODE )> <!ELEMENT PHONE (#PCDATA )> <!ELEMENT AREA-CODE (#PCDATA )> <!ELEMENT JOB-TITLE (#PCDATA )> <!ELEMENT INCOME (SALARY , BONUS* )> <!ELEMENT SALARY (#PCDATA )> <!ELEMENT BONUS (#PCDATA )>
Generated Natural Data Area (italic written parts of the DTD, but necessary for Natural):
DEFINE DATA PARAMETER 1 EMPLOYEE 2 ATTRIBUTES_OF_EMPLOYEE 3 PERSONNEL-ID(A253) * 2 FULL-NAME 3 FIRST-NAME(A253) 3 NAME(A253) * 2 FULL-ADDRESS 3 C@ADDRESS-LINE(I4) 3 ADDRESS-LINE(A253/1:v) 3 CITY(A253) 3 ZIP(A253) 3 COUNTRY(A253) * 2 TELEPHONE 3 AREA-CODE(A253) 3 PHONE(A253) * 2 JOB-TITLE(A253) * 2 C@INCOME(I4) 2 INCOME(1:v) 3 SALARY(A253) 3 C@BONUS(I4) 3 BONUS(A253/1:v) END-DEFINE
Translation Rules:
Natural | Document Type Definiton |
---|---|
1 G1 |
<!ELEMENT G1 (E1)> |
1 G1 |
<!ELEMENT G1 (E1, E2, E3)> |
1 C@E1_MAX (I4) CONST <10> |
|
1 C@E1_MAX (I4) CONST <10> |
|
1 G1 |
<!ELEMENT G1 (E1?)> |
1 G1 |
<!ELEMENT G1 (E1| E2| E3)> |
1 G1 |
<!ELEMENT G1 (E1, E2, G2)> |
1 #G1 |
<!ELEMENT G1 (E1)> |
2 E1 (A…) |
<!ELEMENT E1 (#PCDATA)> |
Using the XML Toolkit, a Natural Data Area, or more precisely a Local Data Area, Parameter Data Area or Global Data Area, can be used to generate a Document Type Definition.
A Natural variable will result in an element with content.
A Natural group will result in a sequence of elements.
Multiple variables or groups will be generated with multiplicity "zero or more".
Special characters not valid for XML names are converted into valid names. For the conversion settings, see the options dialog of the XML Toolkit.
Example Natural Data Area:
DEFINE DATA LOCAL 1 NAT$EMPLOYEE 2 ATTRIBUTES_OF_NAT$EMPLOYEE 3 PERSONNEL/ID(A8) 2 C@MAN@WORK(I4) 2 MAN@WORK 3 JOB(A10) 2 A$TEST$MAKL(I4) 2 AS/FA/SD(P7.5) 2 #ASDFAS(F4) 2 ASF#AS(N9) 2 A-SF-D(A) Dynamic 2 INC@OME(1:6) 3 C@BONUS(I4) 3 BONUS(A9/1:4) END-DEFINE
<!-- DTD XMLTOOLS BEISP --> <!ELEMENT NATdollarEMPLOYEE ( MANatWORK , AdollarTESTdollarMAKL , ASslashFAslashSD , hashASDFAS , ASFhashAS , A-SF-D , INCatOME* ) > <!ATTLIST NATdollarEMPLOYEE PERSONNELslashID CDATA #IMPLIED > <!ELEMENT MANatWORK ( JOB ) > <!ELEMENT JOB (#PCDATA) > <!ELEMENT AdollarTESTdollarMAKL (#PCDATA) > <!ELEMENT ASslashFAslashSD (#PCDATA) > <!ELEMENT hashASDFAS (#PCDATA) > <!ELEMENT ASFhashAS (#PCDATA) > <!ELEMENT A-SF-D (#PCDATA) > <!ELEMENT INCatOME ( BONUS* ) > <!ELEMENT BONUS (#PCDATA) >
Using the XML Toolkit, a copycode can be generated that can be used with the Natural S imple XML Pars er.
The callback copycode takes the following operands:
Operand | Format/Length | Description | from PARSER-X | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | A | ex-XPATH to repesent element structure | operand2 | ||||||||||||||
2 | A1 |
Type of the XPATH content:
|
operand3 | ||||||||||||||
3 | A | Content of found element | operand4 | ||||||||||||||
4 | L | Is TRUE if Parsed Data is empty | operand5 | ||||||||||||||
5 | I4 | Counter Variable 1stDimension | |||||||||||||||
6 | I4 | Counter Variable 2nd Dimension | |||||||||||||||
7 | I4 | Counter Variable 3rd Dimension |
* ---------------------------------------------------------------------- * Paremeter Definition * * &1& 'XML_PARSER_XPATH' /* XPATH to repesent element... * &2& 'XML_PARSER_XPATH_TYPE' /* Type of the XPATH: * ? Processing instruction * D DOCTYPE * ! Comment * C CDATA section * T Starting Tag * @ Attribute * / Close Tag * $ Parsed Data * &3& 'XML_PARSER_CONTENT' /* Content of found element * &4& 'XML_PARSER_CONTENT_IS_EMPTY' /* Is TRUE if Content is empty * &5& '#CX' /* Counter Variable 1st Dimension * &6& '#CY' /* Counter Variable 2nd Dimension * &7& '#CZ' /* Counter Variable 3rd Dimension * ---------------------------------------------------------------------- * DECIDE ON FIRST &1& VALUE 'EMPLOYEE' RESET EMPLOYEE VALUE 'EMPLOYEE/@PERSONNEL-ID' /* #REQUIRED EMPLOYEE.PERSONNEL-ID := &3& VALUE 'EMPLOYEE/FULL-NAME' IGNORE VALUE 'EMPLOYEE/FULL-NAME/FIRST-NAME' IGNORE VALUE 'EMPLOYEE/FULL-NAME/FIRST-NAME/$' EMPLOYEE.FIRST-NAME := &3& VALUE 'EMPLOYEE/FULL-NAME/NAME' IGNORE VALUE 'EMPLOYEE/FULL-NAME/NAME/$' EMPLOYEE.NAME := &3& VALUE 'EMPLOYEE/FULL-ADDRESS' IGNORE VALUE 'EMPLOYEE/FULL-ADDRESS/ADDRESS-LINE' /* OPTIONAL MULTIPLE IST: 18 PARENT: FULL-ADDRESS ADD 1 TO EMPLOYEE.C@ADDRESS-LINE VALUE 'EMPLOYEE/FULL-ADDRESS/ADDRESS-LINE/$' &5& := EMPLOYEE.C@ADDRESS-LINE EMPLOYEE.ADDRESS-LINE(&5&) := &3& VALUE 'EMPLOYEE/FULL-ADDRESS/CITY' IGNORE VALUE 'EMPLOYEE/FULL-ADDRESS/CITY/$' EMPLOYEE.CITY := &3& VALUE 'EMPLOYEE/FULL-ADDRESS/ZIP' IGNORE VALUE 'EMPLOYEE/FULL-ADDRESS/ZIP/$' EMPLOYEE.ZIP := &3& VALUE 'EMPLOYEE/FULL-ADDRESS/COUNTRY' IGNORE VALUE 'EMPLOYEE/FULL-ADDRESS/COUNTRY/$' EMPLOYEE.COUNTRY := &3& VALUE 'EMPLOYEE/TELEPHONE' IGNORE VALUE 'EMPLOYEE/TELEPHONE/PHONE' IGNORE VALUE 'EMPLOYEE/TELEPHONE/PHONE/$' EMPLOYEE.PHONE := &3& VALUE 'EMPLOYEE/TELEPHONE/AREA-CODE' IGNORE VALUE 'EMPLOYEE/TELEPHONE/AREA-CODE/$' EMPLOYEE.AREA-CODE := &3& VALUE 'EMPLOYEE/JOB-TITLE' IGNORE VALUE 'EMPLOYEE/JOB-TITLE/$' EMPLOYEE.JOB-TITLE := &3& VALUE 'EMPLOYEE/INCOME' /* OPTIONAL MULTIPLE IST: 18 PARENT: EMPLOYEE ADD 1 TO EMPLOYEE.C@INCOME VALUE 'EMPLOYEE/INCOME/SALARY' IGNORE VALUE 'EMPLOYEE/INCOME/SALARY/$' &5& := EMPLOYEE.C@INCOME EMPLOYEE.SALARY(&5&) := &3& VALUE 'EMPLOYEE/INCOME/BONUS' /* OPTIONAL MULTIPLE IST: 18 PARENT: INCOME &5& := EMPLOYEE.C@INCOME ADD 1 TO EMPLOYEE.C@BONUS(&5&) VALUE 'EMPLOYEE/INCOME/BONUS/$' &5& := EMPLOYEE.C@INCOME &6& := EMPLOYEE.C@BONUS(&5&) EMPLOYEE.BONUS(&5&,&6&) := &3& NONE IGNORE END-DECIDE
* ---------------------------------------------------------------------- * CLASS NATURAL XML TOOLKIT - UTILITIES * * * DESCRIPTION * Parse a given XML document. * * * AUTHOR SAG * * * (c) Copyright Software AG. All rights reserved. * * ---------------------------------------------------------------------- * DEFINE DATA PARAMETER 1 XML_PARSER_INPUT (A) DYNAMIC PARAMETER USING EMPL PARAMETER 1 XML_PARSER_ERROR_TEXT (A253) 1 XML_PARSER_RESPONSE (I2) * LOCAL USING PARSER-X 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) * LOCAL 1 #CX (I4) 1 #CY (I4) 1 #CZ (I4) END-DEFINE * * ------------------------------------------------- INCLUDE THE PARSER INCLUDE PARSER_X 'XML_PARSER_INPUT' /* XML file to be parsed 'XML_PARSER_XPATH' /* XPATH to repesent element... 'XML_PARSER_XPATH_TYPE' /* Type of callback 'XML_PARSER_CONTENT' /* Content of founld element 'XML_PARSER_CONTENT_IS_EMPTY' /* Is TRUE if element is empty 'XML_PARSER_ERROR_TEXT' /* error Message 'XML_PARSER_RESPONSE' /* Error NR; 0 = OK * * --------------------------------------------------- CALLBACK HANDLER DEFINE SUBROUTINE CALLBACK * INCLUDE EMPL-P 'XML_PARSER_XPATH' /* XPATH to repesent element... 'XML_PARSER_XPATH_TYPE' /* Type of callback 'XML_PARSER_CONTENT' /* Content of founld element 'XML_PARSER_CONTENT_IS_EMPTY' /* Is TRUE if element is empty '#CX' '#CY' '#CZ' * END-SUBROUTINE /* DEFINE SUBROUTINE PARSER_ERROR IGNORE END-SUBROUTINE END
DEFINE DATA PARAMETER 1 EMPLOYEE 2 ATTRIBUTES_OF_EMPLOYEE 3 PERSONNEL-ID(A8) * 2 FULL-NAME 3 FIRST-NAME(A20) 3 NAME(A20) * 2 FULL-ADDRESS 3 C@ADDRESS-LINE(I4) 3 ADDRESS-LINE(A20/1:6) 3 CITY(A20) 3 ZIP(A20) 3 COUNTRY(A3) * 2 TELEPHONE 3 AREA-CODE(A6) 3 PHONE(A15) * 2 JOB-TITLE(A25) * 2 C@INCOME(I4) 2 INCOME(1:6) 3 SALARY(A9) 3 C@BONUS(I4) 3 BONUS(A9/1:4) END-DEFINE