0

I was trying to parse JSON from a website using Delphi XE2 and following code suggested in this thread here. When I implement the code exactly as it appears in the respondents post, it works, but when I implement something almost identical in mine, I get an access violation at a line that read:

LParts:=LJsonObj.Get('parts').JsonValue;

And it fails (when running it) with an AV every time (compiles ok, just won't run). I have simplified my code and below is a snippet that I would expect to work. Afterall, this is a copy and paste of other, working code.

I would be really grateful if someone could have a look below and let me know why mine doesn't work but the code in the referenced post does. I am puzzled largely because when I debug it, it looks like it should be working and there is little debug info to go off of.

program ReadJSONConsoleApp;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  DBXJSON,
  System.SysUtils;


Const
StrJson=
'{' +
'  "response" : [ {' +
'    "distributor" : {' +
'      "id" : 1538,' +
'      "name" : "Arrow Electronics",' +
'      "authorized" : true,' +
'      "logoUrl" : "this is normally a URL but I cut it out"' +
'    },' +
'    "parts" : [ {' +
'      "manufacturer" : "National Semiconductor",' +
'      "part" : "LM741WG/883",' +
'      "description" : "OP Amp Single GP ±22V 10-Pin CFPAK Tray",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 65.0,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 88,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "National Semiconductor",' +
'      "part" : "LM741W/883",' +
'      "description" : "OP Amp Single GP ±22V 10-Pin CPAK Rail",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 40.5,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 1464,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741CH",' +
'      "description" : "OP Amp Single GP ±18V 8-Pin TO-99 Box",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 5.22,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 95,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741CN",' +
'      "description" : "OP Amp Single GP ±18V 8-Pin PDIP Rail",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 0.3633,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 4320,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741H",' +
'      "description" : "OP Amp Single GP ±22V 8-Pin TO-99 Box",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 5.22,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 3458,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741H",' +
'      "description" : "OP Amp Single GP ±22V 8-Pin TO-99 Box",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 5.71,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 0,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741CN/NOPB",' +
'      "description" : "OP Amp Single GP ±18V 8-Pin PDIP Rail",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 0.2977,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 6486,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741J",' +
'      "description" : "OP Amp Single GP ±22V 8-Pin CDIP Rail",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 7.21,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 362,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741H/NOPB",' +
'      "description" : "OP Amp Single GP ±22V 8-Pin TO-99 Box",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 5.22,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 1378,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741J/883",' +
'      "description" : "OP Amp Single GP ±22V 8-Pin CDIP Rail",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 11.8,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 989,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741H/883",' +
'      "description" : "OP Amp Single GP ±22V 8-Pin TO-99 Tray",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 15.74,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 4252,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741CHNOPB",' +
'      "description" : "OP Amp Single GP ±18V 8-Pin TO-99 Box",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 5.22,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 785,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }' +
'    } ]' +
'  } ]' +
'}';

procedure ParseJson;
var
  LJsonObj  : TJSONObject;
  LJPair    : TJSONPair;
  LParts    : TJSONValue;
  LPart     : TJSONValue;
  LItem     : TJSONValue;
  LIndex    : Integer;
  LSize     : Integer;
begin
    LJsonObj    := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(StrJson),0) as TJSONObject;
  try
     LParts:=LJsonObj.Get('parts').JsonValue;
     LSize:=TJSONArray(LParts).Size;
     for LIndex:=0 to LSize-1 do
     begin
      LPart := TJSONArray(LParts).Get(LIndex);
      LJPair   := TJSONPair(LPart);
      Writeln(Format('Part Name %s',[LJPair.JsonString.Value]));
        for LItem in TJSONArray(LJPair.JsonValue) do
        begin
           if TJSONPair(LItem).JsonValue is TJSONFalse then
            Writeln(Format('  %s : %s',[TJSONPair(LItem).JsonString.Value, 'false']))
           else
           if TJSONPair(LItem).JsonValue is TJSONTrue then
            Writeln(Format('  %s : %s',[TJSONPair(LItem).JsonString.Value, 'true']))
           else
            Writeln(Format('  %s : %s',[TJSONPair(LItem).JsonString.Value, TJSONPair(LItem).JsonValue.Value]));
        end;
     end;
  finally
     LJsonObj.Free;
  end;
end;

begin
  try
    ParseJson;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.
Community
  • 1
  • 1
