JSON Parsing API

Warning
This API is experimental, and is therefore likely to change.

API Reference


The JSON Parsing API is intended to provide fast parsing of a JSON data stream with very little memory required. It is an event-driven API that uses callbacks (handlers) to report when things are found in the JSON document. The parser does not build a document structure for you. You build your structure as needed in response to callbacks from the parser. In this way, the JSON parser avoids potential memory fragmentation issues that can arise when document object models are constructed on the heap (e.g., using malloc()).

Starting and Stopping Parsing

The function le_json_Parse() is used to start parsing a JSON document obtained from a file descriptor. This function returns immediately, and further parsing proceeds in an event-driven manner: As JSON data is received, asynchronous call-back functions are called to deliver parsed information or an error message.

Parsing stops automatically when the end of the document is reached or an error is encountered.

le_json_Cleanup() must be called to release memory resources allocated by the parser.

If the document starts with a '{', then it will finish with the matching '}'.

If it starts with a '[', then it will finish with the matching ']'.

All documents must start with either '{' or '['.

To stop parsing early, call le_json_Cleanup() early.

Warning
Be sure to stop parsing before closing the file descriptor.

Event Handling

As parsing progresses and the parser finds things inside the JSON document, the parser calls the event handler function to report the findings.

For example, when the parser finds an object member, it calls the event handler function with the event code LE_JSON_OBJECT_MEMBER; and when if finds a string value, an LE_JSON_STRING event is reported.

The event handler function can call functions to fetch values, depending on the event:

le_json_GetString() and le_json_GetNumber() can only be called from inside of a JSON parsing event handler function or any function being called (directly or indirectly) from a JSON parsing event handler. Calling these functions elsewhere will be fatal to the calling process.

Context

Each JSON object, object member and array in the JSON document is a "context". Each context has an event handler function and an opaque pointer associated with it. The top level context's event handler and opaque pointer are passed into le_json_Parse(). Sub-contexts (object members or array elements) will inherit their context from their parent.

The current context's event handler can be changed from within an event handler function by calling le_json_SetEventHandler(). This will remain in effect until the parser finishes parsing that part of the document and returns back to its parent, at which time the current context will be automatically restored to the parent's context.

Error Handling

There is a global error handler that is also set when the parsing is started, and can be changed by calling le_json_SetErrorHandler(). Unlike other event handlers, this is not part of the context, and will therefore not get restored to a previous handler when the parsing of a member finishes. The error handler function is passed parameters that indicate what type of error occurred.

Other Functions

For diagnostic purposes, le_json_GetEventName() can be called to get a human-readable string containing the name of a given event.

To get the number of bytes that have been read by the parser since le_json_Parse() was called, call le_json_GetBytesRead().

Example

If the JSON document is

{ "x":1, "y":2, "name":"joe" }

The following sequence of events will be reported by the parser:

  1. LE_JSON_OBJECT_START
  2. LE_JSON_OBJECT_MEMBER - If the event handler calls le_json_GetString(), it will return "x".
  3. LE_JSON_NUMBER - If the event handler calls le_json_GetNumber(), it will return 1.
  4. LE_JSON_OBJECT_MEMBER - If the event handler calls le_json_GetString(), it will return "y".
  5. LE_JSON_NUMBER - If the event handler calls le_json_GetNumber(), it will return 2.
  6. LE_JSON_OBJECT_MEMBER - If the event handler calls le_json_GetString(), it will return "name".
  7. LE_JSON_STRING - If the event handler calls le_json_GetString(), it will return "joe".
  8. LE_JSON_OBJECT_END
  1. LE_JSON_DOC_END - At this point, parsing stops.

If the handler function passed to le_json_Parse() is called "<c>TopLevelHandler()</c>", TopLevelHandler() will be called for the all events. But, when TopLevelHandler() gets the event LE_JSON_OBJECT_MEMBER for the member "x" and responds by calling le_json_SetEventHandler(XHandler(), NULL), then the LE_JSON_NUMBER event for "x" will be passed to XHandler(). But, the following LE_JSON_OBJECT_MEMBER event for "y" will still go to TopLevelHandler(), because the context returns to the top level object after the parser finishes parsing member "x".

Multi-Threading

This API is not thread safe. DO NOT attempt to SHARE parsers between threads.

If a thread dies, any parsers in use by that thread that have not been cleaned-up by calls to le_json_Cleanup() will be cleaned up automatically.