skip to Main Content

I am trying to parse a JSON result from the Twitter API using Delphi XE7. I am getting an “Invalid class typecast” error, but I check the JSON with an online verifier and it is OK.

Here is the JSON result:

[
  {
    "trends":
    [
      {
        "name":"#OneDirectionIsOverParty",
        "url":"http://twitter.com/search?q=%23OneDirectionIsOverParty",
        "promoted_content":null,
        "query":"%23OneDirectionIsOverParty",
        "tweet_volume":410022
      },
      {
        "name":"#TheDarkKnight",
        "url":"http://twitter.com/search?q=%23TheDarkKnight",
        "promoted_content":null,
        "query":"%23TheDarkKnight",
        "tweet_volume":null
      },
      {
        "name":"#QuintaComOClubeSdv",
        "url":"http://twitter.com/search?q=%23QuintaComOClubeSdv",
        "promoted_content":null,
        "query":"%23QuintaComOClubeSdv",
        "tweet_volume":23756
      }
    ],
    "as_of":"2016-07-21T20:14:13Z",
    "created_at":"2016-07-21T20:08:31Z",
    "locations":
    [
      {
        "name":"Worldwide",
        "woeid":1
      }
    ]
  }
]

This is my parsing function:

procedure ParseJSON(const JSON: string);
var
 JSONObject: TJSONObject;
 MessageText: TJSONArray;
 NodeDetails: TJSONObject;
 MsgDetail: TJSONString;
 I: Integer;
 Item: TListItem;
begin
 JSONObject := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(JSON), 0) as TJSONObject;
 MessageText := JSONObject.Get('trends').JSONValue as TJSONArray;

for I := 0 to TJSONArray(MessageText).Size - 1 do
begin
  Item := Form1.ListView1.Items.Add;
  NodeDetails := MessageText.Get(I) as TJSONObject;
  MsgDetail := NodeDetails.Get('query').JSONValue as TJSONString;
  Item.Caption := MsgDetail.Value;
end;

Actually, this function works with other JSON results from the Twitter API. It is not working on this one result only.

2

Answers


  1. JSONObject := TJSONObject.ParseJSONValue(TEncoding.UTF8.GetBytes(JSON), 0) as TJSONObject;
    

    The root of the JSON is an array, not an object. Hence the error.

    You need to cast the return value of ParseJSONValue() to TJSONArray instead of TJSONObject, and then you can access the first element in the array and read its trends value. You already have code for parsing arrays, so you clearly know how to do that.

    If you are not clear on the JSON terminology of object and array, please read the JSON spec.

    Login or Signup to reply.
  2. As David has pointed out, the issue is that your code assumes that the JSON text is an object where in this specific case it is an array.

    In situations where code does not know whether a specific JSON container is an object or an array, my alternative JSON library provides a way to deal with this by providing a TJSONText class specifically for dealing with JSON where you do not necessarily know (or care) whether the JSON involved is an object or an array.

    In your case the resulting code would be something like:

    response := TJSONText.CreateFromUTF8(JSON);
    
    case response.ValueType of
      jsArray  : MessageText := response.AsArray[0].AsObject['trends'].AsArray;
      jsObject : MessageText := NIL;  // or as appropriate to extract "trends" from a single object response
    end;
    
    if Assigned(MessageText) then
    begin
      .. etc etc
    end;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search