2009-09-10 8 views
9

Я пытаюсь разобрать содержимое JSON на C#. Для более простых случаев я с большим успехом пользуюсь JSON.NET и очень ценю чистый подход, предлагаемый провайдером LINQ. Вот пример, где я загружая информацию о слое в карте и заполнение некоторых свойств на классе под названием Layer (удивительно!):LINQ и JSON.NET, когда имена свойств изменяются

 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"]; 

Вы можете посмотреть на эту ссылку для подробностей JSON для этого метод: http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/WaterTemplate/WaterDistributionNetwork/MapServer/1?f=json&pretty=true. Но проблема возникает, когда мне нужно, чтобы отдельные поля данных ассоциировались с слоями карты в DataTable или даже с помощью структуры словаря. Проблема в том, что в отличие от RSS-каналов или других согласованных форматов имена полей и количество полей изменяются с уровня карты на слой карты. Вот пример мне выполнения запроса:

[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); 
    } 

код, который работает в layer.FindFeatureById этим и включает в себя ту часть, где я застрять:

 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. 

    } 

Вы можете увидеть JSON выплюнуть по посетив этот URL-адрес (обратите внимание на кодировку при вырезании): href = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/WaterTemplate/WaterDistributionNetwork/MapServer/1/query?f=json & outFields = * & где = FACILITYID% ​​3d'13141 '

Итак, мой вопрос (наконец!). Как мне перебирать коллекцию «атрибутов» в «функциях», чтобы получить фактические значения полей. Вы можете видеть, что я выяснил, как получить имена полей из fieldAliases, но после этого я в тупике. Я уже возится с JsonReader на файл, который выглядит так, но до сих пор нет радости:

{ 
    "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 
    } 
    } 
] 
} 

ответ

3

Ну оказалось, что наилучший подход заключается в использовании JsonTextReader и просто отрываться через данные, а не пытаться использовать LINQ. У меня много отступов, что делает меня несчастным, но я полагаю, что это прямой эффект от использования иерархической структуры данных в первую очередь. Вот как напечатать список строк («Атрибуты») и их коллекции имя/значение:

 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; 
        } 
       } 
      } 
     } 

И на этот раз я также имеющий для обработки геометрии, поэтому проверить этот URL для JSON, что выше код разбора:

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

6

для быстрой и грязной (не LINQ) способ получить на атрибуты и значения, попробуйте следующее:

JObject jo = JObject.Parse(json); 

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

Это не идеальный вариант, но он работает, когда вы не знаете имена полей, которые будут возвращаться. Если я найду лучший способ сделать это, я обновлю его.

+0

хорошо, это хорошо и просто. спасибо за предложение. – Dylan

 Смежные вопросы

  • Нет связанных вопросов^_^