| [Previous][Up][Next] |
TJSONConsumerReader provides an alternative to event-based parsing by using the IJSONConsumer interface. Instead of assigning event handlers, you implement the interface methods to process JSON elements.
This approach provides a cleaner object-oriented design and can be easier to maintain for complex JSON processing logic.
The workflow involves:
Here's an example that builds a simple data structure from JSON:
program JSONConsumerDemo; {$mode objfpc}{$H+} uses Classes, SysUtils, jsonreader, Generics.Collections; type TJSONDataExtractor = class(TInterfacedObject, IJSONConsumer) private FStack: TList<string>; FCurrentPath: string; FData: TStringList; public constructor Create; destructor Destroy; override; // IJSONConsumer interface procedure NullValue; procedure BooleanValue(const AValue: Boolean); procedure NumberValue(const AValue: string); procedure FloatValue(const AValue: Double); procedure Int64Value(const AValue: Int64); procedure QWordValue(const AValue: QWord); procedure IntegerValue(const AValue: Integer); procedure StringValue(const AValue: UTF8String); procedure KeyName(const AKey: UTF8String); procedure StartObject; procedure EndObject; procedure StartArray; procedure EndArray; property Data: TStringList read FData; end; constructor TJSONDataExtractor.Create; begin inherited Create; FStack := TList<string>.Create; FData := TStringList.Create; end; destructor TJSONDataExtractor.Destroy; begin FStack.Free; FData.Free; inherited Destroy; end; procedure TJSONDataExtractor.KeyName(const AKey: UTF8String); begin if FCurrentPath <> '' then FCurrentPath := FCurrentPath + '.' + AKey else FCurrentPath := AKey; end; procedure TJSONDataExtractor.StringValue(const AValue: UTF8String); begin if FCurrentPath <> '' then FData.Values[FCurrentPath] := AValue; FCurrentPath := ''; end; procedure TJSONDataExtractor.IntegerValue(const AValue: Integer); begin if FCurrentPath <> '' then FData.Values[FCurrentPath] := IntToStr(AValue); FCurrentPath := ''; end; procedure TJSONDataExtractor.BooleanValue(const AValue: Boolean); begin if FCurrentPath <> '' then FData.Values[FCurrentPath] := BoolToStr(AValue, True); FCurrentPath := ''; end; procedure TJSONDataExtractor.StartObject; begin if FCurrentPath <> '' then FStack.Add(FCurrentPath); end; procedure TJSONDataExtractor.EndObject; begin if FStack.Count > 0 then begin FCurrentPath := FStack[FStack.Count - 1]; FStack.Delete(FStack.Count - 1); end else FCurrentPath := ''; end; // Implement remaining interface methods procedure TJSONDataExtractor.NullValue; begin FCurrentPath := ''; end; procedure TJSONDataExtractor.NumberValue(const AValue: UTF8String); begin StringValue(AValue); end; procedure TJSONDataExtractor.FloatValue(const AValue: Double); begin StringValue(FloatToStr(AValue)); end; procedure TJSONDataExtractor.Int64Value(const AValue: Int64); begin StringValue(IntToStr(AValue)); end; procedure TJSONDataExtractor.QWordValue(const AValue: QWord); begin StringValue(IntToStr(AValue)); end; procedure TJSONDataExtractor.StartArray; begin end; procedure TJSONDataExtractor.EndArray; begin end; var Reader: TJSONConsumerReader; Extractor: TJSONDataExtractor; JSONData: string; i: Integer; begin JSONData := '{"user": {"name": "Bob Jones", "age": 35, "active": true}, "settings": {"theme": "dark"}}'; Extractor := TJSONDataExtractor.Create; Reader := TJSONConsumerReader.Create(JSONData, []); try Reader.Consumer := Extractor; Reader.Execute; Writeln('Extracted data:'); or := 0 to Extractor.Data.Count - 1 do Writeln(' ', Extractor.Data[i]); finally Reader.Free; Extractor.Free; end; end.
The consumer interface approach is beneficial when you need to: