Get specific Value from Json String Delphi XE8

Dison picture Dison · Mar 2, 2016 · Viewed 8.7k times · Source

I have this Json String in Delphi,

{
  "bpd": {
    "euro": {
      "buying_rate": "48.50",
      "selling_rate": "52.70"
    },
    "dollar": {
      "buying_rate": "45.30",
      "selling_rate": "45.80"
    },
    "source": "https://www.popularenlinea.com/_api/web/lists/getbytitle('Rates')/items"
  },
  "blh": {
    "euro": {
      "buying_rate": "48.50",
      "selling_rate": "52.00"
    },
    "dollar": {
      "buying_rate": "45.35",
      "selling_rate": "45.80"
    },
    "source": "http://www.blh.com.do/Inicio.aspx"
  }
}

I want extract the buying_rate and selling_rate for the dollar for the bank blh

i try this but i get AV

  var
  LJsonObj  : TJSONObject;
  LRows, LElements, LItem : TJSONValue;
begin
    LJsonObj    := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(s),0) as TJSONObject;
  try
     LRows:=LJsonObj.Get(0).JsonValue;
     LElements:=TJSONObject(TJSONArray(LRows).Get(0)).Get(0).JsonValue;
     LItem :=TJSONObject(TJSONArray(LElements).Get(0)).Get(0).JsonValue;
     ShowMessage(TJSONObject(LItem).Get('buying_rate').JsonValue.Value);
  finally
     LJsonObj.Free;
  end;

Answer

David Heffernan picture David Heffernan · Mar 2, 2016

There are many errors in your code. The most significant is your repeated use of unchecked casts. When you write

TJSONArray(LRows)

you are telling the compiler that you know 100% for sure that LRows is descended from TJSONArray. Well, it isn't. Especially when you are dealing with external data you must not make such assumptions. You are then subject to the whims of the data that you receive. Use a checked cast instead

LRows as TJSONArray

Now, that's still wrong because LRows is not an array. In fact your JSON doesn't have any arrays at all. It just has objects. But when you use the checked cast the failure will be a meaningful error rather than an access violation.

This program reads the values you are looking for:

{$APPTYPE CONSOLE}

uses
  System.SysUtils, System.JSON, System.IOUtils;

procedure Main;
var
  s: string;
  LJsonObj: TJSONObject;
  blh: TJSONObject;
  dollar: TJSONObject;
  rate: TJSONString;
begin
  s := TFile.ReadAllText('C:\desktop\json.txt');
  LJsonObj := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(s), 0) as TJSONObject;
  try
    blh := LJsonObj.GetValue('blh') as TJSONObject;
    dollar := blh.GetValue('dollar') as TJSONObject;

    rate := dollar.GetValue('buying_rate') as TJSONString;
    Writeln(rate.Value);

    rate := dollar.GetValue('selling_rate') as TJSONString;
    Writeln(rate.Value);
  finally
    LJsonObj.Free;
  end;
end;

begin
  try
    Main;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Output

45.35
45.80

I advise you to spend some time at the JSON site to make sure that you have a very clear understanding of the terminology. You should have a clear understanding of what is meant by the terms object, array and value. At the moment I think that is lacking.