private Patch CreatePatch( XmlNode sourceNode, XmlElement diffgramElement ) { Debug.Assert( sourceNode.NodeType == XmlNodeType.Document || sourceNode.NodeType == XmlNodeType.DocumentFragment ); Patch patch = new Patch( sourceNode ); _sourceRootNode = sourceNode; // create patch for <xmldiff> node children CreatePatchForChildren( sourceNode, diffgramElement, patch ); return patch; }
private void Patch(ref XmlNode sourceNode, XmlDocument diffDoc) { XmlElement diffgramEl = diffDoc.DocumentElement; if (diffgramEl.LocalName != "xmldiff" || diffgramEl.NamespaceURI != XmlDiff.NamespaceUri) { XmlPatchError.Error(XmlPatchError.ExpectingDiffgramElement); } XmlNamedNodeMap diffgramAttributes = diffgramEl.Attributes; XmlAttribute srcDocAttr = (XmlAttribute)diffgramAttributes.GetNamedItem("srcDocHash"); if (srcDocAttr == null) { XmlPatchError.Error(XmlPatchError.MissingSrcDocAttribute); } ulong hashValue = 0; try { hashValue = ulong.Parse(srcDocAttr.Value); } catch { XmlPatchError.Error(XmlPatchError.InvalidSrcDocAttribute); } XmlAttribute optionsAttr = (XmlAttribute)diffgramAttributes.GetNamedItem("options"); if (optionsAttr == null) { XmlPatchError.Error(XmlPatchError.MissingOptionsAttribute); } // parse options XmlDiffOptions xmlDiffOptions = XmlDiffOptions.None; try { xmlDiffOptions = XmlDiff.ParseOptions(optionsAttr.Value); } catch { XmlPatchError.Error(XmlPatchError.InvalidOptionsAttribute); } _ignoreChildOrder = ((int)xmlDiffOptions & (int)XmlDiffOptions.IgnoreChildOrder) != 0; // Calculate the hash value of source document and check if it agrees with // of srcDocHash attribute value. if (!XmlDiff.VerifySource(sourceNode, hashValue, xmlDiffOptions)) { XmlPatchError.Error(XmlPatchError.SrcDocMismatch); } // Translate diffgram & Apply patch if (sourceNode.NodeType == XmlNodeType.Document) { Patch patch = CreatePatch(sourceNode, diffgramEl); // create temporary root element and move all document children under it XmlDocument sourceDoc = (XmlDocument)sourceNode; XmlElement tempRoot = sourceDoc.CreateElement("tempRoot"); XmlNode child = sourceDoc.FirstChild; while (child != null) { XmlNode tmpChild = child.NextSibling; if (child.NodeType != XmlNodeType.XmlDeclaration && child.NodeType != XmlNodeType.DocumentType) { sourceDoc.RemoveChild(child); tempRoot.AppendChild(child); } child = tmpChild; } sourceDoc.AppendChild(tempRoot); // Apply patch XmlNode temp = null; patch.Apply(tempRoot, ref temp); // remove the temporary root element if (sourceNode.NodeType == XmlNodeType.Document) { sourceDoc.RemoveChild(tempRoot); Debug.Assert(tempRoot.Attributes.Count == 0); while ((child = tempRoot.FirstChild) != null) { tempRoot.RemoveChild(child); sourceDoc.AppendChild(child); } } } else if (sourceNode.NodeType == XmlNodeType.DocumentFragment) { Patch patch = CreatePatch(sourceNode, diffgramEl); XmlNode temp = null; patch.Apply(sourceNode, ref temp); } else { // create fragment with sourceNode as its only child XmlDocumentFragment fragment = sourceNode.OwnerDocument.CreateDocumentFragment(); XmlNode previousSourceParent = sourceNode.ParentNode; XmlNode previousSourceSibbling = sourceNode.PreviousSibling; if (previousSourceParent != null) { previousSourceParent.RemoveChild(sourceNode); } if (sourceNode.NodeType != XmlNodeType.XmlDeclaration) { fragment.AppendChild(sourceNode); } else { fragment.InnerXml = sourceNode.OuterXml; } Patch patch = CreatePatch(fragment, diffgramEl); XmlNode temp = null; patch.Apply(fragment, ref temp); XmlNodeList childNodes = fragment.ChildNodes; if (childNodes.Count != 1) { XmlPatchError.Error(XmlPatchError.InternalErrorMoreThanOneNodeLeft, childNodes.Count.ToString()); } sourceNode = childNodes.Item(0); fragment.RemoveAll(); if (previousSourceParent != null) { previousSourceParent.InsertAfter(sourceNode, previousSourceSibbling); } } }