从JSON对象获取嵌套的fieldNames

时间:2019-05-07 12:05:30

标签: c# json tree-traversal

我有一个包含types列表的JSON。这些类型有一些名称和某些字段。

字段具有dataType的属性,如果其值为object,则表示另一种类型。可以通过在referenceType属性中指定的名称来找到该类型。

还有一个名为parentType的属性,这意味着该类型是parentType的子级,它包含一些其他属性,但仅应视为parentType的对象。

我正在尝试处理此JSON,以获取数组中所有类型的所有嵌套属性名称。

{
    "types": [
        {
            "name": "User1",
            "fields": [
                {
                    "name": "name",
                    "dataType": "string"
                },
                {
                    "name": "address",
                    "dataType": "object",
                    "referenceType": "Address",
                    "isArray": true
                },
                {
                    "name": "weeklyRoles",
                    "dataType": "object",
                    "isArray": true,
                    "referenceType": "Role"
                }
            ]
        },
        {
            "name": "User2",
            "fields": [
                {
                    "name": "name",
                    "dataType": "string"
                },
                {
                    "name": "address",
                    "dataType": "object",
                    "referenceType": "Address",
                    "isArray": true
                }
            ]
        },
        {
            "name": "Address",
            "fields": [
                {
                    "name": "AddressLine1",
                    "dataType": "string"
                },
                {
                    "name": "AddressLine2",
                    "dataType": "string"
                }
            ]
        },
        {
            "name": "BusinessAddress",
            "parentType": "Address",
            "fields": [
                {
                    "name": "headquarters",
                    "dataType": "string"
                }
            ]
        },
        {
            "name": "ServiceAddress",
            "parentType": "Address",
            "fields": [
                {
                    "name": "servicePartner",
                    "dataType": "string"
                },
                {
                    "name": "serviceType",
                    "dataType": "string"
                }
            ]
        },
        {
            "name": "Role",
            "fields": [
                {
                    "name": "roleName",
                    "dataType": "string"
                },
                {
                    "name": "accessCountsObj1",
                    "dataType": "object",
                    "referenceType": "Role2"
                }
            ]
        },
        {
            "name": "Role2",
            "fields": [
                {
                    "name": "roleName2",
                    "dataType": "string"
                },
                {
                    "name": "accessCountsObj2",
                    "dataType": "object",
                    "referenceType": "Role3"
                }
            ]
        },
        {
            "name": "Role3",
            "fields": [
                {
                    "name": "roleName3",
                    "dataType": "string"
                },
                {
                    "name": "accessCountsObj3",
                    "dataType": "object",
                    "referenceType": "Role4"
                }
            ]
        },
        {
            "name": "Role4",
            "fields": [
                {
                    "name": "roleName4",
                    "dataType": "string"
                }
            ]
        }
    ]
}

我期望结果为<typeName>;<fieldName>.<nestedFieldName>

的模式

预期产量

[
    "User1;address.AddressLine1",
    "User1;address.AddressLine2",
    "User1;address.headquarters",
    "User1;address.servicePartner",
    "User1;address.serviceType",
    "User1;weeklyRoles.roleName",
    "User1;weeklyRoles.accessCountsObj1.roleName2",
    "User1;weeklyRoles.accessCountsObj1.accessCountsObj2.roleName3",
    "User1;weeklyRoles.accessCountsObj1.accessCountsObj2.accessCountsObj3.roleName4",
    "User2;address.AddressLine1",
    "User2;address.AddressLine2",
    "User2;address.headquarters",
    "User2;address.servicePartner",
    "User2;address.serviceType",
    "Role;accessCountsObj1.roleName2",
    "Role;accessCountsObj1.accessCountsObj2.roleName3",
    "Role;accessCountsObj1.accessCountsObj2.accessCountsObj3.roleName4",
    "Role2;accessCountsObj2.roleName3",
    "Role2;accessCountsObj2.accessCountsObj3.roleName4",
]

我试图编写一个递归函数来处理它,但是它没有给我预期的结果,也没有终止条件。

public IList<string> GetKeys(JArray types, string parentType = null)
{
    var nestedKeys = new List<string>();
    foreach (var type in types)
    {
        var fields = type[Constants.Fields].ToObject<List<JObject>>();
        var typeName = type.Value<string>("name");

        var nestedKeyBuilder = new StringBuilder($"{typeName};");
        if (!string.IsNullOrEmpty(parentType))
        {
            nestedKeyBuilder = new StringBuilder($"{parentType};");
        }

        foreach (var field in fields)
        {
            var datatype = field.Value<string>("dataType");
            if (string.Equals(datatype,"object"))
            {
                var fieldName = field.Value<string>("name");
                var referenceTypeName = field.Value<string>("referenceType");
                var referenceTypeObject = types.Where(t => string.Equals(t.Value<string>("name"), referenceTypeName))?.First();
                if (referenceTypeObject != null)
                {
                    var refTypeFields = referenceTypeObject["fields"].ToObject<List<JObject>>();
                    foreach (var refTypeField in refTypeFields)
                    {
                        var refTypeFieldName = refTypeField.Value<string>("name");
                        var refTypeDataType = refTypeField.Value<string>("dataType");
                        var refTypeReferenceTypeName = refTypeField.Value<string>("referenceType");
                        if (string.Equals(refTypeDataType, "object") && string.Equals(refTypeReferenceTypeName, currentReferenceType))
                        {
                            var refTypeNestedKeys = GetKeys(types, typeName);
                            nestedKeys.AddRange(refTypeNestedKeys);
                        }
                        else
                        {
                            nestedKeyBuilder.Append($"{fieldName}.{refTypeFieldName}");
                            nestedKeys.Add(nestedKeyBuilder.ToString());
                        }
                    }
                }
            }
        }
    }

    return nestedKeys;
}

3 个答案:

答案 0 :(得分:0)

有一个NuGet可用于处理JSON文件。

搜索Newtonsoft.Json https://eng.uber.com/forecasting-introduction/

您所有的问题都应该解决

答案 1 :(得分:0)

使用newtonsoft JSON反序列化JSON字符串。

JSON.Deserialize<IEnumberable<Type>>(jsonString);

这应该给您一个IEnumerable来处理它,但是您可以使用它。类型是您使用JSON属性作为类属性创建的类。您可以使用类似的东西

注意:“类型”和“字段”是非常模糊的名称。 Type是一个c#类,因此您不应使用它来创建自己的类。您将面临模棱两可的错误,并且需要完全限定名称空间才能使用您的类。强烈建议使用其他名称,并使用属性将其映射到JSON字符串。

[JsonObject(Title="People")]
public class Type
{

   [JsonProperty("name")]
   string Name{ get; set; }
   [JsonProperty("fields")]
   Field FieldValue[]{ get; set; }
}

答案 2 :(得分:0)

您可以使用Newtonsoft库执行此操作。 这是您的POCO课。

{
    public string name { get; set; }
    public string dataType { get; set; }
    public string referenceType { get; set; }
    public bool? isArray { get; set; }
}

public class Type
{
    public string name { get; set; }
    public List<Field> fields { get; set; }
    public string parentType { get; set; }
}

public class RootObject
{
    public List<Type> types { get; set; }
}

并将函数写入DeserializeObject

    [TestMethod]
    public void Read()
    {
        var sample1 = @"X:\JsonFilePath\data.json";
        var jsonString=File.ReadAllText(sample1);

        var result =JsonConvert.DeserializeObject<RootObject>(jsonString);
        Assert.IsNotNull(result);
    }
相关问题