【问题标题】:DELPHI Google GEOCODE Json parser [closed]DELPHI Google GEOCODE Json解析器[关闭]
【发布时间】:2016-08-22 03:15:58
【问题描述】:

使用 google geocode 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);

【问题讨论】:

  • 你遇到了什么异常?其余的相关代码在哪里?
  • 我得到了access violation address,REST 结果是link 我使用TrestClientRestresponse
  • 访问冲突在什么地址等?这些数字确实意味着什么。您是否已开始调试以查看其中一项任务是否返回 nil?那会导致这样的异常。您在哪一行得到异常?
  • 地址0x009ebf24并停在本单元system.jsonfunction TJSONObject.GetCount: Integer; begin Result := FMembers.Count; end;
  • 思维混乱的经典案例。与地理编码无关。不要让它妨碍你。专注于json。这只是单曲?请 json 解析练习。花一些时间学习如何解析 json。阅读示例代码。周围有很多。阅读 json 规范,以便您了解这些概念。了解对象、数组和值之间的区别。等等。让学习和理解成为你的目标。然后你就可以自己写代码了。比希望我们做到这一点要好得多,让您不知道比现在更多。

标签: json delphi google-geocoder


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    https://github.com/hgourvest/superobject查看代码示例

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

    简单的(但如果您需要多个数据项而不是单个数据项,则不是非常理想!!!)方法就像

    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;
    

    【讨论】:

    • 在这里您建议询问者引入对不同 JSON 解析器的第三方依赖。您是否暗示提问者使用的 JSON 解析器无法解析此 JSON?请说清楚。如果你打算建议提问者使用一个新库,你应该为此提供动力。
    • Topic starter 并没有将他的问题限制在使用特定的库上,更何况他的经验不足表明他没有创建太多绑定到 DBX JSON 的代码,所以任何库都适合。
    • 现在您暗示 topicstarter 无法下载和复制文件。如果您的假设是正确的,那么他将不适合成为程序员,并且任何库都无法解决他的问题。您还暗示虽然 topicstarter 无法复制文件,但他能够以某种方式跟踪和解决或修复 DBX JSON 在不同 Delphi 版本中的所有错误。奥利?
    • 我已经添加了。激发新手投资的还有时间来学习和使用劣质库编写代码,只是赌博在 topicstarter 上永远不会有任何真实的、非平凡的数据的工作,或者当他会 - 会提供免费的劳动力来重写所有已经编写的代码这不是一个负责任的建议。
    • 有支持该功能的版本。为什么不使用内置库?它已记录在案,有很多例子。适用于所有平台。无需包含第三方软件。如果没有充分的理由去改变,你就会让自己的生活变得艰难。你很了解 JSON 吗?您知道 JSON 上下文中的术语对象、数组和值是什么意思吗?如果你不这样做,那么你就是在浪费每个人的时间,尤其是你自己的时间。
    【解决方案3】:

    使用可以在此处下载的 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;
    

    【讨论】:

    • 再一次,不必要地提供 OP 以使用另一个第三方 JSON 库。因此,此处提供使用SuperObject 的另一个答案实际上被否决了两次。此外,“非常容易”还有更多代码......?
    • Jerry,也许你必须先阅读这个问题,它无处问如何使用 DBXJson,但问如何解析一个 json 内容!!当 DBXjson 只是设计最糟糕的 json 解析器和我从未见过的最慢的解析器时,解释如何使用 DBXJson 是很愚蠢的(例如,比 alcinoe 或超级对象或其他任何东西慢 100 倍左右,而且毫不夸张)。还有你在哪里看到很多代码?? Alongitude = aJSONDoc.ChildNodes['results'].ChildNodes[0].ChildNodes['geometry'].ChildNodes['location'].ChildNodes['lng'].float 是更多代码吗?请给 dbxjson 等价物!
    • OP 发布了 6 行代码,其中只有一个需要纠正的小错误。你有 184 行代码。如果我把我的旧车给你,说它漏气了,你愿意让我买一辆完全不同的车,而不是修理漏气的轮胎吗?这当然是个好主意,但不是这样问的。
    • 你为人们写的代码越多,他们就越会回来要求我们再做一次:-)
    • @jerry: 哦,我不知道我们必须给出与报价请求者写的行数相对应的低质量响应:) 所以如果我理解你的话,我必须写数千行代码在我的问题中有一个高质量的答案吗?他们在我的回答中没有错我只是分享我自己对 google gmap 和 json 的经验,我不会减少代码行数以更充分地满足请求者编写的代码行数!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 2014-01-30
    • 2012-08-12
    • 1970-01-01
    • 2014-04-24
    • 1970-01-01
    相关资源
    最近更新 更多