简体   繁体   中英

Newtonsoft.Json DeserializeObject only picking up the first two elements

In a C# class, I am trying to deserialize an JSON string which I get from the Google Place Autocomplete API ( https://maps.googleapis.com/maps/api/place/autocomplete/output?parameters ).

The JSON looks like this:

{
   "predictions" : [
      {
         "description" : "11 Sukhumvit Road, Khlong Toei, Bangkok, Thailand",
         "id" : "ca5d46b0982d28ee26c0aa2e94785688cff38357",
         "matched_substrings" : [
            {
               "length" : 2,
               "offset" : 0
            },
            {
               "length" : 2,
               "offset" : 3
            }
         ],
         "place_id" : "ChIJa68zyuae4jAR11FuV_P2eh4",
         "reference" : "CoQBcwAAAMWiPU84BlqBn84vF-fg3RPvBxYUWuSVpQ9QQuQy7mVLU1Z68z-4GZyfXqS8NGiTZ0OcG4VdSUKYbA-7rOdIdeixd6i2i_fxzUg_pwui61Tm82zdYV22JLYKeuuBh77iQ36GII9AWhKQzFYIeMR3W1PvdiQihpjalJIT9u3tNhH9EhAqh48JGeGZDrLGDzHvPQPrGhTvSTqfGzX5H_j7XpP6RptgsWbyKA",
         "structured_formatting" : {
            "main_text" : "11 Sukhumvit Road",
            "main_text_matched_substrings" : [
               {
                  "length" : 2,
                  "offset" : 0
               },
               {
                  "length" : 2,
                  "offset" : 3
               }
            ],
            "secondary_text" : "Khlong Toei, Bangkok, Thailand"
         },
         "terms" : [
            {
               "offset" : 0,
               "value" : "11"
            },
            {
               "offset" : 3,
               "value" : "Sukhumvit Road"
            },
            {
               "offset" : 19,
               "value" : "Khlong Toei"
            },
            {
               "offset" : 32,
               "value" : "Bangkok"
            },
            {
               "offset" : 41,
               "value" : "Thailand"
            }
         ],
         "types" : [ "street_address", "geocode" ]
      },
      {
         "description" : "11 Sukhumvit Road, Khlong Toei Nuea, Watthana, Bangkok, Thailand",
         "id" : "14aa9ff6b7d97031a4722e3ea0bfb71db1f5e718",
         "matched_substrings" : [
            {
               "length" : 2,
               "offset" : 0
            },
            {
               "length" : 2,
               "offset" : 3
            }
         ],
         "place_id" : "ChIJ2Rp_B_2e4jAR5kGy-6xSlmM",
         "reference" : "CpQBgwAAAFKqcxX6_22KbMz8NrEelwf76VZ4FfrJDJhnIEsoi5Pvy6hAuq8rNri1Bcp4amObhNxOa20EMSc4F82mHCzh3d3XSI0C04ERlael6zn71QnwraPmML5VpUuVJT3_pd-SrSwzFtQ-ekJIHJ62Nr42JM2HUO06JVKRWCdn9ZTFItgHT7LsjsExS0riUj3HXIzKjxIQqBO8Iysg1LkSUw6qaUMEQhoUZFSQeIa8z_qeEF39Af0SLV_MWy0",
         "structured_formatting" : {
            "main_text" : "11 Sukhumvit Road",
            "main_text_matched_substrings" : [
               {
                  "length" : 2,
                  "offset" : 0
               },
               {
                  "length" : 2,
                  "offset" : 3
               }
            ],
            "secondary_text" : "Khlong Toei Nuea, Watthana, Bangkok, Thailand"
         },
         "terms" : [
            {
               "offset" : 0,
               "value" : "11"
            },
            {
               "offset" : 3,
               "value" : "Sukhumvit Road"
            },
            {
               "offset" : 19,
               "value" : "Khlong Toei Nuea"
            },
            {
               "offset" : 37,
               "value" : "Watthana"
            },
            {
               "offset" : 47,
               "value" : "Bangkok"
            },
            {
               "offset" : 56,
               "value" : "Thailand"
            }
         ],
         "types" : [ "street_address", "geocode" ]
      },
      {
         "description" : "11 Sukhumvit Alley, Khlong Tan Nuea, Watthana, Bangkok, Thailand",
         "id" : "232f132abc93383477f9c3db792a064ce52ca026",
         "matched_substrings" : [
            {
               "length" : 2,
               "offset" : 0
            },
            {
               "length" : 2,
               "offset" : 3
            }
         ],
         "place_id" : "ChIJPR10XTWe4jARztw9WrjPuA8",
         "reference" : "CpQBgwAAALdNIHByCxKkyKPlVQUGObR_b_iHimkMzCgWSvd_G87jwMsft34B4PKYtTMRsLDdMuw7G2bMma_hiHvazg8I63qDYoNCH_GLQn6e9VkHaHvvcGtXsnglkvP2LVDfK_CCzAhtB537S05y7k5_5hpquG4MhzATqAGUhSQ9QBHw8mfaG30WNuJNrptWlcr27gH3LRIQYZ5rX2MGoVb3lwkw40jm3BoU6JlknjT6CTGWBLQnIzgfyKQphi0",
         "structured_formatting" : {
            "main_text" : "11 Sukhumvit Alley",
            "main_text_matched_substrings" : [
               {
                  "length" : 2,
                  "offset" : 0
               },
               {
                  "length" : 2,
                  "offset" : 3
               }
            ],
            "secondary_text" : "Khlong Tan Nuea, Watthana, Bangkok, Thailand"
         },
         "terms" : [
            {
               "offset" : 0,
               "value" : "11"
            },
            {
               "offset" : 3,
               "value" : "Sukhumvit Alley"
            },
            {
               "offset" : 20,
               "value" : "Khlong Tan Nuea"
            },
            {
               "offset" : 37,
               "value" : "Watthana"
            },
            {
               "offset" : 47,
               "value" : "Bangkok"
            },
            {
               "offset" : 56,
               "value" : "Thailand"
            }
         ],
         "types" : [ "street_address", "geocode" ]
      },
      {
         "description" : "11, Netaji Subhash Marg, Dariya Ganj, New Delhi, Delhi, India",
         "id" : "55e3234dcff96c3dc1fee533d5b1a360c5e228a2",
         "matched_substrings" : [
            {
               "length" : 2,
               "offset" : 0
            },
            {
               "length" : 2,
               "offset" : 11
            }
         ],
         "place_id" : "ChIJPwQlCiD9DDkR2ermrNsq4m8",
         "reference" : "CoQBfwAAAIsyxBsZzJLM5JUm6H_r_imzC-7NgVxN8ZQCORVMTHE3crhQjBheH5Hq2jzpe1UitduWJYKoPG9hVD9diwx3daMPumSwHosJvA_0MzVtBLuo-f0SgS9wbBqBpWtLZ-oCy6AzQJac190_1wy3sI6mYlRdUVDEmQkzyW92sRWfqR8_EhBY7Cb8oiDXCUtm5QqfkIu9GhSznlDT1_7dklnqyGe1hSPgP37JOA",
         "structured_formatting" : {
            "main_text" : "11, Netaji Subhash Marg",
            "main_text_matched_substrings" : [
               {
                  "length" : 2,
                  "offset" : 0
               },
               {
                  "length" : 2,
                  "offset" : 11
               }
            ],
            "secondary_text" : "Dariya Ganj, New Delhi, Delhi, India"
         },
         "terms" : [
            {
               "offset" : 0,
               "value" : "11"
            },
            {
               "offset" : 4,
               "value" : "Netaji Subhash Marg"
            },
            {
               "offset" : 25,
               "value" : "Dariya Ganj"
            },
            {
               "offset" : 38,
               "value" : "New Delhi"
            },
            {
               "offset" : 49,
               "value" : "Delhi"
            },
            {
               "offset" : 56,
               "value" : "India"
            }
         ],
         "types" : [ "street_address", "geocode" ]
      },
      {
         "description" : "11 Charan Sanitwong Road, Bang Ao, Bang Phlat, Bangkok, Thailand",
         "id" : "2bdd14e344854148907b4dd5eeed92db76c780c8",
         "matched_substrings" : [
            {
               "length" : 2,
               "offset" : 0
            }
         ],
         "place_id" : "ChIJ6RiwusKb4jARnKT4ah2YlHo",
         "reference" : "CpQBgwAAABENThY5H5mVwiWidokHm3bz-z-rkRoch04vGIKZV6fhSEe4fs4EX2qYPfzJw7HMDjfItx7Dlz0lGtShu5Sot3WELkz4U8PdclUfrSpMcB1jYjVIfUlYGVBdrKP0k6T-XwLSt3VCOXYFVd4lOcEvq-5Dwfcy9RstwenOXXWHHueI3PH6H-wBYFSEmJKY2Sg7ghIQg14EpHqs9If1hO-Khv4tsxoU_a-1az6q5a1VnWAZtJPvZsS4sNc",
         "structured_formatting" : {
            "main_text" : "11 Charan Sanitwong Road",
            "main_text_matched_substrings" : [
               {
                  "length" : 2,
                  "offset" : 0
               }
            ],
            "secondary_text" : "Bang Ao, Bang Phlat, Bangkok, Thailand"
         },
         "terms" : [
            {
               "offset" : 0,
               "value" : "11"
            },
            {
               "offset" : 3,
               "value" : "Charan Sanitwong Road"
            },
            {
               "offset" : 26,
               "value" : "Bang Ao"
            },
            {
               "offset" : 35,
               "value" : "Bang Phlat"
            },
            {
               "offset" : 47,
               "value" : "Bangkok"
            },
            {
               "offset" : 56,
               "value" : "Thailand"
            }
         ],
         "types" : [ "street_address", "geocode" ]
      }
   ],
   "status" : "OK"
}

