Requirements for JSON Parser

╄→гoц情女王★ 提交于 2019-12-21 16:34:12

问题


I'm thinking about implementing JSON parser for Delphi. What should a good JSON parser do? Any ideas for requirements? I believe it should at least output and process JSON... Looking at XML parsers, should it be more DOM or SAX-like?


回答1:


I think Json.NET does a pretty bang up job.

  • JsonReader and JsonWriter for low level work of parsing and outputting JSON
  • JsonSerializer for converting objects to and from JSON
  • JObject, JArray and JValue classes for working with JSON in an object model

Note I may be a bit bias since I wrote it :)




回答2:


A good floor would be all the functionality provided by the following 3 (taken from JSON.org): uJson, JSON Toolkit, and lkjson.




回答3:


I've used the JSON toolkit in several projects, with great success. The only thing I've modified at some point was the way it formats resulting JSON, but it's a matter of personal taste.

It's free, fairly clean, and easy to use. No need to install packages; just have a .pas file somewhere in your path. Just check test_usage.dpr below for some simple examples on how to use it. It doesn't get much easier than that.

I wouldn't waste my time trying to implement yet another JSON parser, unless you want to do it for educational purposes, in which case you should carefully study existing implementations anyway.

JSON Toolkit home: http://www.progdigy.com/?page_id=6

program test_usage;
{$IFDEF FPC}
  {$MODE OBJFPC}{$H+}
{$ELSE}
  {$APPTYPE CONSOLE}
{$ENDIF}

uses
  SysUtils,
  superobject;

var
  my_string, my_int, my_object, my_array: ISuperObject;
  new_obj: ISuperObject;
  j: integer;
  ite: TSuperObjectIter;

