【问题标题】:LINQ and JSON.NET when the property names vary属性名称不同时的 LINQ 和 JSON.NET
【发布时间】:2010-11-27 01:22:22
【问题描述】:

我正在尝试将一些 JSON 内容解析为 C#。对于更简单的情况,我在 JSON.NET 方面取得了巨大成功,并且非常感谢 LINQ 提供程序提供的简洁方法。这是一个示例,我正在下载有关地图中图层的信息并在名为(令人惊讶!)图层的类上填充一些属性:

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

您可以查看此 URL 以了解该方法的 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.

    }

您可以通过访问此 URL 来查看输出的 JSON(注意剪切粘贴时的编码):href="http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/WaterTemplate/WaterDistributionNetwork/ MapServer/1/query?f=json&outFields=*&where=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
    }
  }
]
}

【问题讨论】:

    标签: c# json.net json arcgis-server


    【解决方案1】:

    事实证明,最好的方法是使用 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;
                        }
                    }
                }
            }
    

    这一次我还必须处理几何图形,因此请查看上面代码正在解析的 JSON 的 URL:

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

    【讨论】:

      【解决方案2】:

      要获得一种快速而肮脏(非 LINQ)的方法来获取属性和值,请尝试以下方法:

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

      这并不理想,但是当您不知道将要返回的字段名称时,它可以工作。如果我找到更好的方法来做到这一点,我会更新它。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-25
        • 1970-01-01
        • 1970-01-01
        • 2014-12-11
        • 1970-01-01
        相关资源
        最近更新 更多