c# - 访问 json 文件中的子字段

标签 c# .net json.net

假设我有一个具有以下结构的 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."}

期望的结果是获取CertExp_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 不匹配:

  1. JSON 中没有数组。因此,您无法将其反序列化为 C# 列表。
  2. “DocumentType”类与 JSON 完全不匹配。该类具有 Created、CustomerID 和 Deleted 属性,它们类似于 DateTime 和字符串。但是 JSON 没有 DateTime 或字符串。它们是具有名为“类型”和“格式”的子属性的对象。属性“元数据”不是字典:它是一个对象,具有一个名为“properties”的属性,该属性可能应该是一个字典。
  3. 大小写不符。
  4. 不要对 Id 和 DocumentId 做那种奇怪的事情。该类应与 JSON 完全匹配且字面意思。没有隐藏在属性中的业务逻辑。
  5. 根对象有一个名为“映射”的属性,因此您需要在获取文档之前向下钻取。
  6. 成功获取文档后,您将需要深入到名为“properties”的属性以找到您感兴趣的字段。

我怀疑可能有多个文档,并且“映射”属性包含这些文档的列表,其中属性名称是动态的并且对应于文档的名称。处理这个问题是完全合理的,但不使用反序列化 + 列表方法。

我在这里看到 3 种方法:

  1. 修复 JSON。不确定您的情况是否可行。如果是这样,首先让映射包含一个数组,而不是让每个文档成为一个以文档名称命名的属性。
  2. 修复反序列化代码以匹配 JSON 文档。 json2csharp 做得很好所以从它开始。它只是不知道“映射”实际上是一个字典,而不仅仅是具有名为“basedoc12_kja”的属性的东西。
  3. 根本不要反序列化它。只需查询元数据。看看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/

相关文章:

c# - 包含特殊字符的哈希查询字符串不起作用

c# - 在 WPF 应用程序中激活 Dragon Naturally Speaking Full-Text Control 功能

c# - 使用 Xceed.Wpf.Toolkit 中的 MaskedTextBox 时出现 SetConnectionId 异常

c# - 使用永远不会发生的 `FirstAsync` 观察者任务来避免资源泄漏

C# 使用 XmlReader 获取额外的空白值,但不使用 XmlDocument

c# - 如何获取芒果的运营商详细信息?

c# - 何时调用 WebResponse.Close()

C# databound ComboBox 更改其他控件中的数据

c# - Json.NET ToObject 日期序列化格式

c# - 反序列化对象的所有值都设置为 Null