不上不下一个JToken [英] Flattening out a JToken

查看:1872
本文介绍了不上不下一个JToken的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有以下JToken:

Suppose I have the following JToken:

@"{
    ""data"": [
        {
            ""company"": {
                ""ID"": ""12345"",
                ""location"": ""Some Location""
            },
            ""name"": ""Some Name""
        }
    ]
}";



我想这个令牌传递到一个FlattenToken函数输出该JToken:

I want to pass this token into a FlattenToken function that outputs this JToken:

@"{
    ""data"": [
        {
            ""company_ID"": ""12345"",
            ""company_location"": ""Some Location"",
            ""name"": ""Some Name""
        }
]}"

这样做的原因是这样的话,我就可以把扁平JToken并反序列化到一个DataTable。

The reason for doing this is so that I can then take the flattened JToken and deserialize it into a DataTable.

我迷失在JObjects,JTokens,JProperties和其他JMadness的混乱,虽然。我看到这个帖子,这是。有用的,但我仍然没有得到它的权利。

I'm getting lost in a jumble of JObjects, JTokens, JProperties, and other JMadness, though. I saw the answer on this post, which was helpful, but I'm still not getting it right.

下面是我到目前为止有:

Here's what I have so far:

public static JToken FlattenToken(JToken token)
{
    foreach (JToken topLevelItem in token["data"].Children())
    {
        foreach (JToken field in topLevelItem.Value<JToken>())
        {
            foreach (JProperty property in field.Value<JObject>().Properties())
            {
                field.AddAfterSelf(JObject.Parse(@"{""" + property.Name + "_" + property.Value));
            }

            field.Remove();
        }
    }

    return token;
}



通过外foreach循环的第一次迭代,topLevelItem =

The first iteration through the outer foreach loop, topLevelItem =

{
    "company": {
        "ID": "12345"
    },
    "name": "Some Name"
}

和通过第二的foreach第一次迭代环路,现场=

And the first iteration through the second foreach loop, field =

"company": {
    "ID": "12345"
}

找好为止。但是,当我打到最里面的foreach循环,我上线的foreach一个例外:不能投Newtonsoft.Json.Linq.JProperty到Newtonsoft.Json.Linq.JToken

Looking good so far. But when I hit the innermost foreach loop, I get an exception on the foreach line: "Cannot cast Newtonsoft.Json.Linq.JProperty to Newtonsoft.Json.Linq.JToken."

不知道发生了什么事情在那里。我的印象是,field.Value通话将要产生JToken并尝试将其转换为JProperty下。那么,是一个JProperty试图将铸造一个JToken,因为错误提示?

Not sure what's going on there. I was under the impression that the field.Value call was going to produce a JToken and try to cast it to a JProperty. So where is a JProperty trying to be casted to a JToken, as the error suggests?

此外,这种感觉就像不上不下一个JToken一个漂亮的毛路。有没有更好的办法?

Also, this feels like a pretty gross way of flattening out a JToken. Is there a better way?

推荐答案

对象的Json.NET的层次结构可以是相当深刻的。一个粗略的指南可以在找到这个答案

The hierarchy of objects in Json.NET can be rather deep. A rough guide can be found in this answer.

要解决你的问题,你首先需要一个扩展方法采取的 JObject 属性和然后返回使用一个名称前缀的集合:

To solve your problem, you first need an extension method to take the properties of a JObject and return then in a collection with a name prefix:

public static class JsonExtensions
{
    public static IEnumerable<KeyValuePair<string, JToken>> FlattenFields(this JObject obj, string prefix)
    {
        foreach (var field in obj)
        {
            string fieldName = prefix + "_" + field.Key;
            var fieldValue = field.Value;
            yield return new KeyValuePair<string, JToken>(fieldName, fieldValue);
        }
    }
}



接下来,你需要一些递归工具通过Json.NET层次遍历并重写选定的 JObject 的属性的集合:

public static class JsonExtensions
{
    public static IEnumerable<T> Yield<T>(this T item)
    {
        yield return item;
    }

    public static JToken EditFields(this JToken token, Func<KeyValuePair<string, JToken>, IEnumerable<KeyValuePair<string, JToken>>> editor)
    {
        if (token == null)
            return null;
        switch (token.Type)
        {
            case JTokenType.Array:
                return EditFields((JArray)token, editor);
            case JTokenType.Object:
                return EditFields((JObject)token, editor);
            default:
                return token;
        }
    }

    static JToken EditFields(JArray array, Func<KeyValuePair<string, JToken>, IEnumerable<KeyValuePair<string, JToken>>> editor)
    {
        JArray newArray = null;
        foreach (var element in array)
        {
            var newElement = EditFields(element, editor);
            if (newElement != null)
            {
                if (newArray == null)
                    newArray = new JArray();
                newArray.Add(newElement);
            }
        }
        return newArray;
    }

    static JToken EditFields(JObject obj, Func<KeyValuePair<string, JToken>, IEnumerable<KeyValuePair<string, JToken>>> editor)
    {
        JObject newObj = null;

        foreach (var field in obj)
        {
            foreach (var newField in editor(field))
            {
                if (newObj == null)
                    newObj = new JObject();
                newObj[newField.Key] = newField.Value.EditFields(editor);
            }
        }

        return newObj;
    }
}



最后,把这些结合在一起创造一个促进的方法他们的父母一个名为 JObject 属性的属性 JObject ,前面加上属性名加上下划线:

Finally, put these together to create a method that promotes properties of a named JObject property to their parent JObject, prepending the property name plus an underscore:

public static class JsonExtensions
{
    public static JToken PromoteNamedPropertiesToParents(this JToken token, string propertyName)
    {
        return token.EditFields(pair =>
        {
            if (pair.Key == propertyName && pair.Value is JObject)
            {
                return ((JObject)pair.Value).FlattenFields(pair.Key);
            }
            return pair.Yield();
        });
    }
}

然后,测试一下:

public static class TestFlatten
{
    public static void Test()
    {
        string jsonString = @"{
            ""data"": [
                {
                    ""company"": {
                        ""ID"": ""12345"",
                        ""location"": ""Some Location""
                    },
                    ""name"": ""Some Name""
                }
            ]
        }";
        JObject obj = JObject.Parse(jsonString);
        var newObj = (JObject)obj.PromoteNamedPropertiesToParents("company");
        Debug.WriteLine(newObj);
    }
}

和输出是:

{
  "data": [
    {
      "company_ID": "12345",
      "company_location": "Some Location",
      "name": "Some Name"
    }
  ]
}

这是你想要的东西。请注意,此代码创建了一个新的 JObject 层次结构,而不是修改原来的层次结构。

Which is what you want. Please note that this code creates a new JObject hierarchy rather than modifying the original hierarchy.

这篇关于不上不下一个JToken的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