|
|
Reading XML files
For ISO Module-2
Tested with XDS and Stony Brook Modula-2
By Frank Schoonjans (frank.schoonjans@medcalc.net) - 7 December 2004
I am working on a library to read XML files. When programming the parser I wanted to avoid
(a) the use of recursion, and (b) any limitations on string length.
Error reporting is limited.
I have tested with Stony Brook and XDS.
In XDS, you must select the Project option "Enable language extensions" and "Default memory management".
I hope to receive your comments or suggestions.
The XMLRead library has the following interface:
DEFINITION MODULE XMLReadLib;
FROM SYSTEM IMPORT CAST;
TYPE StringPointer = POINTER TO ARRAY OF CHAR;
TYPE XMLHandle;
CONST INVALID_XMLHandle=CAST(XMLHandle,NIL);
PROCEDURE XMLOpenDocument(filename : ARRAY OF CHAR) : XMLHandle;
PROCEDURE XMLCloseDocument(VAR handle: XMLHandle);
TYPE AttrPair = RECORD
IdPtr : StringPointer;
ValPtr : StringPointer;
END;
PairRecPtr = POINTER TO ARRAY OF AttrPair;
XMLElementRec = RECORD
NamePtr : StringPointer;
DataPtr : StringPointer;
AttribSz : CARDINAL; (* number of Attributes *)
Attributes : PairRecPtr;
END;
Tags = (opentag,closetag,emptyelementtag,processinginstruction,comment);
TYPE XMLCallbackProc = PROCEDURE(CARDINAL, Tags, XMLElementRec) : BOOLEAN;
PROCEDURE XMLSetCallback(handle : XMLHandle;
userdata : CARDINAL;
proc : XMLCallbackProc) : BOOLEAN;
PROCEDURE XMLParseDocument(handle : XMLHandle) : INTEGER;
(* returns -1 = Invalid file handle
0 = OK
1 = Found '<' but expected '>'
2 = Found '>' but expected '<'
3 = Wrong end tag
4 = Not all elements are closed
5 = File contains trailing text
6 = Found '>' but expected '?>'
7 = Found '<!' but expected '<!--'
8 = Found '>' but expected '-->'
9 = Expected closing "
10 = Expected =
15 = Out of memory
*)
PROCEDURE XMLGetErrorString(handle : XMLHandle; VAR strptr : StringPointer);
END XMLReadLib.
|
Here is a simple test program
MODULE ReadTest;
FROM XMLReadLib IMPORT XMLHandle,XMLOpenDocument,XMLSetCallback,XMLParseDocument,
XMLCloseDocument,XMLElementRec,Tags,XMLGetErrorString,
StringPointer;
FROM STextIO IMPORT WriteString,WriteLn,ReadChar;
PROCEDURE ShowElement(element : XMLElementRec);
VAR c : CARDINAL;
BEGIN
WriteString(element.NamePtr^); WriteString("'"); WriteLn;
IF element.DataPtr#NIL THEN
WriteString(" data : '");
WriteString(element.DataPtr^);
WriteString("'");
WriteLn;
END;
IF element.AttribSz>0 THEN
FOR c:=0 TO element.AttribSz-1 DO
WriteString(" '");
WriteString(element.Attributes^[c].IdPtr^);
WriteString("' : '");
WriteString(element.Attributes^[c].ValPtr^);
WriteString("'");
WriteLn;
END;
END;
END ShowElement;
PROCEDURE CallbackFunction(userdata : CARDINAL;
tag : Tags;
element : XMLElementRec) : BOOLEAN;
BEGIN
CASE tag OF
| processinginstruction : WriteString("Proc instr. : '"); ShowElement(element);
| opentag : WriteString("Open tag : '"); ShowElement(element);
| closetag : WriteString("Close tag : '"); ShowElement(element);
| emptyelementtag : WriteString("Empty elem. : '"); ShowElement(element);
| comment : WriteString("Comment : '"); ShowElement(element);
END;
RETURN TRUE;
END CallbackFunction;
VAR handle : XMLHandle;
ch : CHAR;
str : StringPointer;
BEGIN
handle:=XMLOpenDocument("test.xml");
IF XMLSetCallback(handle,1,CallbackFunction) THEN END;
IF XMLParseDocument(handle)#0 THEN
WriteString("ERROR : ");
XMLGetErrorString(handle,str);
WriteString(str^);
WriteLn;
END;
XMLCloseDocument(handle);
ReadChar(ch);
END ReadTest.
|
After you open the file using XMLOpenDocument ,
you assign a callback procedure to it with XMLSetCallback .
Next call XMLParseDocument and finally close the file using XMLCloseDocument .
The XMLParseDocument procedure will call the Callback function you have defined when it encounters
a processing instruction (enclosed in <? ?>), an open tag (enclosed in < >),
a close tag (enclosed in </ >), an empty-element-tag (enclosed in < />) or a comment
(enclosed in <!-- -->).
For the following XML file:
<?xml version="1.0"?>
<document author="frank">
<empty_element/>
<field1>
<!--comment 123-->data for field 1
<sub1>sub stuff 1</sub1>
<sub2>sub stuff 2</sub2>
</field1>
<field2>data for field2</field2>
</document> |
the output of our test program is:
Proc instr. : 'xml'
'version' : '1.0'
Open tag : 'document'
'author' : 'frank'
Empty elem. : 'empty_element'
Open tag : 'field1'
Comment : 'comment 123'
Open tag : 'sub1'
Close tag : 'sub1'
data : 'sub stuff 1'
Open tag : 'sub2'
Close tag : 'sub2'
data : 'sub stuff 2'
Close tag : 'field1'
data : 'data for field 1'
Open tag : 'field2'
Close tag : 'field2'
data : 'data for field2'
Close tag : 'document'
'author' : 'frank'
|
Download
XMLReadLib.rar
| |