ahausladen / JsonDataObjects

JSON parser for Delphi 2009 and newer
MIT License
414 stars 160 forks source link

Consider public TJsonWriter #32

Open zuobaoquan opened 8 years ago

zuobaoquan commented 8 years ago

It is often not necessary to create DOM (JsonObject) when serializing objects to a stream. It is more efficient to expose a public TJsonWriter to perform such task.

TJsonOutputWriter is used internally so far. Also, UTF8String should be considered in this part.

ahausladen commented 8 years ago

JsonDataObject uses Data-Objects and is per definition a DOM parser. Changing JsonDataObject to be a SAX parser won't happen in the near future as I personally don't need it (yet). But pull requests are welcome.

zuobaoquan commented 8 years ago

I'm with you. I think DOM parser is fine. What I suggested is actually more like a json string builder. e.g. writer := TJsonWriter.Create(stream, TEncoding.UTF8); // sample writer.StartObject; writer.WritePropertyName('name'); writer.WriteValue('Paul'); writer.EndObject; writer.Flush;

at present, it is done by two steps:

json.FromSimpleObject(obj); json.SaveToStream(stream);

An intermediate DOM is not necessary in this task. P.S. FromSimpleObject is close and very limited.

ahausladen commented 8 years ago

I don't need To/FromSimpleObject myself. I only added it to have at least something simple (and Delphi 2009 compatible) in the unit for others.

Your example of a TJsonWriter wouldn't be that hard to implement, so I may consider it.

cesarliws commented 8 years ago

A fluent interface JsonWriter is very welcome! It is now in my TODO list. I have a local fork of https://github.com/VSoftTechnologies/Delphi-Fluent-JSON that I have changed to use JsonDataObjects internally to add objects, but I'll probably rewrite it all to use only JsonDataObjects.

Righ now I'm using it mostly to write log as Json, like this:

Result := CreateJsonObject
  .Text(MODULE_MEMBER, FModuleName)
  .Text(TASK_MEMBER, FTaskName)
  .Text(ERROR_MEMBER, ErrMsg)
  .Text(EXCEPTION_MEMBER, E.ClassMessage) 
  .Number(SYS_ERR_CODE_MEMBER, SysErrorCode)
  .Text(SYS_ERR_MSG_MEMBER, SysErrorMessage(SysErrorCode))
  .Text(STACK_TRACE_MEMBER, GetStackTrace(ExceptAddr))
  .ToString;

For my fluent interface I have methods like:

    function Obj: IJsonBuilder; overload;
    function Obj(const name: string): IJsonBuilder; overload;
    function Obj(const name: string; value: TObject): IJsonBuilder; overload;
    function Text(const name: string; const value: string): IJsonBuilder; overload;
    function Text(const name: string; const value: string; const Args: array of const): IJsonBuilder; overload;
    function Number(const name: string; const value: Double): IJsonBuilder; overload;

I also have methods for Array, Null, and need to implement for Date, so it will be handled by the overloaded method.