2009-09-10 9 views
9

Ich versuche, einige JSON-Inhalt in C# zu analysieren. Für die einfacheren Fälle bin ich sehr erfolgreich mit JSON.NET und schätze den sauberen Ansatz des LINQ-Anbieters. Hier ist ein Beispiel, wo ich Informationen über eine Schicht in einer Karte bin Download und in einigen Eigenschaften einer Klasse Füllung genannt Schicht (suprisingly!):LINQ und JSON.NET, wenn die Eigenschaftsnamen variieren

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

Sie an dieser URL für Details des JSON für die aussehen können Methode: http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/WaterTemplate/WaterDistributionNetwork/MapServer/1?f=json&pretty=true. Das Problem tritt jedoch auf, wenn ich die einzelnen Datenfelder, die mit Kartenebenen verknüpft sind, in eine DataTable oder sogar nur in eine Dictionary-Struktur umwandeln muss. Das Problem besteht darin, dass sich die Feldnamen und die Anzahl der Felder im Gegensatz zu RSS-Feeds oder anderen konsistenten Formaten von Kartenebene zu Kartenebene ändern. Hier ist ein Beispiel von mir eine Abfrage ausgeführt wird:

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

Der Code, der in layer.FindFeatureById laufen gelassen ist dies und schließt den Teil, wo ich stecken:

 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. 

    } 

Sie können die JSON sehen ausspucken durch Besuchen Sie diese URL (beachten Sie die Codierung beim Ausschneiden und Einfügen): href = "http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/WaterTemplate/WaterDistributionNetwork/MapServer/1/query?f=json & outFields = * & wo = FACILITYID% ​​3d'13141 '

Also meine Frage (endlich!) Ist das. Wie durchlaufe ich die Sammlung von "Attributen" in den "Features", um die tatsächlichen Feldwerte zu erhalten. Sie können sehen, dass ich herausgefunden habe, wie man die Feldnamen aus dem fieldAliases bekommt, aber danach bin ich ratlos. Ich habe auf eine Datei mit dem JsonReader worden bastelt, der so aussieht, aber noch keine Freude:

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

Antwort

3

Nun, es das der beste Ansatz stellte sich heraus, war ein JsonTextReader zu verwenden und rippen nur durch die Daten, anstatt zu versuchen LINQ verwenden. Es hat viele Einrückungen, die mich unglücklich machen, aber ich nehme an, das ist ein direkter Effekt der Verwendung einer hierarchischen Datenstruktur an erster Stelle. Hier ist, wie die Liste der Zeilen drucken („Attribute“) und deren Name/Wert-Sammlungen:

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

Und dieses Mal bin ich auch Geometrie zu handhaben ist, so überprüfen Sie diese URL für die JSON, dass die oben Code-Analyse:

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

6

Für eine schnelle und schmutzig (nicht-LINQ) Art und Weise an den Attributen und Werten zu erhalten, gehen Sie folgendermaßen vor:

JObject jo = JObject.Parse(json); 

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

Es ist nicht ideal, aber es funktioniert, wenn Sie die Feldnamen nicht kennen, die zurückkommen werden. Wenn ich einen besseren Weg finde, dies zu tun, werde ich es aktualisieren.

+0

Nun, das ist schön und einfach. danke für den Vorschlag. – Dylan