DoubleE
  • 71
  • 1
  • 10
  • Just a side note: the JSON data in this has been heavily edited to make the post shorter. I can post the full length JSON data if this doesn't suffice to recreate the issue. – DoubleE Nov 04 '13 at 21:31
  • 2
    Found the problem... `LJsonObj` is `nil` after you call `TJSONObject.ParseJSONValue`... figuring out why now and will post an answer for you! – LaKraven Nov 04 '13 at 21:47
  • @DoubleE Do you know how to use the debugger yet? – David Heffernan Nov 04 '13 at 21:56
  • 1
    Your JSON string doesn't seem to want to parse... even though it looks properly formatted. I'm looking deeper into that now. – LaKraven Nov 04 '13 at 22:00
  • @DavidHeffernan I have a pretty decent grasp of it but by no means claim to be the expert. So many dialogs to wade thru and not all of them intuitive. I noticed in the locals that my JSON Object was nil. I just couldn't figure how to follow that thru to the source to see what was causing it. I can seem to single step but it's not taking me into into the referenced library / class definition when I step. Any pointers there would be grand! Still, I know the basics, watches, locals, call stack, inspector. Suggestions on what else I might have looked at? – DoubleE Nov 04 '13 at 22:13
  • Even when the JSON data is correctly formed (as I've done now), the `LParts := LJsonObj.GET('parts').JsonValue;` line causes a fresh AV. – LaKraven Nov 04 '13 at 22:14
  • @TLama here's the corrected JSON: http://pastebin.com/La3cpW69 – LaKraven Nov 04 '13 at 22:23
  • I rolled back the question. It's hard enough at the best of times without the question being a moving target. – David Heffernan Nov 04 '13 at 22:31
  • 1
    @DoubleE, You are not parsing correctly the JSON string, post a new question and I will help you :) – RRUZ Nov 04 '13 at 23:38
  • @RRUZ Help here if you wish, if DoubleE won't post new Q. ILm happy to delete in that case. The Q and A will be better then because parsing valid JSON is more interesting than simple invalid JSON. I defer to your greater knowledge on the subject, and your more suitable time zone!! – David Heffernan Nov 04 '13 at 23:40
  • Hi Guys -- @RRUZ I've just posted a new query to: http://stackoverflow.com/questions/19779541/delphi-access-violation-on-parsing-json-data-run-time. Everyone, thank you for your help and your patience. As my nickname implies, I'm an electronics guy just trying to make sense of the applications space. Any help you provide is greatly appreciated. And that *includes* help in navigating the forums and with best practices in the community. So thanks. – DoubleE Nov 04 '13 at 23:53
  • Add the common `Delphi` tag to your next question as well. By doing so you'll pay more attention to it. And, feel free to delete this one ;-) – TLama Nov 04 '13 at 23:59
  • 1
    @TLama - Thanks mate, just did that! And thanks for the help! – DoubleE Nov 05 '13 at 00:01

1 Answers1

1

The call to ParseJSONValue returns nil. The documentation calls this out:

ParseJSONValue returns the JSON value corresponding to the parsed data, or null if the parsing fails.

You fail to check for such a condition, and the access violation is the inevitable consequence. Unless your JSON is pre-validated, you'll want to check its validity.

You can double check this yourself by pasting your JSON into an online validator. For example: http://jsonlint.com/ Do this and you will see that the JSON is not valid.

Here's some valid JSON:

