DELPHI Google 地理编码 Json 解析器

DELPHI Google GEOCODE Json parser

使用 google 地理编码 API,当我使用 PHP 时,我可以这样做:

$request = file_get_contents("https://maps.googleapis.com/maps/api/geocode/json?latlng=-6.408107,107.468262&key=AIzaSyCUzlhl-ibUJsKCwWDwsZqjiW7EP_On30g&sensor=false");
$json = json_decode($request, true);
echo $json['results'][0]['address_components'][0]['long_name'];
echo $json['results'][0]['address_components'][1]['long_name'];

现在,如何在 DELPHI 上进行?我尝试了这个但是出现了异常

  myjson:=RESTResponse1.Content;
  JSONObject := TJSONObject.ParseJSONValue(myjson) as TJSONObject;
  JSONObject2 := JSONObject.GetValue('results') as TJSONObject;
  arrayjson := JSONObject2.GetValue('address_components') as TJSONArray;
  currcond := arrayjson.Items[0] as TJSONObject;
  showmessage(currcond.GetValue('long_name').Value);

您在 PHP 代码中访问的 JSON results 元素是数组类型。然而,在您的 Delphi 代码中,您试图将其作为对象访问。这会导致 arrayjson 变为 return nil,并且当您尝试访问 arrayjson 时,由于它不存在,您会得到一个 Access Violation 异常。

相反,您应该将第一个 results 元素作为数组读取。然后,要么读取该数组中的第一个 (0) 元素,要么遍历所有元素 - 视需要而定。

请参阅 https://github.com/hgourvest/superobject

处的代码示例

这个库更易于使用(比较你的源代码和我的)并且通常经过更多测试和更可靠(只需搜索有关 Delphi 捆绑 DBX JSON 的问题),这遗憾的是,最近的 Delphi "out of the box" 个库很常见。

简单化(但如果您需要多个数据项而不是一个数据项,则不是最优的!!!)方法就像

var json: iSuperObject;

json := TSuperObject.ParseStirng( RESTResponse1.Content );

ShowMessage( json[ 'results[0].address_components[0].long_name' ].AsString );

json := nil;  // clean-up after you no more need it

更好的是这样的(没有检查,只是一个快速草稿):

var json1, json2: iSuperObject;
    arr1, arr2: TSuperArray;
    i1, i2: integer;

json1 := TSuperObject.ParseStirng( RESTResponse1.Content );
arr1 := json1.AsArray;
for i1 := 0 to arr1.Length-1 do begin
  json2 := arr1.O[i1].O['address_components'];
  arr2  := json2.AsArray;
  for i2 := 0 to arr2.Length-1 do begin 
    ShowMessage( arr2.O[i2].S['long_name'] );
  end;
end;

json2 := nil; json1 := nil;

使用您可以在此处下载的 ALJsonDoc:https://sourceforge.net/projects/alcinoe/

或者使用 svn 更好: (svn) https://svn.code.sf.net/p/alcinoe/code/

你可以很容易地做到这一点:

function _FindLatLongU(const aQuery: String;
                                     var aID_Gmap: String;
                                     var aLatitude,
                                         aLongitude: Double;
                                     const aHighAccuracy: boolean = True): boolean;

var aHttp: Twin_HttpTaskU;
    aHTTPResponse: IHTTPResponse;
    aBytes: Tbytes;
    AResponseContentStream: TMemoryStream;
    ADecodedResponseContentStream: TStream;
    aFreeDecodedResponseContentStream: boolean;
    aJsonDoc: TalJsonDocumentU;
    S1: String;

