/// <summary> /// Links the graph nodes of two objects together. This method will iterate on the children, references /// </summary> /// <param name="sourceRootNode"></param> /// <param name="targetRootNode"></param> /// <param name="linkAction"></param> public static void LinkNodes(IGraphNode sourceRootNode, IGraphNode targetRootNode, LinkActionDelegate linkAction, ReferenceMatchDelegate referenceMatch = null) { if (sourceRootNode == null) throw new ArgumentNullException(nameof(sourceRootNode)); if (targetRootNode == null) throw new ArgumentNullException(nameof(targetRootNode)); if (linkAction == null) throw new ArgumentNullException(nameof(linkAction)); if (referenceMatch == null) referenceMatch = (x, y) => Equals(x.Index, y.Index); var nodes = new Queue<ContentNodeLink>(); nodes.Enqueue(new ContentNodeLink(sourceRootNode, targetRootNode)); while (nodes.Count > 0) { var node = nodes.Dequeue(); linkAction(node.Source, node.Target); if (node.Target != null) { // Enqueue children foreach (var sourceChild in node.Source.Children) { var targetChild = node.Target.Children.FirstOrDefault(x => x.Name == sourceChild.Name); if (targetChild != null) { nodes.Enqueue(new ContentNodeLink(sourceChild, targetChild)); } } // Enqueue object reference var sourceObjectReference = node.Source.Content.Reference as ObjectReference; if (sourceObjectReference?.TargetNode != null) { var targetObjectReference = node.Target.Content.Reference.AsObject; nodes.Enqueue(new ContentNodeLink(sourceObjectReference.TargetNode, targetObjectReference?.TargetNode)); } // Enqueue enumerable references var sourceEnumReference = node.Source.Content.Reference as ReferenceEnumerable; var targetEnumReference = node.Target.Content.Reference as ReferenceEnumerable; if (sourceEnumReference != null && targetEnumReference != null) { foreach (var sourceReference in sourceEnumReference.Where(x => x.TargetNode != null)) { var targetReference = targetEnumReference.FirstOrDefault(x => referenceMatch(x, sourceReference)); if (targetReference != null) { nodes.Enqueue(new ContentNodeLink(sourceReference.TargetNode, targetReference.TargetNode)); } } } } } }
/// <summary> /// Links the graph nodes of two objects together. This method will iterate on the children and references /// </summary> /// <param name="sourceRootNode">The root node of the source graph.</param> /// <param name="targetRootNode">The root node of the target graph.</param> /// <param name="linkAction">The action to invoke to link nodes.</param> /// <param name="referenceMatch">A function that checks whether two elements of a collection are actually matching.</param> /// <param name="findTarget">An additional function that retrieve a target when the current target node is null.</param> public static void LinkNodes(IGraphNode sourceRootNode, IGraphNode targetRootNode, LinkActionDelegate linkAction, ReferenceMatchDelegate referenceMatch = null, FindTargetDelegate findTarget = null) { if (sourceRootNode == null) { throw new ArgumentNullException(nameof(sourceRootNode)); } if (linkAction == null) { throw new ArgumentNullException(nameof(linkAction)); } if (referenceMatch == null) { referenceMatch = (x, y) => Equals(x.Index, y.Index); } var nodes = new Queue <ContentNodeLink>(); nodes.Enqueue(new ContentNodeLink(sourceRootNode, targetRootNode)); while (nodes.Count > 0) { var node = nodes.Dequeue(); if (findTarget != null) { var target = findTarget(node.Source, node.Target); if (target != node.Target) { node = new ContentNodeLink(node.Source, target); } } if (node.Target != null) { linkAction(node.Source, node.Target); } // Enqueue children foreach (var sourceChild in node.Source.Children) { var targetChild = node.Target?.Children.FirstOrDefault(x => x.Name == sourceChild.Name); nodes.Enqueue(new ContentNodeLink(sourceChild, targetChild)); } // Enqueue object reference var sourceObjectReference = node.Source.Content.Reference as ObjectReference; if (sourceObjectReference?.TargetNode != null) { var targetObjectReference = node.Target?.Content.Reference.AsObject; nodes.Enqueue(new ContentNodeLink(sourceObjectReference.TargetNode, targetObjectReference?.TargetNode)); } // Enqueue enumerable references var sourceEnumReference = node.Source.Content.Reference as ReferenceEnumerable; var targetEnumReference = node.Target?.Content.Reference as ReferenceEnumerable; if (sourceEnumReference != null) { foreach (var sourceReference in sourceEnumReference.Where(x => x.TargetNode != null)) { var targetReference = targetEnumReference?.FirstOrDefault(x => referenceMatch(x, sourceReference)); nodes.Enqueue(new ContentNodeLink(sourceReference.TargetNode, targetReference?.TargetNode)); } } } }