Esempio n. 1
0
        private IEnumerable <uSyncChange> CalculateChanges(TrackedItem change, XElement current, XElement target, string name, string path)
        {
            if (change == null)
            {
                return(Enumerable.Empty <uSyncChange>());
            }

            var changePath = GetChangePath(path, change.Path);
            var changeName = GetChangeName(name, change.Name);

            if (change.Repeating == null)
            {
                if (change.HasChildProperties)
                {
                    return(CalculatePropertyChanges(change, current, target, changeName, changePath));
                }
                else
                {
                    return(CalculateSingleChange(change, current, target, changeName, changePath));
                }
            }


            return(CalculateRepeatingChanges(change, current, target, changeName, changePath));
        }
Esempio n. 2
0
        /// <summary>
        ///  works out changes, when the child elements are all properties (and have their own node names)
        ///  this only works when each property is unique (no duplicates in a list)
        /// </summary>
        private IEnumerable <uSyncChange> CalculatePropertyChanges(TrackedItem change, XElement current, XElement target, string name, string path)
        {
            var updates = new List <uSyncChange>();

            var currentNode = current.XPathSelectElement(path);
            var targetNode  = target.XPathSelectElement(path);

            foreach (var childNode in currentNode.Elements())
            {
                var currentNodePath = GetChangePath(change.Path, $"/{childNode.Name.LocalName}");
                var currentNodeName = GetChangeName(change.Name, childNode.Name.LocalName);

                // we basically compare to target now.
                var targetChildNode = targetNode.Element(childNode.Name.LocalName);

                if (targetChildNode == null)
                {
                    // no target, this element will get deleted
                    updates.Add(uSyncChange.Delete(path, $"{name} [{childNode.Name.LocalName}]", GetElementValues(childNode)));
                    continue;
                }

                // check all the children of the current and target for changes
                if (change.Children != null && change.Children.Any())
                {
                    foreach (var child in change.Children)
                    {
                        updates.AddRange(CalculateChanges(child, currentNode, targetNode, currentNodeName, currentNodePath));
                    }
                }
                else
                {
                    var childValue       = childNode.ValueOrDefault(string.Empty);
                    var targetChildValue = targetChildNode.ValueOrDefault(string.Empty);

                    if (!childValue.Equals(targetChildValue))
                    {
                        // if there are no children, they we are comparing the actual text of the nodes
                        updates.AddNotNull(Compare(currentNodePath, currentNodeName,
                                                   childValue, targetChildValue,
                                                   change.MaskValue));
                    }
                }
            }

            // missing from current (so new)
            foreach (var targetChild in targetNode.Elements())
            {
                var currentChildNode = currentNode.Element(targetChild.Name.LocalName);
                if (currentChildNode == null)
                {
                    // not in current, its a new property.
                    updates.Add(uSyncChange.Create(path, $"{name} [{targetChild.Name.LocalName}]", GetElementValues(targetChild)));
                }
            }
            return(updates);
        }
