The following example illustrates the use of the PLISAXD built-in subroutine and uses the example XML document and the XML schema cited in the previous examples.
This example includes the validation of 8 different XML files against the same stock.osr schema. In the following output, you can see which XML documents in the saxdtest program fail validation against the schema.
The PLISAXD built-in subroutine requires the XML schema file to be read into a buffer. The OSR file in the following example is in a PDS. The initial size of the OSR buffer is set to 4096. If you have a larger OSR file, you can increase the initial size of the OSR buffer accordingly.
If the inbound schema file were in an HFS file instead, you could use the following code to read the OSR file into the buffer:
dcl osrin file input stream environment(u); dcl fileddint builtin; dcl fileread builtin; /* Read the HFS OSR file into buffer*/ open file(osrin); osr_length = fileddint( osrin, 'filesize'); osr_ptr = allocate(osr_length); rc = fileread(osrin,osr_ptr,osr_length);
To run a program by using an OSR in a PDS, you can specify the following DD statement in the JCL:
//OSRIN DD DSN=HLQ.XML.OSR(STOCK),DISP=SHR
If the associated ddname OSRIN is an HFS file, then use the following JCL statement instead:
//OSRIN DD PATH="/u/HLQ/xml/stock.osr"
saxdtest: package exports(saxdtest);
/************************************************************/
/* saxdtest: Test PL/I XML validation support */
/* expected output: */
/* */
/* SAXDTEST: PL/I XML Validation sample */
/* SAXDTEST: Document Successfully parsed */
/* SAXDTEST: Document Successfully parsed */
/* Invalid: missing attribute itemNumber. */
/* exception return_code =00000018, reason_code =8613 */
/* Invalid: unexpected attribute warehouse. */
/* exception return_code =00000018, reason_code =8612 */
/* Invalid: illegal attribute value 123-Ab. */
/* exception return_code =00000018, reason_code =8809 */
/* Invalid: missing element quantityOnHand. */
/* exception return_code =00000018, reason_code =8611 */
/* Invalid: unexpected element comment. */
/* exception return_code =00000018, reason_code =8607 */
/* Invalid: out-of-range element value 100 */
/* exception return_code =00000018, reason_code =8803 */
/* */
/************************************************************/
define alias event
limited entry( pointer, pointer, fixed bin(31) )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
define alias event_with_flag
limited entry( pointer, pointer, fixed bin(31),
bit(8) aligned )
returns( byvalue fixed bin(31) )
options( nodescriptor byvalue linkage(optlink) );
define alias event_with_namespace
limited entry( pointer, pointer, fixed bin(31),
pointer, fixed bin(31),
pointer, fixed bin(31) )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
define alias event_without_data
limited entry( pointer )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
define alias event_pi
limited entry( pointer, pointer, fixed bin(31),
pointer, fixed bin(31) )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
define alias event_namespace_dcl
limited entry( pointer, pointer, fixed bin(31),
pointer, fixed bin(31) )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
define alias event_exception
limited entry( pointer, fixed bin(31),
fixed bin(31),
fixed bin(31) )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
define alias event_end_of_input
limited entry( pointer,
pointer byaddr,
fixed bin(31) byaddr )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
saxdtest: proc options( main );
dcl
1 eventHandler static
,2 e01 type event_without_data
init( start_of_document )
,2 e02 type event
init( version_information )
,2 e03 type event
init( encoding_declaration )
,2 e04 type event
init( standalone_declaration )
,2 e05 type event
init( document_type_declaration )
,2 e06 type event_without_data
init( end_of_document )
,2 e07 type event_with_namespace
init( start_of_element )
,2 e08 type event_with_namespace
init( attribute_name )
,2 e09 type event
init( attribute_characters )
,2 e10 type event_with_namespace
init( end_of_element )
,2 e11 type event_without_data
init( start_of_CDATA )
,2 e12 type event_without_data
init( end_of_CDATA )
,2 e13 type event_with_flag
init( content_characters )
,2 e14 type event_pi
init( processing_instruction )
,2 e15 type event
init( comment )
,2 e16 type event_namespace_dcl
init( namespace_declare )
,2 e17 type event_end_of_input
init( end_of_input )
,2 e18 type event
init( unresolved_reference )
,2 e19 type event_exception
init( exception )
;
dcl token char(45);
dcl rc fixed bin(31);
dcl i fixed bin(31);
dcl xml_document(8) char(300) var;
dcl xml_valid_msg(8) char(45) var;
dcl osr_ptr pointer;
dcl record char(80);
dcl osr_index fixed bin;
dcl osr_buf_tail fixed bin;
dcl temp_osr pointer;
dcl buf_size fixed bin(31) init(4096);
dcl rec_size fixed bin(31);
dcl osr_length fixed bin(31);
dcl buf_length fixed bin(31);
dcl eof fixed bin(31) init(0);
dcl osrin file input;
on endfile(osrin) begin;
eof = 1;
end;
/* read the entire PDS osr file into the buffer */
put skip list ('SAXDTEST: PL/I XML Validation sample ');
osr_length = buf_size;
osr_index = 0;
osr_buf_tail = 0;
rec_size = length(record);
osr_ptr = allocate(osr_length);
do while (eof = 0 );
read file(osrin) into(record);
osr_buf_tail += rec_size;
if osr_buf_tail > buf_size then
do;
buf_length = osr_length;
osr_length +=buf_size;
temp_osr = allocate(osr_length);
call plimove(temp_osr, osr_ptr, buf_length);
call plifree(osr_ptr);
osr_ptr = temp_osr;
osr_buf_tail = rec_size;
call plimove(osr_ptr+osr_index, addr(record), rec_size);
osr_index += rec_size;
end;
else
do;
call plimove(osr_ptr+osr_index, addr(record), rec_size);
osr_index +=rec_size;
end;
end;
/* Valid XMLFILE */
xml_document(1) = '<stockItem itemNumber="453-SR">'
|| '<itemName>Stainless steel rope thimbles</itemName>'
|| '<quantityOnHand>23</quantityOnHand>'
|| '</stockItem>';
xml_valid_msg(1) = 'Valid XMLFILE ';
/* Valid: the ITEMNAME element can be omitted */
xml_document(2) = '<stockItem itemNumber="453-SR">'
|| '<quantityOnHand>23</quantityOnHand>'
|| '</stockItem>';
xml_valid_msg(2) = 'Valid: the ITEMNAME element can be omitted.';
/* Invalid: missing attribute itemNumber */
xml_document(3) = '<stockItem>'
|| '<itemName>Stainless steel rope thimbles</itemName>'
|| '<quantityOnHand>23</quantityOnHand>'
|| '</stockItem>';
xml_valid_msg(3) = 'Invalid: missing attribute itemNumber.';
/* Invalid: unexpected attribute warehouse */
xml_document(4) = '<stockItem itemNumber="453-SR" warehouse="NY">'
|| '<itemName>Stainless steel rope thimbles</itemName>'
|| '<quantityOnHand>23</quantityOnHand>'
|| '</stockItem>';
xml_valid_msg4) = 'Invalid: unexpected attribute warehouse.';
/* Invalid: illegal attribute value 123-Ab */
xml_document(5) = '<stockItem itemNumber="123-Ab">'
|| '<itemName>Stainless steel rope thimbles</itemName>'
|| '<quantityOnHand>23</quantityOnHand>'
|| '</stockItem>';
xml_valid_msg(5) = 'Invalid: illegal attribute value 123-Ab.';
/* Invalid: missing element quantityOnHand */
xml_document(6) = '<stockItem itemNumber="074-UN">'
|| '<itemName>Stainless steel rope thimbles</itemName>'
|| '</stockItem>';
xml_valid_msg(6) = 'Invalid: missing element quantityOnHand.';
/* Invalid: unexpected element comment */
xml_document(7) = '<stockItem itemNumber="453-SR">'
|| '<itemName>Stainless steel rope thimbles</itemName>'
|| '<quantityOnHand>1</quantityOnHand>'
|| '<commnet>Nylon bristles</comment>'
|| '</stockItem>';
xml_valid_msg(7) = 'Invalid: unexpected element comment.';
/* Invalid: out-of-range element value 100 */
xml_document(8) = '<stockItem itemNumber="123-AB">'
|| '<itemName>Paintbrush</itemName>'
|| '<quantityOnHand>100</quantityOnHand>'
|| '</stockItem>';
xml_valid_msg(8) = 'Invalid: out-of-range element value 100';
do i = 1 to hbound(xml_document);; token = xml_valid_msg(i); call plisaxd( eventHandler, addr(token), addrdata(xml_document(i)), length(xml_document(i)), osr_ptr, 37 ); end; close file(osrin); call plifree(osr_ptr); end; start_of_document: proc( userToken ) returns( byvalue fixed bin(31) ) options( byvalue linkage(optlink) ); dcl userToken pointer; return(0); end; version_information: proc( userToken, xmlToken, TokenLength ) returns( byvalue fixed bin(31) ) options( byvalue linkage(optlink) ); dcl userToken pointer; dcl xmlToken pointer; dcl tokenLength fixed bin(31); return(0); end; encoding_declaration: proc( userToken, xmlToken, TokenLength ) returns( byvalue fixed bin(31) ) options( byvalue linkage(optlink) ); dcl userToken pointer; dcl xmlToken pointer; dcl tokenLength fixed bin(31); return(0); end; standalone_declaration: proc( userToken, xmlToken, TokenLength ) returns( byvalue fixed bin(31) ) options( byvalue linkage(optlink) ); dcl userToken pointer; dcl xmlToken pointer; dcl tokenLength fixed bin(31); return(0); end;
document_type_declaration:
proc( userToken, xmlToken, TokenLength )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
dcl userToken pointer;
dcl xmlToken pointer;
dcl tokenLength fixed bin(31);
return(0);
end;
end_of_document:
proc( userToken )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
dcl userToken pointer;
put skip list( 'SAXDTEST: Document Successfully parsed ');
return(0);
end;
start_of_element:
proc( userToken, xmlToken, TokenLength,
nsPrefix, nsPrefixLength,
nsUri, nsUriLength )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
dcl userToken pointer;
dcl xmlToken pointer;
dcl tokenLength fixed bin(31);
dcl nsPrefix pointer;
dcl nsPrefixLength fixed bin(31);
dcl nsUri pointer;
dcl nsUriLength fixed bin(31);
return(0);
end;
attribute_name:
proc( userToken, xmlToken, tokenLength,
nsPrefix, nsPrefixLength,
nsUri, nsUriLength )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
dcl userToken pointer;
dcl xmlToken pointer;
dcl tokenLength fixed bin(31);
dcl nsPrefix pointer;
dcl nsPrefixLength fixed bin(31);
dcl nsUri pointer;
dcl nsUriLength fixed bin(31);
return(0);
end;
attribute_characters:
proc( userToken, xmlToken, TokenLength )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
dcl userToken pointer;
dcl xmlToken pointer;
dcl tokenLength fixed bin(31);
return(0);
end;
end_of_element:
proc( userToken, xmlToken, TokenLength,
nsPrefix, nsPrefixLength,
nsUri, nsUriLength )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
dcl userToken pointer;
dcl xmlToken pointer;
dcl tokenLength fixed bin(31);
dcl nsPrefix pointer;
dcl nsPrefixLength fixed bin(31);
dcl nsUri pointer;
dcl nsUriLength fixed bin(31);
return(0);
end;
start_of_CDATA:
proc( userToken )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
dcl userToken pointer;
return(0);
end;
end_of_CDATA:
proc( userToken )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
dcl userToken pointer;
return(0);
end;
content_characters:
proc( userToken, xmlToken, TokenLength, flags )
returns( byvalue fixed bin(31) )
options( nodescriptor, byvalue linkage(optlink) );
dcl userToken pointer;
dcl xmlToken pointer;
dcl tokenLength fixed bin(31);
dcl flags bit(8) aligned;
if flags = ''b then;
else
return(0);
end;
processing_instruction:
proc( userToken, piTarget, piTargetLength,
piData, piDataLength )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
dcl userToken pointer;
dcl piTarget pointer;
dcl piTargetLength fixed bin(31);
dcl piData pointer;
dcl piDataLength fixed bin(31);
return(0);
end;
comment:
proc( userToken, xmlToken, TokenLength )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
dcl userToken pointer;
dcl xmlToken pointer;
dcl tokenLength fixed bin(31);
return(0);
end;
namespace_declare:
proc( userToken, nsPrefix, nsPrefixLength,
nsUri, nsUriLength )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
dcl userToken pointer;
dcl nsPrefix pointer;
dcl nsPrefixLength fixed bin(31);
dcl nsUri pointer;
dcl nsUriLength fixed bin(31);
return(0);
end;
unresolved_reference:
proc( userToken, xmlToken, TokenLength )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
dcl userToken pointer;
dcl xmlToken pointer;
dcl tokenLength fixed bin(31);
return(0);
end;
exception:
proc( userToken, currentOffset, return_code, reason_code )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
dcl userToken pointer;
dcl currentOffset fixed bin(31);
dcl return_code fixed bin(31);
dcl reason_code fixed bin(31);
dcl validmsg char(45) based;
put skip list( userToken -> validmsg);
put skip list( lowercase( procname() )
|| ' return_code =' || hex(return_code)
|| ', reason_code =' || substr(hex(reason_code),5,4));
return(0);
end;
end_of_input:
proc( userToken, addr_xml, length_xml )
returns( byvalue fixed bin(31) )
options( byvalue linkage(optlink) );
dcl userToken pointer;
dcl addr_xml byaddr pointer;
dcl length_xml byaddr fixed bin(31);
return(0);
end;The following output shows the result of the sample program. For those documents that are not valid, the PLISAXD built-in subroutine invokes the XML exception event with the return code and reason code listed. For a detailed description of each return code and reason code, see XML System Services User's Guide and Reference.
SAXDTEST: PL/I XML Validation sample SAXDTEST: Document Successfully parsed SAXDTEST: Document Successfully parsed Invalid: missing attribute itemNumber. exception return_code =00000018, reason_code =8613 Invalid: unexpected attribute warehouse. exception return_code =00000018, reason_code =8612 Invalid: illegal attribute value 123-Ab. exception return_code =00000018, reason_code =8809 Invalid: missing element quantityOnHand. exception return_code =00000018, reason_code =8611 Invalid: unexpected element comment. exception return_code =00000018, reason_code =8607 Invalid: out-of-range element value 100 exception return_code =00000018, reason_code =8803