begin

  try

    //init var
    Result := False;
    aID_Gmap := '';
    aLatitude := 999;
    aLongitude := 999;

    //create local object
    aHttp := Twin_HttpTaskU.Create;
    AResponseContentStream := TMemoryStream.Create;
    ADecodedResponseContentStream := nil;
    aFreeDecodedResponseContentStream := False;
    aJsonDoc := TalJsonDocumentU.Create(true);
    try

      //init aJsonDoc
      aJsonDoc.Options := [doNodeAutoCreate];

      //do the http request
      aHTTPResponse := aHttp.HttpClient.get('http://maps.googleapis.com/maps/api/geocode/json?'+   // json indicates output as JSON
                                             'address=' + TnetEncoding.URL.Encode(aQuery) + '&'+              // The address that you want to geocode.
                                             'sensor=false&'+                                      // Indicates whether or not the geocoding request comes from a device with a location sensor. This value must be either true or false.
                                             'language=en',
                                            AResponseContentStream); // AResponseContent

      //normally this never happen because it's raise an exception in previous step
      if aHTTPResponse.StatusCode <> 200 then exit(False);

      //decode the result if necessary
      {$if defined(_USE_ZLIB)}
      if ALSameTextU(aHTTPResponse.ContentEncoding, 'gzip') then begin
        ADecodedResponseContentStream := TDecompressionStream.Create(AResponseContentStream, 15 + 16); // 15 is the default mode.
        aFreeDecodedResponseContentStream := True;                                                     // 16 is to enable gzip mode.  http://www.zlib.net/manual.html#Advanced
      end
      else ADecodedResponseContentStream := AResponseContentStream;
      {$ELSE}
      ADecodedResponseContentStream := AResponseContentStream;
      {$ENDIF}

      //put the response in aJsonDoc
      ADecodedResponseContentStream.Position := 0;
      setlength(aBytes, ADecodedResponseContentStream.Size);
      ADecodedResponseContentStream.ReadBuffer(pointer(aBytes)^, ADecodedResponseContentStream.Size);
      S1 := Tencoding.UTF8.GetString(aBytes);  //{
                                               //   "results" : [
                                               //      {
                                               //         "address_components" : [
                                               //            {
                                               //               "long_name" : "Toledo",
                                               //               "short_name" : "Toledo",
                                               //               "types" : [ "locality", "political" ]
                                               //            },
                                               //            {
                                               //               "long_name" : "Toledo",
                                               //               "short_name" : "Toledo",
                                               //               "types" : [ "administrative_area_level_4", "political" ]
                                               //            },
                                               //            {
                                               //               "long_name" : "Vega de Toledo",
                                               //               "short_name" : "Vega de Toledo",
                                               //               "types" : [ "administrative_area_level_3", "political" ]
                                               //            },
                                               //            {
                                               //               "long_name" : "Toledo",
                                               //               "short_name" : "TO",
                                               //               "types" : [ "administrative_area_level_2", "political" ]
                                               //            },
                                               //            {
                                               //               "long_name" : "Castile-La Mancha",
                                               //               "short_name" : "CM",
                                               //               "types" : [ "administrative_area_level_1", "political" ]
                                               //            },
                                               //            {
                                               //               "long_name" : "Spain",
                                               //               "short_name" : "ES",
                                               //               "types" : [ "country", "political" ]
                                               //            }
                                               //         ],
                                               //         "formatted_address" : "Toledo, Toledo, Spain",
                                               //         "geometry" : {
                                               //            "bounds" : {
                                               //               "northeast" : {
                                               //                  "lat" : 39.88605099999999,
                                               //                  "lng" : -3.9192423
                                               //               },
                                               //               "southwest" : {
                                               //                  "lat" : 39.8383676,
                                               //                  "lng" : -4.0629256
                                               //               }
                                               //            },
                                               //            "location" : {
                                               //               "lat" : 39.8628316,
                                               //               "lng" : -4.027323099999999
                                               //            },
                                               //            "location_type" : "APPROXIMATE",
                                               //            "viewport" : {
                                               //               "northeast" : {
                                               //                  "lat" : 39.88605099999999,
                                               //                  "lng" : -3.9192423
                                               //               },
                                               //               "southwest" : {
                                               //                  "lat" : 39.8383676,
                                               //                  "lng" : -4.0629256
                                               //               }
                                               //            }
                                               //         },
                                               //         "place_id" : "ChIJ8f21C60Lag0R_q11auhbf8Y",
                                               //         "types" : [ "locality", "political" ]
                                               //      }
                                               //   ],
                                               //   "status" : "OK"
                                               //}
      aJsonDoc.LoadFromJSONString(S1);

      // "OK" indicates that no errors occurred; the address was successfully parsed and at least one geocode was returned.
      if ALSametextU(aJsonDoc.ChildNodes['status'].Text, 'OK') then begin

        // get only the first result (it's the most accurate)
        if ((aHighAccuracy) and (aJsonDoc.ChildNodes['results'].ChildNodes.Count = 1)) or
           ((not aHighAccuracy) and (aJsonDoc.ChildNodes['results'].ChildNodes.Count > 0)) then begin

          // extract ID of Google Maps, it looks like hash and must be saved as text.
          // An example: EisxMjAwMyBNYWluIFN0cmVldCwgQnJpYXJ3b29kLCBOWSAxMTQzNSwgVVNB
          aID_Gmap := aJSONDoc.ChildNodes['results'].ChildNodes[0].ChildNodes['place_id'].Text;

          //"geometry" : {
          //   "location" : {
          //      "lat" : 37.4224553,
          //      "lng" : -122.0843062
          //   },
          //   "location_type" : "ROOFTOP",
          //   "viewport" : {
          //      "northeast" : {
          //         "lat" : 37.42380428029149,
          //         "lng" : -122.0829572197085
          //      },
          //      "southwest" : {
          //         "lat" : 37.42110631970849,
          //        "lng" : -122.0856551802915
          //      }
          //   }
          //}
          with aJSONDoc.ChildNodes['results'].ChildNodes[0].ChildNodes['geometry'] do begin
            aLongitude := ALStrToFloatU(ChildNodes['location'].ChildNodes['lng'].Text, ALDefaultFormatSettingsU);
            aLatitude  := ALStrToFloatU(ChildNodes['location'].ChildNodes['lat'].Text, ALDefaultFormatSettingsU);
          end;

          //set result to true
          result := true;

        end;

      end;

    finally
      AResponseContentStream.Free;
      if aFreeDecodedResponseContentStream then aDecodedResponseContentStream.Free;
      aJsonDoc.Free;
      aHttp.Free;
    end;

  except
    result := False;
  end;

end;