2009-09-10 9 views
9

Próbuję parsować zawartość JSON w C#. Dla prostszych przypadków mam ogromny sukces z JSON.NET i naprawdę doceniam czyste podejście oferowane przez dostawcę LINQ. Oto przykład, gdzie jestem pobieranie informacji o warstwie w mapie i wypełniania niektórych właściwości na klasę o nazwie Layer (zaskakująco!):LINQ i JSON.NET, gdy nazwy właściwości różnią się

 using (var client = new WebClient()) 
     { 
      _content = client.DownloadString(_url.AbsoluteUri + OutputFormats.Json); 
     } 

     JObject json = JObject.Parse(_content); 
     IEnumerable<Field> fields = from f in json["fields"].Children() 
            select new Field(
             (string)f["name"], 
             (string)f["alias"], 
             (EsriFieldType)Enum.Parse(typeof(EsriFieldType), (string)f["type"]) 
             ); 
     _fields = fields.ToList(); 
     _displayFieldName = (string)json["displayField"]; 

Możesz zajrzeć pod tym adresem do szczegółów JSON za które metoda: http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/WaterTemplate/WaterDistributionNetwork/MapServer/1?f=json&pretty=true. Ale problem pojawia się, gdy potrzebuję włączyć poszczególne pola danych skojarzone z warstwami mapy do elementu DataTable lub nawet struktury słownika. Problem polega na tym, że w przeciwieństwie do kanałów RSS lub innych spójnych formatów nazwy pól i liczba pól zmienia się z warstwy mapy na warstwę mapy. Oto przykład ze mnie działa zapytania:

[Test] 
    [Category(Online)] 
    public void Can_query_a_single_feature_by_id() 
    { 
     var layer = _map.LayersWithName(ObjectMother.LayerWithoutOID)[0]; 
     layer.FindFeatureById("13141"); 
     Assert.IsNotNull(layer.QueryResults); 
    } 

Kod, który jest prowadzony w layer.FindFeatureById to jest i obejmuje część gdzie utknąć:

 public void FindFeatureById(string id) 
    { 
     var queryThis = ObjectIdField() ?? DisplayField(); 
     var queryUrl = string.Format("/query{0}&outFields=*&where=", OutputFormats.Json); 
     var whereClause = queryThis.DataType == typeof(string) 
           ? string.Format("{0}='{1}'", queryThis.Name, id) 
           : string.Format("{0}={1}", queryThis.Name, id); 
     var where = queryUrl + HttpUtility.UrlEncode(whereClause); 
     var url = new Uri(_url.AbsoluteUri + where); 
     Debug.WriteLine(url.AbsoluteUri); 
     string result; 

     using (var client = new WebClient()) 
     { 
      result = client.DownloadString(url); 
     } 

     JObject json = JObject.Parse(result); 
     IEnumerable<string> fields = from r in json["fieldAliases"].Children() 
            select ((JProperty)r).Name; 
     // Erm...not sure how to get this done. 
     // Basically need to populate class instances/rows with the 
     // values for each field where the list of fields is not 
     // known beforehand. 

    } 

Możesz zobaczyć JSON wypluć przez odwiedzając ten adres URL (zwróć uwagę na kodowanie podczas wycinania i wklejania): href = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/WaterTemplate/WaterDistributionNetwork/MapServer/1/query?f=json & outFields = * & gdzie = FACILITYID% ​​3d'13141 '

Moje pytanie (nareszcie!) Jest takie. Jak przechodzić przez kolekcję "atrybutów" w "funkcjach", aby uzyskać rzeczywiste wartości pól. Widać, że wymyśliłem, jak uzyskać nazwy pól z pola Aliases, ale po tym jestem zakłopotany. Byłem majstrować przy JsonReader na plik, który wygląda tak, ale jeszcze nie radość:

