2009-09-10 6 views
9

Je tente d'analyser certains contenus JSON en C#. Pour les cas les plus simples, j'ai beaucoup de succès avec JSON.NET et j'apprécie vraiment l'approche propre proposée par le fournisseur LINQ. Voici un exemple où je télécharge des informations sur une couche dans une carte et remplir certaines propriétés sur une classe appelée couche (suprisingly!):LINQ et JSON.NET lorsque les noms de propriétés varient

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

Vous pouvez regarder cette URL pour les détails de la JSON pour que méthode: http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/WaterTemplate/WaterDistributionNetwork/MapServer/1?f=json&pretty=true. Mais le problème vient quand j'ai besoin d'allumer les champs de données individuels associés à des couches de carte dans un DataTable ou même juste une structure de dictionnaire. Le problème est que, contrairement aux flux RSS ou à d'autres formats cohérents, les noms de champs et le nombre de champs changent de la couche de la carte à la couche de la carte. Voici un exemple de moi d'exécuter une requête:

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

Le code qui est exécuté dans layer.FindFeatureById est cela et comprend la partie où je suis coincé:

 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. 

    } 

Vous pouvez voir la JSON cracher par visitant cette URL (notez l'encodage quand vous coupez et collez): href = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/WaterTemplate/WaterDistributionNetwork/MapServer/1/query?f=json & outFields = * & où = FACILITYID% ​​3d'13141 '

Donc, ma question (enfin!) Est la suivante. Comment puis-je parcourir la collection des "attributs" dans les "caractéristiques" pour obtenir les valeurs réelles du champ. Vous pouvez voir que j'ai compris comment obtenir les noms de domaine des fieldAliases, mais après cela, je suis perplexe. J'ai été bricoler avec le JsonReader sur un fichier qui ressemble à ceci, mais toujours pas de joie:

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

Répondre

3

Eh bien, il est avéré que la meilleure approche était la d'utiliser un JsonTextReader et juste déchirer les données plutôt que d'essayer utiliser LINQ. Il y a beaucoup sur l'indentation qui me rend malheureux mais je suppose que c'est un effet direct de l'utilisation d'une structure de données hiérarchique en premier lieu. Voici comment imprimer la liste des lignes (« attributs ») et leurs collections nom/valeur:

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

Et cette fois, je suis aussi avoir à gérer la géométrie, afin de vérifier cette URL pour le JSON que ci-dessus Code est l'analyse:

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

6

pour un moyen d'obtenir les attributs et les valeurs rapide et sale (non LINQ), effectuez les opérations suivantes:

JObject jo = JObject.Parse(json); 

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

Ce n'est pas idéal, mais cela fonctionne quand vous ne connaissez pas les noms de champs qui reviendront. Si je trouve un meilleur moyen de le faire, je le mettrai à jour.

+0

bien c'est sympa et simple. Merci pour la suggestion. – Dylan

Questions connexes