假设我有一个具有以下结构的 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是一个文档数组,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);
}
异常
{"Cannot deserialize the current JSON object (e.g. {\"name\":\"value\"}) into type 'System.Collections.Generic.List`1[DocumentType]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.\r\nTo fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.\r\nPath 'mappings', line 2, position 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; }
}
最佳答案
这里的问题是你的数据结构与 JSON 不匹配:
- JSON 中没有数组。因此,您无法将其反序列化为 C# 列表。
- “DocumentType”类与 JSON 完全不匹配。该类具有 Created、CustomerID 和 Deleted 属性,它们类似于 DateTime 和字符串。但是 JSON 没有 DateTime 或字符串。它们是具有名为“类型”和“格式”的子属性的对象。属性“元数据”不是字典:它是一个对象,具有一个名为“properties”的属性,该属性可能应该是一个字典。
- 大小写不符。
- 不要对 Id 和 DocumentId 做那种奇怪的事情。该类应与 JSON 完全匹配且字面意思。没有隐藏在属性中的业务逻辑。
- 根对象有一个名为“映射”的属性,因此您需要在获取文档之前向下钻取。
- 成功获取文档后,您将需要深入到名为“properties”的属性以找到您感兴趣的字段。
我怀疑可能有多个文档,并且“映射”属性包含这些文档的列表,其中属性名称是动态的并且对应于文档的名称。处理这个问题是完全合理的,但不使用反序列化 + 列表方法。
我在这里看到 3 种方法:
- 修复 JSON。不确定您的情况是否可行。如果是这样,首先让映射包含一个数组,而不是让每个文档成为一个以文档名称命名的属性。
- 修复反序列化代码以匹配 JSON 文档。 json2csharp 做得很好所以从它开始。它只是不知道“映射”实际上是一个字典,而不仅仅是具有名为“basedoc12_kja”的属性的东西。
- 根本不要反序列化它。只需查询元数据。看看http://www.newtonsoft.com/json/help/html/QueryingLINQtoJSON.htm其中展示了使用 JObject 属性和 LINQ 查询 JSON 的几种方法。
选项 1
如果你走那条路,稍微清理过的 JSON 的例子:
{
"mappings": [
{
"name"" : "basedoc_12kja",
"properties": {
""created": "20150522",
etc.
},
注意“映射”是一个数组,名称成为文档的属性。现在您可以创建一个 List<> 或使用 JArray。更好的办法是去掉顶部未使用的东西,像这样:
[
{
"name" : "basedoc_12kja",
"properties": {
"created"": "20150522",
etc.
},
]
现在它只是一个完全没有“映射”的数组。
** 选项 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 结构,它们仍然很困惑,但您至少可以到达那里。
希望对您有所帮助!
关于c# - 访问 json 文件中的子字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30401567/