假设我有一个具有以下结构的JSON文件。我如何访问元数据字段中的属性名称。
{
"mappings": {
"basedoc_12kja": {
"properties": {
"created": {
"type": "date",
"format": "dateOptionalTime"
},
"customerID": {
"type": "string"
},
"deleted": {
"type": "boolean"
},
"documentID": {
"type": "string"
},
"id": {
"type": "string"
},
"metadata": {
"properties": {
"Cert": {
"type": "string"
},
"Exp_date": {
"format": "dateOptionalTime"
},
}
}
}
}
}
}
Mappings是一个文档数组,映射的每个子字段都有不同的代码。我想获取每个文档的元数据字段,以找出它们之间共有的元数据字段。
我无法实例化此文档。
var response = esReader.GetIndicesMapping();
foreach (var mapping in response.Response.Values)
{
// Parse JSON into dynamic object, convenient!
dynamic results = JObject.Parse(mapping);
List<DocumentType> deserializedObject = JsonConvert.DeserializeObject<List<DocumentType>>(mapping);
}
异常
{“无法将当前JSON对象(例如{\”name \“:\”value \“})反序列化为类型'System.Collections.Generic.List`1 [DocumentType]',因为该类型需要JSON数组(例如[1,2,3])要正确反序列化。\ r \ n要修复此错误要么将JSON更改为JSON数组(例如[1,2,3]),要么更改反序列化类型以使其正常.NET类型(例如,不是整数的基本类型,不是类似于数组或List的集合类型),可以从JSON对象反序列化.JsonObjectAttribute也可以添加到类型中以强制它从JSON对象反序列化。 r \ nPath'mappings',第2行,第14位。“}
希望的结果是获取Cert
和Exp_date
字段的名称
修改
public class DocumentType
{
public string Id { set { DocumentID = value; } get { return DocumentID; } }
public string DocumentID { set; get; }
public DateTime Created { set; get; }
.
.
.
public Dictionary<string, object> Metadata { set; get; }
}
答案 0 :(得分:3)
这里的问题是您的数据结构与JSON不匹配:
我怀疑可能有多个文件,而且#34;映射&#34; property包含这些文档的列表,其中属性名称是动态的,并且对应于文档的名称。处理它是完全合理的,但不使用反序列化+列表方法。
我在这里看到3种方法:
选项1
如果您走这条路线,稍微清理一下JSON的示例:
{
"mappings": [
{
"name"" : "basedoc_12kja",
"properties": {
""created": "20150522",
etc.
},
注意&#34;映射&#34;是一个数组,名称成为文档的属性。现在你可以制作一个List&lt;&gt;或使用JArray。更好的是摆脱顶部未使用的东西,如:
[
{
"name" : "basedoc_12kja",
"properties": {
"created"": "20150522",
etc.
},
]
现在它只是一个没有&#34;映射的数组&#34;一点都不。
**选项2 ** 这是通过反序列化完成此操作的代码。有两个部分。第一步是使用json2charp生成的内容。我将此处包含在此供参考:
public class Created
{
public string type { get; set; }
public string format { get; set; }
}
public class CustomerID
{
public string type { get; set; }
}
public class Deleted
{
public string type { get; set; }
}
public class DocumentID
{
public string type { get; set; }
}
public class Id
{
public string type { get; set; }
}
public class Cert
{
public string type { get; set; }
}
public class ExpDate
{
public string format { get; set; }
}
public class Properties2
{
public Cert Cert { get; set; }
public ExpDate Exp_date { get; set; }
}
public class Metadata
{
public Properties2 properties { get; set; }
}
public class Properties
{
public Created created { get; set; }
public CustomerID customerID { get; set; }
public Deleted deleted { get; set; }
public DocumentID documentID { get; set; }
public Id id { get; set; }
public Metadata metadata { get; set; }
}
public class Basedoc12kja
{
public Properties properties { get; set; }
}
public class Mappings
{
public Basedoc12kja basedoc_12kja { get; set; }
}
public class RootObject
{
public Mappings mappings { get; set; }
}
然后,将Basedoc12kja重命名为DocumentType,并更改RootObject以保存字典。你明白了:
public class DocumentType
{
public Properties properties { get; set; }
}
public class RootObject
{
public Dictionary<string, DocumentType> mappings { get; set; }
}
如果您想访问除Cert和Exp_date之外的其他属性,请将元数据更改为:
public class Metadata
{
public Dictionary<string,object> properties { get; set; }
}
现在可以反序列化您的文档:
JObject results = JObject.Parse(mapping);
RootObject ro = results.ToObject<RootObject>()
您可以通过映射枚举并获取属性。由于JSON结构,它们仍然很混乱,但你至少可以到达那里。
我希望这有帮助!
答案 1 :(得分:2)
这里有一个命名属性的分层字典,其中每个属性都可以有一个类型,格式,以及可能的命名子属性的嵌套字典 - metadata
。您可以使用以下数据模型表示:
[DataContract]
public class PropertyData
{
[DataMember(Name="type", EmitDefaultValue=false)]
public string Type { get; set; }
[DataMember(Name = "format", EmitDefaultValue = false)]
public string Format { get; set; }
[DataMember(Name = "properties", EmitDefaultValue = false)]
public Dictionary<string, PropertyData> Properties { get; set; }
}
[DataContract]
public class Mappings
{
[DataMember(Name = "mappings", EmitDefaultValue = false)]
public Dictionary<string, PropertyData> DocumentMappings { get; set; }
}
(这个数据模型没有捕获这样一个事实,即给定的属性(可能)只能是一个简单类型或具有嵌套属性的复杂类型 - 但不能同时兼顾两者。但这似乎足以满足您的需求。 )
然后,根据上面的JSON,您将读入它并将其转换为文档名称到元数据属性名称的字典,如下所示:
var mappings = JsonConvert.DeserializeObject<Mappings>(json);
Debug.WriteLine(JsonConvert.SerializeObject(mappings, Formatting.Indented)); // Verify that all was read in.
var metadataNames = mappings.DocumentMappings.ToDictionary(doc => doc.Key, doc => doc.Value.Properties["metadata"].Properties.Select(p => p.Key).ToList());
Debug.WriteLine(JsonConvert.SerializeObject(metadataNames, Formatting.Indented)); // Inspect the resulting mapping table.
结果是您想要的元数据名称字典:
{ "basedoc_12kja": [ "Cert", "Exp_date" ] }
如果您担心有时可能会遗漏嵌套的metadata
,因此在上面的查询中生成NullReferenceExceptions
,您可以按如下方式添加空检查:
// Extension methods to query or walk through nested properties, avoiding null reference exceptions when properties are missing
public static class PropertyDataExtensions
{
public static IEnumerable<KeyValuePair<string, PropertyData>> GetProperties(this PropertyData data)
{
if (data == null || data.Properties == null)
return Enumerable.Empty<KeyValuePair<string, PropertyData>>();
return data.Properties;
}
public static PropertyData GetProperty(this PropertyData data, string name)
{
if (data == null || data.Properties == null)
return null;
PropertyData child;
if (!data.Properties.TryGetValue(name, out child))
return null;
return child;
}
}
然后:
var metadataNamesSafe = mappings.DocumentMappings.ToDictionary(doc => doc.Key, doc => doc.Value.GetProperty("metadata").GetProperties().Select(p => p.Key).ToList());