当属性名称变化时,LINQ和JSON.NET
-
05-07-2019 - |
题
我试图将一些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"];
您可以查看此网址,了解该方法的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吐出(请注意切割'n'paste时的编码):href =&quot; http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/WaterTemplate/WaterDistributionNetwork /地图服务器/ 1 /查询F = JSON&安培;外场= *&安培;其中= 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
}
}
]
}
解决方案 2
事实证明,最好的方法是使用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:
其他提示
要获得快速而脏的(非LINQ)方法来获取属性和值,请尝试以下操作:
JObject jo = JObject.Parse(json);
foreach (JObject j in jo["features"])
{
foreach (JProperty k in j["attributes"])
{
Console.WriteLine(k.Name + " = " + k.Value);
}
}
这并不理想,但是当你不知道将要回来的字段名称时,它会起作用。如果我找到更好的方法,我会更新它。