Esempio n. 3
0
        /// <summary>
        ///  works out changes when we have a repeating block (e.g all the properties on a content type)
        /// </summary>
        private IEnumerable <uSyncChange> CalculateRepeatingChanges(TrackedItem change, XElement current, XElement target, string name, string path)
        {
            var updates = new List <uSyncChange>();

            var currentItems = current.XPathSelectElements(path);
            var targetItems  = target.XPathSelectElements(path);

            var currentIndex = 0;

            // loop through the nodes in the current item
            foreach (var currentNode in currentItems)
            {
                var currentNodePath = path;
                var currentNodeName = name;

                XElement targetNode = null;


                // if the key is blank we just compare the values in the elements
                if (string.IsNullOrWhiteSpace(change.Repeating.Key))
                {
                    if (change.Repeating.ElementsInOrder)
                    {
                        if (targetItems.Count() > currentIndex)
                        {
                            targetNode = targetItems.ElementAt(currentIndex);
                        }
                    }
                    else
                    {
                        // if the element isn't the key, then we get the first one (by value)
                        // if the value is different in this case we will consider this a delete
                        targetNode = targetItems.FirstOrDefault(x => x.Value == currentNode.Value);
                    }
                }
                else
                {
                    // we need to find the current key value
                    var currentKey = GetKeyValue(currentNode, change.Repeating.Key, change.Repeating.KeyIsAttribute);
                    if (currentKey == string.Empty)
                    {
                        continue;
                    }

                    // now we need to make the XPath for the children this will be [key = ''] or [@key ='']
                    // depending if its an attribute or element key
                    currentNodePath += MakeKeyPath(change.Repeating.Key, currentKey, change.Repeating.KeyIsAttribute);
                    if (!string.IsNullOrWhiteSpace(change.Repeating.Name))
                    {
                        var itemName = GetKeyValue(currentNode, change.Repeating.Name, change.Repeating.NameIsAttribute);
                        if (!string.IsNullOrWhiteSpace(itemName))
                        {
                            currentNodeName += $": {itemName}";
                        }
                    }

                    // now see if we can find that node in the target elements we have loaded
                    targetNode = GetTarget(targetItems, change.Repeating.Key, currentKey, change.Repeating.KeyIsAttribute);
                }

                if (targetNode == null)
                {
                    // no target, this element will get deleted
                    var oldValue = currentNode.Value;
                    if (!string.IsNullOrWhiteSpace(change.Repeating.Name))
                    {
                        oldValue = GetKeyValue(currentNode, change.Repeating.Name, change.Repeating.NameIsAttribute);
                    }

                    updates.Add(uSyncChange.Delete(path, name, oldValue));
                    continue;
                }

                // check all the children of the current and target for changes
                if (change.Children != null && change.Children.Any())
                {
                    foreach (var child in change.Children)
                    {
                        updates.AddRange(CalculateChanges(child, currentNode, targetNode, currentNodeName, currentNodePath));
                    }
                }
                else
                {
                    // if there are no children, they we are comparing the actual text of the nodes
                    updates.AddNotNull(Compare(currentNodePath, currentNodeName,
                                               currentNode.ValueOrDefault(string.Empty),
                                               targetNode.ValueOrDefault(string.Empty),
                                               change.MaskValue));
                }

                currentIndex++;
            }

            if (!change.Repeating.ElementsInOrder)
            {
                // look for things in target but not current (for they will be removed)
                List <XElement> missing = new List <XElement>();

                if (string.IsNullOrWhiteSpace(change.Repeating.Key))
                {
                    missing = targetItems.Where(x => !currentItems.Any(t => t.Value == x.Value))
                              .ToList();
                }
                else
                {
                    foreach (var targetItem in targetItems)
                    {
                        var targetNodePath = path;

                        var targetKey = GetKeyValue(targetItem, change.Repeating.Key, change.Repeating.KeyIsAttribute);
                        if (string.IsNullOrEmpty(targetKey))
                        {
                            continue;
                        }

                        targetNodePath += MakeKeyPath(change.Repeating.Key, targetKey, change.Repeating.KeyIsAttribute);
                        var currentNode = GetTarget(currentItems, change.Repeating.Key, targetKey, change.Repeating.KeyIsAttribute);
                        if (currentNode == null)
                        {
                            missing.Add(targetItem);
                        }
                    }
                }

                if (missing.Any())
                {
                    foreach (var missingItem in missing)
                    {
                        var oldValue = missingItem.Value;
                        if (!string.IsNullOrWhiteSpace(change.Repeating.Name))
                        {
                            oldValue = GetKeyValue(missingItem, change.Repeating.Name, change.Repeating.NameIsAttribute);
                        }

                        updates.Add(uSyncChange.Create(path, name, oldValue));
                    }
                }
            }

            return(updates);
        }
Esempio n. 4
0
        private IEnumerable <uSyncChange> CalculateSingleChange(TrackedItem change, XElement current, XElement target, string name, string path)
        {
            var updates = new List <uSyncChange>();

            var currentNode = current;
            var targetNode  = target;

            if (!string.IsNullOrEmpty(path))
            {
                currentNode = current.XPathSelectElement(path);
                targetNode  = target.XPathSelectElement(path);



                if (currentNode == null)
                {
                    if (targetNode != null)
                    {
                        return(uSyncChange.Create(path, name, targetNode.ValueOrDefault(string.Empty), change.CompareValue)
                               .AsEnumerableOfOne());
                    }

                    // if both are null, just return nothing.
                    return(updates);
                }

                if (targetNode == null)
                {
                    // its a delete (not in target)
                    return(uSyncChange.Delete(path, name, currentNode.ValueOrDefault(string.Empty), change.CompareValue)
                           .AsEnumerableOfOne());
                }

                // this happens if both exist, we compare values in them.

                if (change.CompareValue)
                {
                    // actual change
                    updates.AddNotNull(Compare(path, name,
                                               currentNode.ValueOrDefault(string.Empty),
                                               targetNode.ValueOrDefault(string.Empty),
                                               change.MaskValue));
                }

                if (change.Attributes != null && change.Attributes.Any())
                {
                    foreach (var attribute in change.Attributes)
                    {
                        var currentValue = currentNode.Attribute(attribute).ValueOrDefault(string.Empty);
                        var targetValue  = targetNode.Attribute(attribute).ValueOrDefault(string.Empty);
                        updates.AddNotNull(Compare(path, $"{name} [{attribute}]", currentValue, targetValue, change.MaskValue));
                    }
                }
            }

            if (change.Children != null && change.Children.Any())
            {
                foreach (var child in change.Children)
                {
                    updates.AddRange(CalculateChanges(child, currentNode, targetNode, name, path));
                }
            }

            return(updates);
        }