programing

JObject를 사전으로 변환

nasanasas 2020. 11. 23. 08:15
반응형

JObject를 사전으로 변환. 가능합니까?


JObject속성에 임의의 json 페이로드를 허용하는 웹 API 메서드가 있습니다. 따라서 나는 무엇이 올지 모르지만 여전히 .NET 유형으로 번역해야합니다. 내가 Dictionary<string,object>원하는 방식으로 처리 할 수 ​​있도록하고 싶습니다.

나는 많이 검색했지만 아무것도 찾을 수 없었고 결국이 변환을 수행하는 지저분한 방법을 시작했습니다. 쉽게 할 수있는 방법이 있습니까?

입력->

JObject person = new JObject(
    new JProperty("Name", "John Smith"),
    new JProperty("BirthDate", new DateTime(1983, 3, 20)),
    new JProperty("Hobbies", new JArray("Play football", "Programming")),
    new JProperty("Extra", new JObject(
        new JProperty("Foo", 1),
        new JProperty("Bar", new JArray(1, 2, 3))
    )
)

감사!


당신이 가지고있는 경우 JObject객체를, 다음이 작동하지 않을 수 있습니다 :

JObject person;
var values = person.ToObject<Dictionary<string, object>>();

없는 경우 확장 방법으로 JObject만들 수 있습니다 Newtonsoft.Json.Linq.

using Newtonsoft.Json.Linq;

var values = JObject.FromObject(person).ToObject<Dictionary<string, object>>();

그렇지 않으면 이 답변 이 JSON 문자열을 사전으로 역 직렬화하므로 올바른 방향을 가리킬 수 있습니다.

var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);

나는 아무도 실제로 그것을 못 박았 기 때문에 두 답변을 혼합하여 사용했습니다.

ToObject ()는 JSON 객체에서 첫 번째 수준의 속성을 수행 할 수 있지만 중첩 된 객체는 Dictionary ()로 변환되지 않습니다.

ToObject ()는 첫 번째 수준의 속성으로 매우 훌륭하므로 모든 것을 수동으로 할 필요가 없습니다.

다음은 코드입니다.

public static class JObjectExtensions
{
    public static IDictionary<string, object> ToDictionary(this JObject @object)
    {
        var result = @object.ToObject<Dictionary<string, object>>();

        var JObjectKeys = (from r in result
                           let key = r.Key
                           let value = r.Value
                           where value.GetType() == typeof(JObject)
                           select key).ToList();

        var JArrayKeys = (from r in result
                          let key = r.Key
                          let value = r.Value
                          where value.GetType() == typeof(JArray)
                          select key).ToList();

        JArrayKeys.ForEach(key => result[key] = ((JArray)result[key]).Values().Select(x => ((JValue)x).Value).ToArray());
        JObjectKeys.ForEach(key => result[key] = ToDictionary(result[key] as JObject));

        return result;
    }
}

작동하지 않고 성능이 가장 강력한 품질이 아닌 경우가있을 수 있습니다.

감사합니다!


시작 버전은 다음과 같습니다 . @Nawaz가 지적한대로 승인 된 답변에는 포함되지 않은 JArrays / JObjects에 중첩 된 JObjects를 JArrays 재귀 하도록 코드를 수정했습니다 .

using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;

public static class JsonConversionExtensions
{
    public static IDictionary<string, object> ToDictionary(this JObject json)
    {
        var propertyValuePairs = json.ToObject<Dictionary<string, object>>();
        ProcessJObjectProperties(propertyValuePairs);
        ProcessJArrayProperties(propertyValuePairs);
        return propertyValuePairs;
    }

    private static void ProcessJObjectProperties(IDictionary<string, object> propertyValuePairs)
    {
        var objectPropertyNames = (from property in propertyValuePairs
            let propertyName = property.Key
            let value = property.Value
            where value is JObject
            select propertyName).ToList();

        objectPropertyNames.ForEach(propertyName => propertyValuePairs[propertyName] = ToDictionary((JObject) propertyValuePairs[propertyName]));
    }

    private static void ProcessJArrayProperties(IDictionary<string, object> propertyValuePairs)
    {
        var arrayPropertyNames = (from property in propertyValuePairs
            let propertyName = property.Key
            let value = property.Value
            where value is JArray
            select propertyName).ToList();

        arrayPropertyNames.ForEach(propertyName => propertyValuePairs[propertyName] = ToArray((JArray) propertyValuePairs[propertyName]));
    }

    public static object[] ToArray(this JArray array)
    {
        return array.ToObject<object[]>().Select(ProcessArrayEntry).ToArray();
    }

    private static object ProcessArrayEntry(object value)
    {
        if (value is JObject)
        {
            return ToDictionary((JObject) value);
        }
        if (value is JArray)
        {
            return ToArray((JArray) value);
        }
        return value;
    }
}

확장 메서드에 대한 좋은 사용 사례처럼 들립니다. Json.NET으로 변환하는 것이 매우 간단합니다 (NuGet에 감사드립니다!).

Of course, this is quickly hacked together - you'd want to clean it up, etc.

public static class JTokenExt
{
    public static Dictionary<string, object> 
         Bagify(this JToken obj, string name = null)
    {
        name = name ?? "obj";
        if(obj is JObject)
        {
            var asBag =
                from prop in (obj as JObject).Properties()
                let propName = prop.Name
                let propValue = prop.Value is JValue 
                    ? new Dictionary<string,object>()
                        {
                            {prop.Name, prop.Value}
                        } 
                    :  prop.Value.Bagify(prop.Name)
                select new KeyValuePair<string, object>(propName, propValue);
            return asBag.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
        }
        if(obj is JArray)
        {
            var vals = (obj as JArray).Values();
            var alldicts = vals
                .SelectMany(val => val.Bagify(name))
                .Select(x => x.Value)
                .ToArray();
            return new Dictionary<string,object>()
            { 
                {name, (object)alldicts}
            };
        }
        if(obj is JValue)
        {
            return new Dictionary<string,object>()
            { 
                {name, (obj as JValue)}
            };
        }
        return new Dictionary<string,object>()
        { 
            {name, null}
        };
    }
}

Here is a simpler version:

    public static object ToCollections(object o)
    {
        var jo = o as JObject;
        if (jo != null) return jo.ToObject<IDictionary<string, object>>().ToDictionary(k => k.Key, v => ToCollections(v.Value));
        var ja = o as JArray;
        if (ja != null) return ja.ToObject<List<object>>().Select(ToCollections).ToList();
        return o;
    }

If using C# 7 we can use pattern matching where it would look like this:

    public static object ToCollections(object o)
    {
        if (o is JObject jo) return jo.ToObject<IDictionary<string, object>>().ToDictionary(k => k.Key, v => ToCollections(v.Value));
        if (o is JArray ja) return ja.ToObject<List<object>>().Select(ToCollections).ToList();
        return o;
    }

참고URL : https://stackoverflow.com/questions/14886800/convert-jobject-into-dictionarystring-object-is-it-possible

반응형