如何使用F# JsonProvider从URL读取JSON

3

我正在观看一个关于“为什么应该使用F#”的九频道视频,惊讶于从维基百科获取数据的简易程度。例如,他展示了以下列出《Doctor Who》不同出现次数的代码...

[<Literal>]
let url = @"https://en.wikipedia.org/wiki/Doctor_Who"
type DoctorWhoData = HtmlProvider<url>

let data = DoctorWhoData.GetSample()
let app = data.Tables.``Changes of appearance``.Rows

当他输入时,最后一行开启了Intellisense,这消除了查找数据的猜测。
我最近有一个从谷歌地图API提取一些数据的要求。例如,以下URL提取英国邮政编码SW1A 1AA(白金汉宫,如果有兴趣!)的数据...

http://maps.google.com/maps/api/geocode/json?address=sw1a+1aa+uk

鉴于数据只是Json格式,我认为使用F#从中提取信息应该同样容易。然而,当我尝试获取纬度和经度时遇到了困难。
我开始使用以下代码...
type GoogleData = JsonProvider<"http://maps.google.com/maps/api/geocode/json?address=sw1a+1aa+uk">

...但是在提取数据时卡住了。JSON包含一个条目的数组。其中包含一个 geometry 节点,该节点包含一个 location 节点,保存了两个值。以伪代码形式,我希望这样做...

let lat = GoogleData.GetSample().[0].geometry.location.lat

然而,这并没有起作用。我试过不使用GetSample(),但是没有取得更多进展。智能感知向我展示了一些与Json似乎不匹配的东西...在此输入图片描述 有人能指导我错在哪里吗?我该如何找到数据?更重要的是,我该如何让Intellisense帮助我?我设法在C#中做到了这一点,但是由于我必须使用动态对象,因此非常难以捉摸,所以没有获得Intellisense。根据我在那个视频中看到的内容,我希望在这里获得Intellisense。
1个回答

3
JSON响应包含两个顶级对象,resultsstatus
{
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "SW1A 1AA",
               "short_name" : "SW1A 1AA",
               "types" : [ "postal_code" ]
    //snip
    ],
    "status" : "OK"
}

纬度和经度在results下面,所以您需要从.GetSample()向下查找。

let lat = GoogleData.GetSample().Results.[0].Geometry.Location.Lat

要使用除示例数据以外的数据,请使用 Load 函数:

let honley = GoogleData.Load "http://maps.google.com/maps/api/geocode/json?address=honley+uk"
let honley_latlong = honley.Results.[0].Geometry.Location

//{
//  "lat": 53.602267,
//  "lng": -1.794173
//}
printfn "%A" honley_latlong

感谢您指出,我没有注意到状态也在顶层!有没有一种简洁的方法可以同时获取纬度和经度,比如 let (lat, lng) = ??? ,而不是两次调用整个行? - Avrohom Yisroel
2
你可以定义一个辅助函数 let ll2tp (ll: GoogleData.Northeast) = (ll.Lat, ll.Lng) 然后使用 let (lat, lng) = honley.Results.[0].Geometry.Location |> ll2tp 进行调用。 - DaveShaw
谢谢。不确定通过这种方式是否真的能够获得很多好处,但值得了解。再次感谢您的帮助。 - Avrohom Yisroel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接