比较相同结构的两个任意JToken-

时间:2015-10-08 18:07:07

标签: c# json json.net

提前致谢。我感谢任何帮助。

我想比较两个相同类型和结构的任意JTokens(来自NewtonSoft的Json.Net)。

static int CompareTokens(JToken x, JToken y);  
// possible output: 0 / 1 / -1

主要目标是能够使用此方法对两个Json字符串进行排序,这样即使在开始时它们具有相同的数据,但是顺序不同,最后这些是两个完全相同的字符串所以排序标准并不重要,重要的是这个标准总是一样的。并且应该考虑每个小数据元素。

JToken可以是以下几种类型之一:Array, Boolean, Date, Float, Guid, Integer, Null, Object, Property, String, TimeSpan, Uri。我没有考虑比较Bytes, Comment, Constructor, None, Undefined, Raw

  • 了解比较 JArrays JObjects 会很棒。这应该是一些递归比较,因为 JArrays 可能包含其他 JArrays JObjects ,反之亦然。任何想法都将不胜感激。
  • 但是了解比较更简单的类型也会非常有帮助。我想知道如何将 JToken 转换为实际类型(而不是知道如何逻辑地进行)。
  • JValue 已实现 IComparable ,但我没有弄清楚如何将简单类型 JToken 转换为 JValue 。了解这一点也会有所帮助。

这是一个很常见的问题。如果我弄明白该怎么做,我会给它加一个+100。对不起我的英语。

2 个答案:

答案 0 :(得分:8)

在Linq-to-JSON中,JValue表示原始值(字符串,数字,布尔值等)。它实现了IComparable<JValue>,因此Json.NET负责为您排序原始值。

基于此,您将需要以递归方式并行地下降两个fit f(x) data via *parameter* plot f(x), data using ((abs($2-f($1)) > threshold) ? $2 : NaN) 对象层次结构。当您遇到具有不同.Net类型的第一个令牌或不同的属性(如果不是JToken)或具有不同的值(如果是JValue)时,您需要返回比较值。

请记住以下内容:

  • 比较方法应该是反身的,反对称的和传递的。
  • 不同.Net类型的容器令牌需要按照一致的方式按类型排序。
  • 订购JValueJArray的子令牌。
  • JConstructor的子令牌不是,因此需要以一种稳定,对称的方式进行比较。按照属性名称的顺序行走似乎都有效。
  • 没有明显的方法来比较JObject,所以不要尝试,并抛出异常。

以下是原型实现:

JRaw

轻度测试prototype fiddle

答案 1 :(得分:2)

实际上,这可以用更少的代码完成。不太好,因为使用 字符串比较 而不是JValue比较。

以下不是我自己问题的确切答案,但目标已实现。

    public static JToken Normalize(this JToken token)
    {
        var result = token;

        switch (token.Type)
        {
            case JTokenType.Object:
                var jObject = (JObject)token;

                if (jObject != null && jObject.HasValues)
                {
                    var newObject = new JObject();

                    foreach (var property in jObject.Properties().OrderBy(x => x.Name).ToList())
                    {
                        var value = property.Value as JToken;
                        if (value != null)
                        {
                            value = Normalize(value);
                        }

                        newObject.Add(property.Name, value);
                    }
                    return newObject;
                }

                break;

            case JTokenType.Array:

                var jArray = (JArray)token;

                if (jArray != null && jArray.Count > 0)
                {
                    var normalizedArrayItems = jArray
                        .Select(x => Normalize(x))
                        .OrderBy(x => x.ToString(), StringComparer.Ordinal);

                    result = new JArray(normalizedArrayItems);
                }

                break;
            default:
                break;
        }

        return result;
    }