コード例 #1
0
        /// <summary>
        /// Formats and prints the resulting <see cref="ChangeList{T}"/> from a <see cref="DiffTrees(JsonNode, JsonNode)"/>.
        /// </summary>
        /// <returns>
        /// A string representation of the change list.
        /// </returns>
        public static string PrintTreeChangeList(ChangeList <JsonNode> changeList)
        {
            var treeToPrint = new PrintNode();

            for (int i = 0; i < changeList.Count; ++i)
            {
                var change = changeList[i];
                var node   = change.Value;
                var path   = new LinkedList <string>();
                // Use "it.Parent != null" instead of "it != null" to
                // ignore printing the root parent node that matches the opening bracket
                // for all JSON objects
                for (var it = node; it.Parent != null; it = it.Parent)
                {
                    path.AddFirst(it.Name);
                }

                var printNode = treeToPrint;
                // Build a tree of the change list values, placing nodes based off
                // their positions in the old or new tree
                foreach (var pathAtom in path)
                {
                    if (!printNode.Children.ContainsKey(pathAtom))
                    {
                        printNode.Children.Add(pathAtom, new PrintNode());
                    }

                    printNode = printNode.Children[pathAtom];
                }

                printNode.ChangedNodes.Add(change);
            }

            return(treeToPrint.ToString());
        }
コード例 #2
0
        /// <summary>
        /// Diffs two trees.
        /// </summary>
        /// <param name="rootA">
        /// The root of the original tree.
        /// </param>
        /// <param name="rootB">
        /// The root of the transformed tree.
        /// </param>
        /// <returns>
        /// A <see cref="ChangeList{JsonNode}"/> containing
        /// the leaf nodes that differ.
        /// </returns>
        public static ChangeList <JsonNode> DiffTrees(JsonNode rootA, JsonNode rootB)
        {
            var leavesA = CollectValueNodes(rootA);
            var leavesB = CollectValueNodes(rootB);

            var changeList = new ChangeList <JsonNode>(leavesA, leavesB);

            return(changeList);
        }
コード例 #3
0
            /// <summary>
            /// Returns the tree of changes encapusulated by this <see cref="PrintNode"/> as an indented, formatted string.
            /// </summary>
            public override string ToString()
            {
                using (var sbPool = Pools.GetStringBuilder())
                {
                    var sb    = sbPool.Instance;
                    var stack = new Stack <RecursionState>();
                    stack.Push(new RecursionState(this, -1, null));

                    while (stack.Count != 0)
                    {
                        var curr         = stack.Pop();
                        var indentPrefix = curr.Level > 0 ? new string('\t', curr.Level) : string.Empty;

                        if (curr.Name != null)
                        {
                            sb.AppendLine(indentPrefix + curr.Name);
                        }

                        // Each PrintNode represents one position in a tree. The values of a PrintNode represent nodes that were added or removed at that position.
                        // The max number of values at a position is 2, when a node is removed from one position and a new one is added at the same position.
                        // This is equivalent to modifying the state of that node.
                        switch (curr.PrintNode.ChangedNodes.Count)
                        {
                        // A node exists in one tree that does not exist in the other
                        // In this case, print all the values of the node as either added or removed
                        case 1:
                            var changeListValue = curr.PrintNode.ChangedNodes[0];
                            sb.Append(indentPrefix + changeListValue.ToString());
                            break;

                        // A node exists in both trees, but with different values (equivalent to modifying the node)
                        // Consolidate the print out by diffing just the values
                        case 2:
                            ChangeList <JsonNode> .ChangeListValue removed, added;
                            if (curr.PrintNode.ChangedNodes[0].ChangeType == ChangeList <JsonNode> .ChangeType.Removed)
                            {
                                removed = curr.PrintNode.ChangedNodes[0];
                                added   = curr.PrintNode.ChangedNodes[1];
                            }
                            else
                            {
                                removed = curr.PrintNode.ChangedNodes[1];
                                added   = curr.PrintNode.ChangedNodes[0];
                            }

                            // Order of removed vs added node is not guaranteed in the change list,
                            // but when diffing the nodes' values, the removed node represents a node from the old tree,
                            // so it should go first and represent the old list to get the correct diff.
                            var changeList = new ChangeList <string>(removed.Value.Values, added.Value.Values);

                            if (changeList.Count == 0)
                            {
                                // There was no difference in values between the removed node and added node,
                                // this means that the node simply moved positions.
                                // In this case, print the full list of values for both the removed and added node
                                sb.Append(indentPrefix + removed.ToString());
                                sb.Append(indentPrefix + added.ToString());
                            }
                            else
                            {
                                // Otherwise, rely on the normal diff
                                sb.Append(changeList.ToString(indentPrefix));
                            }

                            break;

                        default:
                            break;
                        }

                        foreach (var child in curr.PrintNode.Children)
                        {
                            stack.Push(new RecursionState(child.Value, curr.Level + 1, child.Key));
                        }
                    }

                    return(sb.ToString());
                }
            }