begin
  try
    my_string := TSuperObject.Create(#9);
    writeln('my_string=', my_string.AsString);
    writeln('my_string.AsJSon=', my_string.AsJSon);

    my_string := TSuperObject.Create('foo');
    writeln('my_string=', my_string.AsString);
    writeln('my_string.AsJson=', my_string.AsJson);

    my_int := TSuperObject.Create(9);
    writeln('my_int=', my_int.AsInteger);
    writeln('my_int.AsJson=', my_int.AsJson);

    my_array := TSuperObject.Create(stArray);
    my_array.I[''] := 1; // append
    my_array.I[''] := 2; // append
    my_array.I[''] := 3; // append
    my_array.I['4'] := 5;
    writeln('my_array=');
    with my_array.AsArray do
    for j := 0 to Length - 1 do
      if O[j] = nil then
        writeln(#9'[', j,']=', 'null') else
        writeln(#9'[', j,']=', O[j].AsJson);
    writeln('my_array.AsJson=', my_array.AsJson);

    my_object := TSuperObject.Create(stObject);
    my_object.I['abc'] := 12;
   // my_object.S['path.to.foo[5]'] := 'bar';
    my_object.B['bool0'] := false;
    my_object.B['bool1'] := true;
    my_object.S['baz'] := 'bang';
    my_object.S['baz'] := 'fark';
    my_object.AsObject.Delete('baz');
    my_object['arr'] := my_array;
    writeln('my_object=');
    if ObjectFindFirst(my_object, ite) then
    repeat
      writeln(#9,ite.key,': ', ite.val.AsJson);
    until not ObjectFindNext(ite);
    ObjectFindClose(ite);
    writeln('my_object.AsJson=', my_object.AsJson);

    new_obj := TSuperObject.Parse('"003"');
    writeln('new_obj.AsJson=', new_obj.AsJson);

    new_obj := TSuperObject.Parse('/* hello */"foo"');
    writeln('new_obj.AsJson=', new_obj.AsJson);

    new_obj := TSuperObject.Parse('// hello'#10'"foo"');
    writeln('new_obj.AsJson=', new_obj.AsJson);

    new_obj := TSuperObject.Parse('"\u0041\u0042\u0043"');
    writeln('new_obj.AsJson=', new_obj.AsJson);

    new_obj := TSuperObject.Parse('null');
    if new_obj = nil then
      writeln('new_obj.AsJson=', 'null');

    new_obj := TSuperObject.Parse('true');
    writeln('new_obj.AsJson=', new_obj.AsJson);

    new_obj := TSuperObject.Parse('12');
    writeln('new_obj.AsJson=', new_obj.AsJson);

    new_obj := TSuperObject.Parse('12.3');
    writeln('new_obj.AsJson=', new_obj.AsJson);

    new_obj := TSuperObject.Parse('["\n"]');
    writeln('new_obj.AsJson=', new_obj.AsJson);

    new_obj := TSuperObject.Parse('["\nabc\n"]');
    writeln('new_obj.AsJson=', new_obj.AsJson);

    new_obj := TSuperObject.Parse('[null]');
    writeln('new_obj.AsJson=', new_obj.AsJson);

    new_obj := TSuperObject.Parse('[]');
    writeln('new_obj.AsJson=', new_obj.AsJson);

    new_obj := TSuperObject.Parse('["abc",null,"def",12]');
    writeln('new_obj.AsJson=', new_obj.AsJson);

    new_obj := TSuperObject.Parse('{}');
    writeln('new_obj.AsJson=', new_obj.AsJson);

    new_obj := TSuperObject.Parse('{ "foo": "bar" }');
    writeln('new_obj.AsJson=', new_obj.AsJson);

    new_obj := TSuperObject.Parse('{ "foo": "bar", "baz": null, "bool0": true }');
    writeln('new_obj.AsJson=', new_obj.AsJson);

    new_obj := TSuperObject.Parse('{ "foo": [null, "foo"] }');
    writeln('new_obj.AsJson=', new_obj.AsJson);

    new_obj := TSuperObject.Parse('{ "abc": 12, "foo": "bar", "bool0": false, "bool1": true, "arr": [ 1, 2, 3, null, 5 ] }');
    writeln('new_obj.AsJson=', new_obj.AsJson);

    new_obj := TSuperObject.Parse('{ foo }');
    if (new_obj = nil) then
      writeln('got error as expected');

    my_string := nil;
    my_int := nil;
    my_object := nil;
    my_array := nil;
    new_obj := nil;


    writeln(#10'press enter ...');
    readln;
  except
    on E: Exception do
      writeln(E.Message)
  end;
end.



回答4:


I have implemented a pull-style parser in Java, which I find very nice to use. It parses strictly conforming JSON, with some relaxations accepted (primarily for my specific purposes). It is published and detailed on my website. Also published is an additional method which illustrates a document load using the parser - so you can use it either stream-oriented or document oriented.

I highly recommend pull style parsng (I have an XML parser which is pull, also).




回答5:


When it deals with parsing some (textual) content, two directions are usually envisaged. In the XML world, you have usually to make a choice between:

  • A DOM parser, which creates an in-memory tree structure of objects mapping the XML nodes;
  • A SAX parser, which reads the XML content, then call pre-defined events for each XML content element.

In fact, DOM parsers use internally a SAX parser to read the XML content. Therefore, with the overhead of object creation and their property initialization, DOM parsers are typically three to five times slower than SAX. But, DOM parsers are much more powerful for handling the data: as soon as it's mapped in native objects, code can access with no time to any given node, whereas a SAX-based access will have to read again the whole XML content.

Most JSON parser available in Delphi use a DOM-like approach. For instance, the DBXJSON unit included since Delphi 2010 or the SuperObject or DWS libraries create a class instance mapping each JSON node.

In a JSON-based Client-Server ORM like ours, profiling shows that a lot of time is spent in JSON parsing, on both Client and Server side (on the Server, we convert JSON content into SQL on the fly). Therefore, we tried to optimize this part of the library.

In order to achieve best speed, we try to use a mixed approach:

  • All the necessary conversion (e.g. un-escape text) is made in-memory, from and within the JSON buffer, to avoid memory allocation;
  • The parser returns pointers to the converted elements (just like the vtd-xml library).

The resulting speed is amazing, for both small and very large JSON content buffer.

In order to produce JSON, we wrote also some fast JSON serialization functions, from any object content.

For details and code source, see this Blog's entry.




回答6:


I agree with James; there are 3 sensible ways to work with Json: as a stream of events/tokens; as a tree (like XML DOM), or by binding to/from "native" objects. The package I am familiar with is Jackson (http://jackson.codehaus.org), and it also supports these 3 methods, similar to how (I assume) Json.NET does.




回答7:


Well, the nice thing about JSON is that it uses a fairly simple grammar and writing a parser for it is fairly simple. "forgetting" all of the other implementations, but using Delphi I would start with the TParser class in the classes unit for a jumpstart. Create separate methods to handle each element (some are already done in TParser, which is why I suggested starting from there).

Now, what to do with what you have parsed. There is where the fun comes in. If you mimic the interfaces and implementation of the TXmlDocument, then conversion to/from XML/JSON is somewhat trivial.




回答8:


Jettison (http://jettison.codehaus.org/) is a popular JSON StAX (Streaming API for XML) implementation, written in Java.

Jettison is a collection of Java APIs (like STaX and DOM) which read and write JSON. This allows nearly transparent enablement of JSON based web services in services frameworks like CXF or XML serialization frameworks like XStream.



来源:https://stackoverflow.com/questions/413139/requirements-for-json-parser

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!