{ 
    "displayFieldName" : "FACILITYID", 
    "fieldAliases" : { 
    "FACILITYID" : "Facility Identifier", 
    "ACCOUNTID" : "Account Identifier", 
    "LOCATIONID" : "Location Identifier", 
    "CRITICAL" : "Critical Customer", 
    "ENABLED" : "Enabled", 
    "ACTIVEFLAG" : "Active Flag", 
    "OWNEDBY" : "Owned By", 
    "MAINTBY" : "Managed By" 
}, 
"features" : [ 
    { 
    "attributes" : { 
     "FACILITYID" : "3689", 
     "ACCOUNTID" : "12425", 
     "LOCATIONID" : "12425", 
     "CRITICAL" : 1, 
     "ENABLED" : 1, 
     "ACTIVEFLAG" : 1, 
     "OWNEDBY" : 1, 
     "MAINTBY" : 1 
    } 
    }, 
    { 
    "attributes" : { 
     "FACILITYID" : "4222", 
     "ACCOUNTID" : "12958", 
     "LOCATIONID" : "12958", 
     "CRITICAL" : 1, 
     "ENABLED" : 1, 
     "ACTIVEFLAG" : 1, 
     "OWNEDBY" : 1, 
     "MAINTBY" : 1 
    } 
    } 
] 
} 

Odpowiedz

3

Dobrze okazało się, że najlepsze podejście było użyć JsonTextReader i po prostu zgrać poprzez danych zamiast próbować używać LINQ. Ma wiele wcięć, co sprawia, że ​​jestem nieszczęśliwy, ale sądzę, że jest to bezpośredni efekt zastosowania hierarchicznej struktury danych. Oto jak wydrukować listę wierszy („atrybuty”) i ich kolekcje nazwa/wartość:

 using (var file = File.OpenText(_fileWithGeom)) 
     { 
      JsonReader reader = new JsonTextReader(file); 

      while (reader.Read()) 
      { 
       while (Convert.ToString(reader.Value) != "features") 
       { 
        reader.Read(); 
       } 

       Console.WriteLine("Found feature collections"); 

       // ignore stuff until we get to attribute array 

       while (reader.Read()) 
       { 
        switch (Convert.ToString(reader.Value)) 
        { 
         case "attributes": 
          Console.WriteLine("Found feature"); 
          reader.Read(); // get pass attributes property 

          do 
          { 
           // As long as we're still in the attribute list... 
           if (reader.TokenType == JsonToken.PropertyName) 
           { 
            var fieldName = Convert.ToString(reader.Value); 
            reader.Read(); 
            Console.WriteLine("Name: {0} Value: {1}", fieldName, reader.Value); 
           } 

           reader.Read(); 

          } while (reader.TokenType != JsonToken.EndObject 
            && Convert.ToString(reader.Value) != "attributes"); 
          break; 

         case "geometry": 
          Console.WriteLine("Found geometry"); 
          reader.Read(); 
          break; 
        } 
       } 
      } 
     } 

i tym razem ja także mający obsługiwać geometrię, więc sprawdź ten adres URL JSON, że powyższe Kod jest parsowania:

http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/WaterTemplate/WaterDistributionNetwork/MapServer/7/query?where=OBJECTID%3C10&returnGeometry=true&outSR=&outFields= * & f = pjson

6

na szybki i brudny (nie LINQ) sposób dostać się do atrybutów i wartości, spróbuj wykonać następujące czynności:

JObject jo = JObject.Parse(json); 

foreach (JObject j in jo["features"]) 
{ 
    foreach (JProperty k in j["attributes"]) 
    { 
    Console.WriteLine(k.Name + " = " + k.Value); 
    } 
} 

Nie jest idealny, ale działa, gdy nie znasz nazw pól, które będą wracać. Jeśli znajdę lepszy sposób, aby to zrobić, zaktualizuję go.

+0

Cóż, to jest ładne i proste. dzieki za sugestie. – Dylan

Powiązane problemy