[英]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。“}
期望的結果是獲取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不匹配:
我懷疑可能有多個文檔,並且“映射”屬性包含這些文檔的列表,其中屬性名稱是動態的,並且與文檔名稱相對應。 完全可以解決這個問題,但不要使用反序列化+列表方法。
我在這里看到3種方法:
選項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.