private static bool IsDescendentOrSelf(SimpleXmlChange existingChange, SimpleXmlChange newChange) { var child = existingChange.Node; var parent = newChange.Node; if (child == parent) { if (child.Parent == null) { //either two deletes //or a node N was added and then deleted if (existingChange.Parent == newChange.Parent) { return true; } } else if (newChange.Parent == existingChange.Parent) { //do not return true in case of move return true; } } var pe = parent as XElement; if (pe != null) { for (var e = existingChange.Parent as XElement; e != null; e = e.Parent) { if (e == pe) { return true; } } } return false; }
private void OnBeforeChange(object sender, XObjectChangeEventArgs e) { var node = sender as XObject; // We do not allow editing DTDs through XmlModel if (node is XDocumentType) { var msg = String.Format(CultureInfo.CurrentCulture, Resources.VanillaProvider_DtdNodesReadOnly); throw new NotSupportedException(msg); } var action = e.ObjectChange; currentChange = null; XElement element = null; XAttribute attribute = null; XText text = null; XProcessingInstruction pi = null; XComment comment = null; switch (action) { case XObjectChange.Add: var addChange = new AddNodeChangeInternal(node, action); currentChange = addChange; break; case XObjectChange.Remove: var removeChange = new RemoveNodeChange(node, action); removeChange.Parent = node.Parent; if (removeChange.Parent == null) { removeChange.Parent = node.Document; } var attrib = (node as XAttribute); if (attrib != null) { removeChange.NextNode = attrib.NextAttribute; } else { removeChange.NextNode = (node as XNode).NextNode; } currentChange = removeChange; break; case XObjectChange.Name: var nameChange = new NodeNameChange(node, action); if ((element = node as XElement) != null) { nameChange.OldName = element.Name; } else if ((pi = node as XProcessingInstruction) != null) { nameChange.OldName = XName.Get(pi.Target); } else { Debug.Assert(false, "The name of something changed that we're not handling here!"); throw new NotSupportedException(); } currentChange = nameChange; break; case XObjectChange.Value: var valueChange = new NodeValueChange(node, action); if ((element = node as XElement) != null) { valueChange.OldValue = element.Value; } else if ((attribute = node as XAttribute) != null) { valueChange.OldValue = attribute.Value; } else if ((text = node as XText) != null) { valueChange.OldValue = text.Value; if (text.Parent != null) { valueChange.Parent = text.Parent; } else { valueChange.Parent = text.Document; } } else if ((comment = node as XComment) != null) { valueChange.OldValue = comment.Value; } else if ((pi = node as XProcessingInstruction) != null) { valueChange.OldValue = pi.Data; } else { Debug.Assert(false, "The value of something changed that we're not handling here!"); throw new NotSupportedException(); } currentChange = valueChange; break; } }
private RemoveStatus RemoveAllDescendentChanges(SimpleXmlChange newChange) { // This node is being removed, therefore any change to any child of this // node is now unnecessary, so we can filter them out. var rc = RemoveStatus.None; List<XmlModelCommand> toRemove = null; for (int i = committedPosition, n = txCommands.Count; i < n; i++) { var cmd = txCommands[i]; var change = cmd.Change; if (IsDescendentOrSelf(change, newChange)) { if (change.Node == newChange.Node && change.Action == XObjectChange.Add) { rc = RemoveStatus.FoundSelfAdd; // we are removing an add of the same node! } if (toRemove == null) { toRemove = new List<XmlModelCommand>(); } toRemove.Add(cmd); } } RemoveRange(txCommands, toRemove); return rc; }
public XmlModelCommand(SimpleXmlChange change) : base() { this._change = change; }