From: Fred L. Drake, Jr.
In order to read an external DTD, you also have to set an external entity reference handler as described above.
+Expat 1.95.8 introduces a new feature: its now possible to stop +parsing temporarily from within a handler function, even if more data +has already been passed into the parser. Applications for this +include
+ +To take advantage of this feature, the main parsing loop of an +application needs to support this specifically. It cannot be +supported with a parsing loop compatible with Expat 1.95.7 or +earlier (though existing loops will continue to work without +supporting the stop/resume feature).
+ +An application that uses this feature for a single parser will have +the rough structure (in pseudo-code):
+ ++fd = open_input() +p = create_parser() + +if parse_xml(p, fd) { + /* suspended */ + + int suspended = 1; + + while (suspended) { + do_something_else() + if ready_to_resume() { + suspended = continue_parsing(p, fd); + } + } +} ++ +
An application that may resume any of several parsers based on +input (either from the XML being parsed or some other source) will +certainly have more interesting control structures.
+ +This C function could be used for the parse_xml
+function mentioned in the pseudo-code above:
+#define BUFF_SIZE 10240 + +/* Parse a document from the open file descriptor 'fd' until the parse + is complete (the document has been completely parsed, or there's + been an error), or the parse is stopped. Return non-zero when + the parse is merely suspended. +*/ +int +parse_xml(XML_Parser p, int fd) +{ + for (;;) { + int last_chunk; + int bytes_read; + enum XML_Status status; + + void *buff = XML_GetBuffer(p, BUFF_SIZE); + if (buff == NULL) { + /* handle error... */ + return 0; + } + bytes_read = read(fd, buff, BUFF_SIZE); + if (bytes_read < 0) { + /* handle error... */ + return 0; + } + status = XML_ParseBuffer(p, bytes_read, bytes_read == 0); + switch (status) { + case XML_STATUS_ERROR: + /* handle error... */ + return 0; + case XML_STATUS_SUSPENDED: + return 1; + } + if (bytes_read == 0) + return 0; + } +} ++ +
The corresponding continue_parsing
function is
+somewhat simpler, since it only need deal with the return code from
+XML_ResumeParser
; it can
+delegate the input handling to the parse_xml
+function:
+/* Continue parsing a document which had been suspended. The 'p' and + 'fd' arguments are the same as passed to parse_xml(). Return + non-zero when the parse is suspended. +*/ +int +continue_parsing(XML_Parser p, int fd) +{ + enum XML_Status status = XML_ResumeParser(p); + switch (status) { + case XML_STATUS_ERROR: + /* handle error... */ + return 0; + case XML_ERROR_NOT_SUSPENDED: + /* handle error... */ + return 0;. + case XML_STATUS_SUSPENDED: + return 1; + } + return parse_xml(p, fd); +} ++ +
Now that we've seen what a mess the top-level parsing loop can
+become, what have we gained? Very simply, we can now use the XML_StopParser
function to stop
+parsing, without having to go to great lengths to avoid additional
+processing that we're expecting to ignore. As a bonus, we get to stop
+parsing temporarily, and come back to it when we're
+ready.
To stop parsing from a handler function, use the XML_StopParser
function. This function
+takes two arguments; the parser being stopped and a flag indicating
+whether the parse can be resumed in the future.
+enum XML_Status XMLCALL +XML_StopParser(XML_Parser p, + XML_Bool resumable); ++
Stops parsing, causing XML_Parse
or XML_ParseBuffer
to return. Must be called from within a
+call-back handler, except when aborting (when resumable
+is XML_FALSE
) an already suspended parser. Some
+call-backs may still follow because they would otherwise get
+lost, including
+
This can be called from most handlers, including DTD related
+call-backs, except when parsing an external parameter entity and
+resumable
is XML_TRUE
. Returns
+XML_STATUS_OK
when successful,
+XML_STATUS_ERROR
otherwise. The possible error codes
+are:
XML_ERROR_SUSPENDED
XML_ERROR_FINISHED
XML_ERROR_SUSPEND_PE
Since the stop/resume feature requires application support in the +outer parsing loop, it is an error to call this function for a parser +not being handled appropriately; see Temporarily Stopping Parsing for more information.
+ +When resumable
is XML_TRUE
then parsing
+is suspended, that is, XML_Parse
and XML_ParseBuffer
return XML_STATUS_SUSPENDED
.
+Otherwise, parsing is aborted, that is, XML_Parse
and XML_ParseBuffer
return
+XML_STATUS_ERROR
with error code
+XML_ERROR_ABORTED
.
Note:
+This will be applied to the current parser instance only, that is, if
+there is a parent parser then it will continue parsing when the
+external entity reference handler returns. It is up to the
+implementation of that handler to call XML_StopParser
on the parent parser
+(recursively), if one wants to stop parsing altogether.
When suspended, parsing can be resumed by calling XML_ResumeParser
.
New in Expat 1.95.8.
++enum XML_Status XMLCALL +XML_ResumeParser(XML_Parser p); ++
Resumes parsing after it has been suspended with XML_StopParser
. Must not be called from
+within a handler call-back. Returns same status codes as XML_Parse
or XML_ParseBuffer
. An additional error
+code, XML_ERROR_NOT_SUSPENDED
, will be returned if the
+parser was not currently suspended.
Note:
+This must be called on the most deeply nested child parser instance
+first, and on its parent parser only after the child parser has
+finished, to be applied recursively until the document entity's parser
+is restarted. That is, the parent parser will not resume by itself
+and it is up to the application to call XML_ResumeParser
on it at the
+appropriate moment.
New in Expat 1.95.8.
++void XMLCALL +XML_GetParsingStatus(XML_Parser p, + XML_ParsingStatus *status); ++
+enum XML_Parsing { + XML_INITIALIZED, + XML_PARSING, + XML_FINISHED, + XML_SUSPENDED +}; + +typedef struct { + enum XML_Parsing parsing; + XML_Bool finalBuffer; +} XML_ParsingStatus; ++
Returns status of parser with respect to being initialized,
+parsing, finished, or suspended, and whether the final buffer is being
+processed. The status
parameter must not be
+NULL.
New in Expat 1.95.8.
+Although handlers are typically set prior to parsing and left alone, an diff --git a/expat/doc/style.css b/expat/doc/style.css index 8f19fbd5..69df30bc 100644 --- a/expat/doc/style.css +++ b/expat/doc/style.css @@ -49,6 +49,17 @@ body { margin-right: 10%; } +.pseudocode { + padding-left: 1em; + padding-top: .5em; + padding-bottom: .5em; + border: solid thin; + margin: 1em 0; + background-color: rgb(250,220,180); + margin-left: 2em; + margin-right: 10%; +} + .handler { width: 100%; border-top-width: thin;