簡體   English   中英

訪問json文件中的子字段

[英]Accessing subfields in json file

假設我有一個具有以下結構的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"
            },
          }
        }
      }
    }
  }
}

映射是文檔的數組,映射的每個子字段都有不同的代碼。 我想獲取每個文檔的元數據字段,以找出它們之間共有的元數據字段。

我尚未實例化此文檔。

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 “映射”,第2行,位置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和string。 但是JSON沒有日期時間或字符串。 它們是具有名為“類型”和“格式”的子屬性的對象。 屬性“ Metadata”不是字典:它是一個對象,只有一個名為“ 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結構,它們仍然很凌亂,但是您至少可以到達那里。

我希望這有幫助!

您在這里擁有的是命名屬性的層次結構字典,其中每個屬性可以具有類型,格式以及命名子屬性的嵌套字典(在您的情況下為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());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM