JSON解析器的要求

时间:2009-01-05 13:48:25

标签: delphi json delphi-2009

我正在考虑为Delphi实现JSON解析器。 一个好的JSON解析器应该做什么?对要求的任何想法? 我相信至少应该输出和处理JSON ...... 看看XML解析器,它应该更像DOM还是SAX?

8 个答案:

答案 0 :(得分:4)

我认为Json.NET做得非常好。

  • JsonReader和JsonWriter for low 解析和输出JSON的级别工作
  • 用于将对象与JSON进行转换的JsonSerializer
  • JObject,JArray和JValue类的工作 在对象模型中使用JSON

注意我写这篇文章可能有点偏见:)

答案 1 :(得分:3)

好的楼层将是以下3个(取自JSON.org)提供的所有功能:uJsonJSON Toolkitlkjson

答案 2 :(得分:2)

我在几个项目中使用了JSON工具包,取得了巨大的成功。我在某些时候修改过的唯一一件事就是格式化JSON的方式,但这是个人品味的问题。

它是免费的,相当干净,易于使用。无需安装包;在你的路径中的某个地方只有一个.pas文件。只需查看下面的 test_usage.dpr ,了解有关如何使用它的一些简单示例。它并没有那么容易。

我不会浪费时间尝试实现另一个JSON解析器,除非你想用于教育目的,在这种情况下你应该仔细研究现有的实现。

JSON Toolkit主页: 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.

答案 3 :(得分:2)

我在Java中实现了一种拉式解析器,我发现它很好用。它解析严格符合JSON,接受一些放松(主要是为了我的特定目的)。它已发布并详细on my website。同时发布的另一种方法是使用解析器来说明文档加载 - 因此您可以将其用于面向流或面向文档。

我强烈推荐使用pull style parsng(我还有一个XML解析器,也是拉)。

答案 4 :(得分:2)

当它处理解析某些(文本)内容时,通常会设想两个方向。在XML世界中,您通常可以选择:

  • DOM解析器,它创建映射XML节点的对象的内存中树结构;
  • SAX解析器,读取XML内容,然后为每个XML内容元素调用预定义事件。

实际上,DOM解析器在内部使用SAX解析器来读取XML内容。因此,由于对象创建和属性初始化的开销,DOM解析器通常比SAX慢三到五倍。但是,DOM解析器在处理数据方面要强大得多:只要它映射到本机对象中,代码就可以立即访问任何给定节点,而基于SAX的访问则必须再次读取整个XML内容。 / p>

Delphi中可用的大多数JSON解析器都使用类似DOM的方法。例如,自Delphi 2010或DBXJSONSuperObject库以来包含的DWS单元创建了映射每个JSON节点的类实例。

在像我们这样的JSON-based Client-Server ORM中,分析显示在JSON解析中花费了大量时间,在客户端和服务器端(在服务器上,我们将JSON内容动态转换为SQL)。因此,我们尝试优化库的这一部分。

为了达到最佳速度,我们尝试使用混合方法:

  • 所有必要的转换(例如取消转义文本)都是在内存中,从JSON缓冲区内和内部进行的,以避免内存分配;
  • 解析器返回指向已转换元素的指针(就像vtd-xml library)。

对于小型和非常大的JSON内容缓冲区,结果速度都很惊人。

为了生成JSON,我们还从任何对象内容中写了一些fast JSON serialization functions

有关详细信息和代码来源,请参阅this Blog's entry

答案 5 :(得分:1)

我同意詹姆斯;有三种合理的方式与Json合作:作为一系列事件/代币;作为树(如XML DOM),或通过绑定到/来自“本机”对象。 我熟悉的包是Jackson(http://jackson.codehaus.org),它也支持这三种方法,类似于Json.NET的方式(我假设)。

答案 6 :(得分:0)

嗯,关于JSON的好处是它使用了一个相当简单的语法并为它编写解析器非常简单。 “忘记”所有其他实现,但是使用Delphi我会从类单元中的TParser类开始,用于一个快速启动。创建单独的方法来处理每个元素(一些已经在TParser中完成,这就是我建议从那里开始的原因)。

现在,如何处理已解析的内容。有趣的地方。如果你模仿TXmlDocument的接口和实现,那么转换到XML / JSON /从XML / JSON转换有点微不足道。

答案 7 :(得分:0)

Jettison(http://jettison.codehaus.org/)是一种流行的JSON StAX(用于XML的Streaming API)实现,用Java编写。

  

Jettison是Java API的集合   (如STaX和DOM)读取和   写JSON。这几乎可以   基于JSON的透明启用   服务框架中的Web服务   像CXF或XML序列化   像XStream这样的框架。