在C#中使用newtonsoft查找并返回JSON差异?
我想得到一个使用Newtonsoft进行比较时不匹配的JSON部分列表。
我有这个代码比较:
JObject xpctJSON = JObject.Parse(expectedJSON); JObject actJSON = JObject.Parse(actualJSON); bool res = JToken.DeepEquals(xpctJSON, actJSON);
但找不到任何可以返回差异的东西。
这是一个相对古老的问题,但是发布了解决此问题的可能方法之一,假设您想要的结果正是更改了哪些属性值
string sourceJsonString = "{'name':'John Doe','age':'25','hitcount':34}"; string targetJsonString = "{'name':'John Doe','age':'26','hitcount':30}"; JObject sourceJObject = JsonConvert.DeserializeObject(sourceJsonString); JObject targetJObject = JsonConvert.DeserializeObject (targetJsonString); if (!JToken.DeepEquals(sourceJObject, targetJObject)) { foreach (KeyValuePair sourceProperty in sourceJObject) { JProperty targetProp = targetJObject.Property(sourceProperty.Key); if (!JToken.DeepEquals(sourceProperty.Value, targetProp.Value)) { Console.WriteLine(string.Format("{0} property value is changed", sourceProperty.Key)); } else { Console.WriteLine(string.Format("{0} property value didn't change", sourceProperty.Key)); } } } else { Console.WriteLine("Objects are same"); }
注意:尚未针对非常深层次的层次结构进行测试。
这是我写的递归版本。 您使用两个JObject调用CompareObjects,它返回差异列表。 您使用两个JArrays调用CompareArrays并比较数组。 数组和对象可以互相嵌套。
更新 :@nttakr在下面的评论中指出,这种方法实际上是一种偏差算法。 它只会告诉您与源列表的不同之处。 如果源中不存在键但目标列表中存在该键,则将忽略该差异。 这是我的测试要求的设计。 这使您可以测试所需的项目,而无需在完成比较之前将其从目标中删除。
/// /// Deep compare two NewtonSoft JObjects. If they don't match, returns text diffs /// /// The expected results /// The actual results /// Text string private static StringBuilder CompareObjects(JObject source, JObject target) { StringBuilder returnString = new StringBuilder(); foreach (KeyValuePair sourcePair in source) { if (sourcePair.Value.Type == JTokenType.Object) { if (target.GetValue(sourcePair.Key) == null) { returnString.Append("Key " + sourcePair.Key + " not found" + Environment.NewLine); } else if (target.GetValue(sourcePair.Key).Type != JTokenType.Object) { returnString.Append("Key " + sourcePair.Key + " is not an object in target" + Environment.NewLine); } else { returnString.Append(CompareObjects(sourcePair.Value.ToObject(), target.GetValue(sourcePair.Key).ToObject ())); } } else if (sourcePair.Value.Type == JTokenType.Array) { if (target.GetValue(sourcePair.Key) == null) { returnString.Append("Key " + sourcePair.Key + " not found" + Environment.NewLine); } else { returnString.Append(CompareArrays(sourcePair.Value.ToObject(), target.GetValue(sourcePair.Key).ToObject (), sourcePair.Key)); } } else { JToken expected = sourcePair.Value; var actual = target.SelectToken(sourcePair.Key); if (actual == null) { returnString.Append("Key " + sourcePair.Key + " not found" + Environment.NewLine); } else { if (!JToken.DeepEquals(expected, actual)) { returnString.Append("Key " + sourcePair.Key + ": " + sourcePair.Value + " != " + target.Property(sourcePair.Key).Value + Environment.NewLine); } } } } return returnString; } /// /// Deep compare two NewtonSoft JArrays. If they don't match, returns text diffs /// /// The expected results /// The actual results /// The name of the array to use in the text diff /// Text string private static StringBuilder CompareArrays(JArray source, JArray target, string arrayName = "") { var returnString = new StringBuilder(); for (var index = 0; index < source.Count; index++) { var expected = source[index]; if (expected.Type == JTokenType.Object) { var actual = (index >= target.Count) ? new JObject() : target[index]; returnString.Append(CompareObjects(expected.ToObject(), actual.ToObject ())); } else { var actual = (index >= target.Count) ? "" : target[index]; if (!JToken.DeepEquals(expected, actual)) { if (String.IsNullOrEmpty(arrayName)) { returnString.Append("Index " + index + ": " + expected + " != " + actual + Environment.NewLine); } else { returnString.Append("Key " + arrayName + "[" + index + "]: " + expected + " != " + actual + Environment.NewLine); } } } } return returnString; }
只是为了帮助未来的查询。 我遇到了一个很好的json diff工具。 它对于json结构的diff / patch完美无缺:
jsondiffpatch.net还有一个nuget包。
用法很简单。
var jdp = new JsonDiffPatch(); JToken diffResult = jdp.Diff(leftJson, rightJson);
请注意以下库:
using System.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq;
我不完全确定我正确理解你的问题。 我假设您正在尝试确定实际JSON中缺少哪些键。
如果您只对缺少的KEYS感兴趣,以下代码将对您有所帮助,如果没有,请提供您尝试识别的差异类型的示例。
public IEnumerable DoCompare(string expectedJSON, string actualJSON) { // convert JSON to object JObject xptJson = JObject.Parse(expectedJSON); JObject actualJson = JObject.Parse(actualJSON); // read properties var xptProps = xptJson.Properties().ToList(); var actProps = actualJson.Properties().ToList(); // find missing properties var missingProps = xptProps.Where(expected => actProps.Where(actual => actual.Name == expected.Name).Count() == 0); return missingProps; }
注意,如果this方法返回一个空的IEnumerable,那么ACTUAL JSON根据预期的JSON结构具有所需的所有键。
注意:实际的JSON仍然可以包含更多不需要预期JSON的密钥。
进一步解释我的笔记……
假设您的预期JSON是:
{ Id: 1, Name: "Item One", Value: "Sample" }
而你的ACTUAL JSON是:
{ Id: 1, Name: "Item One", SomeProp: "x" }
上面的函数会告诉你Value键缺失,但是不会提到SomeProp键的任何内容……除非你交换输入参数。
- TextRenderer.MeasureText和Graphics.MeasureString的大小不匹配
- 当VirtualizingStackPanel.IsVirtualizing =“False”时,ItemContainerGenerator.ContainerFromItem()返回null
- 事件消息:发生了未处理的访问exception(IIS 7.5,无法加载网站)
- C#动态编译字符串和.cs文件
- 使用CsvHelper可以将空格转换为可空吗?
- .indexOf用于多个结果
- 在反序列化JSON String期间处理名称空间更改
- 对来自流读取器的过滤数据执行小计
- entity framework类中的两个相同的类类型问题