When I run the following:

using Newtonsoft.Json.Linq;
JObject jObj = (JObject)JsonConvert.DeserializeObject(content);
Debug.Write(jObj.Count);

jObj.Count has a value of 2, when, as you can see in the JSON file, it has 5 child elements. Why is this?

(I'm trying to create a WinForms autocomplete textbox for Google Maps places)

Because the outer object has two properties, "predictions" and "status". You are looking at the elements of the "predictions" array within the outer object. Try this instead:

JObject jObj = (JObject)JsonConvert.DeserializeObject(content);
JArray predictions = (JArray)jObj["predictions"];
Debug.Write(predictions.Count);    

Fiddle: https://dotnetfiddle.net/NdlwUI

The most complete way to deserialize the JSON is to create a GooglePlaceModel class that contains all of the properties from the JSON response.

Once you have added the GooglePlaceModel, you can use JsonConvert.DeserializeObject to convert the JSON string to a GooglePlaceModel

Deserializing the Json

public GooglePlaceModel DeserializeGooglePlaceJson(string json)
{
    return JsonConvert.DeserializeObject<GooglePlaceModel>(json);
} 

GooglePlaceModel

using System;
using System.Collections.Generic;
using System.Globalization;

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

public class GooglePlaceModel
{
    [JsonProperty("predictions")]
    public List<Prediction> Predictions { get; set; }

    [JsonProperty("status")]
    public string Status { get; set; }
}

public class Prediction
{
    [JsonProperty("description")]
    public string Description { get; set; }

    [JsonProperty("id")]
    public string Id { get; set; }

    [JsonProperty("matched_substrings")]
    public List<MatchedSubstring> MatchedSubstrings { get; set; }

    [JsonProperty("place_id")]
    public string PlaceId { get; set; }

    [JsonProperty("reference")]
    public string Reference { get; set; }

    [JsonProperty("structured_formatting")]
    public StructuredFormatting StructuredFormatting { get; set; }

    [JsonProperty("terms")]
    public List<Term> Terms { get; set; }

    [JsonProperty("types")]
    public List<TypeElement> Types { get; set; }
}

public class MatchedSubstring
{
    [JsonProperty("length")]
    public long Length { get; set; }

    [JsonProperty("offset")]
    public long Offset { get; set; }
}

public class StructuredFormatting
{
    [JsonProperty("main_text")]
    public string MainText { get; set; }

    [JsonProperty("main_text_matched_substrings")]
    public List<MatchedSubstring> MainTextMatchedSubstrings { get; set; }

    [JsonProperty("secondary_text")]
    public string SecondaryText { get; set; }
}

public class Term
{
    [JsonProperty("offset")]
    public long Offset { get; set; }

    [JsonProperty("value")]
    public string Value { get; set; }
}

public enum TypeElement { Geocode, StreetAddress };

internal static class Converter
{
    public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
    {
        MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
        DateParseHandling = DateParseHandling.None,
        Converters = {
            TypeElementConverter.Singleton,
            new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
        },
    };
}

internal class TypeElementConverter : JsonConverter
{
    public override bool CanConvert(Type t) => t == typeof(TypeElement) || t == typeof(TypeElement?);

    public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null) return null;
        var value = serializer.Deserialize<string>(reader);
        switch (value)
        {
            case "geocode":
                return TypeElement.Geocode;
            case "street_address":
                return TypeElement.StreetAddress;
        }
        throw new Exception("Cannot unmarshal type TypeElement");
    }

    public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
    {
        if (untypedValue == null)
        {
            serializer.Serialize(writer, null);
            return;
        }
        var value = (TypeElement)untypedValue;
        switch (value)
        {
            case TypeElement.Geocode:
                serializer.Serialize(writer, "geocode");
                return;
            case TypeElement.StreetAddress:
                serializer.Serialize(writer, "street_address");
                return;
        }
        throw new Exception("Cannot marshal type TypeElement");
    }

    public static readonly TypeElementConverter Singleton = new TypeElementConverter();
}

Source for GooglePlaceModel: https://app.quicktype.io

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM