Domanda

Sto tentando di analizzare alcuni contenuti JSON in C #. Per i casi più semplici sto riscuotendo un grande successo con JSON.NET e apprezzo molto l'approccio pulito offerto dal provider LINQ. Ecco un esempio in cui sto scaricando informazioni su un livello in una mappa e compilando alcune proprietà su una classe chiamata (sorprendentemente!) Livello:

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

Puoi consultare questo URL per i dettagli di JSON per quel metodo: http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/WaterTemplate/WaterDistributionNetwork/MapServer/1?f=json&pretty=true . Ma il problema si presenta quando devo trasformare i singoli campi di dati associati ai livelli della mappa in una DataTable o anche solo in una struttura di dizionario. Il problema è che, a differenza dei feed RSS o di altri formati coerenti, i nomi dei campi e il numero di campi cambiano dal livello della mappa al livello della mappa. Ecco un esempio di me che eseguo una query:

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

Il codice che viene eseguito in layer.FindFeatureById è questo e include la parte in cui rimango bloccato:

        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.

    }

Puoi vedere lo sputo JSON visitando questo URL (nota la codifica quando tagli il file): href = " http: //sampleserver1.arcgisonline.com/ArcGIS/rest/services/WaterTemplate/WaterDistributionNetwork / MapServer / 1 / f = interrogazione jSON & amp;? outfields = * & amp; dove = FACILITYID% ??3d'13141'

Quindi la mia domanda (finalmente!) è questa. Come scorrere la raccolta di " attributi " nelle "caratteristiche" per ottenere i valori dei campi effettivi. Puoi vedere che ho capito come ottenere i nomi dei campi da FieldAliases, ma dopo sono sconcertato. Ho armeggiato con JsonReader su un file simile a questo, ma ancora senza gioia:

{
  "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
    }
  }
]
}
È stato utile?

Soluzione 2

Beh, si è scoperto che l'approccio migliore era usare un JsonTextReader e analizzare i dati invece di provare a usare LINQ. Ha molto sul rientro, il che mi rende infelice, ma suppongo che sia un effetto diretto dell'utilizzo di una struttura gerarchica di dati in primo luogo. Ecco come stampare l'elenco delle righe (" attributi ") e le loro raccolte nome / valore:

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

E questa volta devo anche gestire la geometria, quindi controlla questo URL per JSON che il codice sopra sta analizzando:

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

Altri suggerimenti

Per un modo rapido e sporco (non LINQ) per ottenere gli attributi e i valori, provare quanto segue:

JObject jo = JObject.Parse(json);

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

Non è l'ideale, ma funziona quando non si conoscono i nomi dei campi che torneranno. Se trovo un modo migliore per farlo, lo aggiornerò.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top