StrJson=
'{' +
'  "response" : {' +
'    "distributor" : {' +
'      "id" : 1538,' +
'      "name" : "Arrow Electronics",' +
'      "authorized" : true,' +
'      "logoUrl" : "this is normally a URL but I cut it out"' +
'    },' +
'    "parts" : [ {' +
'      "manufacturer" : "National Semiconductor",' +
'      "part" : "LM741WG/883",' +
'      "description" : "OP Amp Single GP ±22V 10-Pin CFPAK Tray",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 65.0,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 88,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "National Semiconductor",' +
'      "part" : "LM741W/883",' +
'      "description" : "OP Amp Single GP ±22V 10-Pin CPAK Rail",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 40.5,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 1464,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741CH",' +
'      "description" : "OP Amp Single GP ±18V 8-Pin TO-99 Box",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 5.22,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 95,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741CN",' +
'      "description" : "OP Amp Single GP ±18V 8-Pin PDIP Rail",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 0.3633,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 4320,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741H",' +
'      "description" : "OP Amp Single GP ±22V 8-Pin TO-99 Box",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 5.22,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 3458,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741H",' +
'      "description" : "OP Amp Single GP ±22V 8-Pin TO-99 Box",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 5.71,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 0,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741CN/NOPB",' +
'      "description" : "OP Amp Single GP ±18V 8-Pin PDIP Rail",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 0.2977,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 6486,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741J",' +
'      "description" : "OP Amp Single GP ±22V 8-Pin CDIP Rail",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 7.21,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 362,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741H/NOPB",' +
'      "description" : "OP Amp Single GP ±22V 8-Pin TO-99 Box",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 5.22,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 1378,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741J/883",' +
'      "description" : "OP Amp Single GP ±22V 8-Pin CDIP Rail",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 11.8,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 989,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741H/883",' +
'      "description" : "OP Amp Single GP ±22V 8-Pin TO-99 Tray",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 15.74,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 4252,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }, {' +
'      "manufacturer" : "Texas Instruments",' +
'      "part" : "LM741CHNOPB",' +
'      "description" : "OP Amp Single GP ±18V 8-Pin TO-99 Box",' +
'      "price" : [ {' +
'        "quantity" : 0,' +
'        "price" : 5.22,' +
'        "currency" : "USD"' +
'      } ],' +
'      "stock" : 785,' +
'      "lastUpdated" : "2013-11-04 18:27:16 UTC"' +
'    }' +
'    ]' +
'  }' +
'}';

Whether or not it's what you want, I cannot be sure.

Plug this constant into your program, and it will advance further, but then fail on the Get('parts') line. That also returns nil and you get another AV when you try to read the JsonValue property.

Not knowing exactly what you are doing, I cannot tell you how to debug the entire code. What you do need to do is to start taking note of the fact that these JSON methods and properties may return nil. So check for that before you attempt to access methods and properties on a nil reference.

My other piece of advice is to put the JSON into a file so that it is easier to work with. Building up constants like this makes debugging very tricky.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Thank you. Must have crossed in the ether as I just modified the post with correctly formatted JSON data. Still the application encounters an AV. This time in the call to ParseJson. Trying to track this down now. – DoubleE Nov 04 '13 at 22:30
  • There is no method called `ParseJSON`. That's your main function. The problem that you asked about was due to invalid JSON. The next problem is, well, the next problem. Since we don't know for sure what the right JSON is, and what you are trying to do, we cannot debug your entire program. What we can do is answer the question that you asked. – David Heffernan Nov 04 '13 at 22:33
  • Not sure I understand your response. I replaced the source code with valid JSON in the original post (something I mentioned when I originally posted, if you see the first comment) and the program still generates an AV. Using the valid JSON. The issue is not simply invalid JSON. That was something I mentioned *may* be a problem with the posted code as I was removing things for brevity's sake. – DoubleE Nov 04 '13 at 22:46
  • Incidentally, the issue all along has been failing on the Get() line. It's in the subject of the post. – DoubleE Nov 04 '13 at 22:48
  • You posted a program and asked why it produced an access violation. And I answered that question. The code that you posted produced an AV because the JSON was invalid. You can execute the code in the post and observe that `LJsonObj` is `nil`. So yes, the call to `Get` fails because the subject of the method call is `nil`. And that's because the JSON is not valid. – David Heffernan Nov 04 '13 at 22:49
  • @DavidHeffernan -- And I thank you for the help you've given me so far. Truly. I really appreciate it. – DoubleE Nov 04 '13 at 23:03
  • There is no so far. I absolutely answered the question that you asked. You are now asking a new and different question. The etiquette here demands that you ask a new question. The question you asked has been solved. The point is this. Stack Overflow is a question and answer site. Questions are asked, and then answered. Your goal is to solve your problem. You may make progress to that solution by asking a question, or even more than one. But the goal at a single question is not to solve every different problem that you have. – David Heffernan Nov 04 '13 at 23:26
  • So, I don't much care for your edits to the question. I recommend that you revert them and ask a second question. You know understand that you need to make sure that your JSON is well formed. My other advice would be to cut it down drastically. You ought to be able to cut it down to just 10 or so lines. And put the JSON in a separate file so that we can read it clearly without Pascal syntax getting in the way. But most of all ask a new question. Please don't make this question into a chameleon question. – David Heffernan Nov 04 '13 at 23:27