private void PreprocessDiffgram(XmlDocument diffgramDoc) { // read xmldiff options XmlAttribute attr = (XmlAttribute)diffgramDoc.DocumentElement.Attributes.GetNamedItem("options"); if (attr == null) { throw new Exception("Missing 'options' attribute in the diffgram."); } string optionsAttr = attr.Value; XmlDiffOptions options = XmlDiff.ParseOptions(optionsAttr); _bIgnoreChildOrder = (((int)options & (int)(XmlDiffOptions.IgnoreChildOrder)) > 0); _bIgnoreComments = (((int)options & (int)(XmlDiffOptions.IgnoreComments)) > 0); _bIgnorePI = (((int)options & (int)(XmlDiffOptions.IgnorePI)) > 0); _bIgnoreWhitespace = (((int)options & (int)(XmlDiffOptions.IgnoreWhitespace)) > 0); _bIgnoreNamespaces = (((int)options & (int)(XmlDiffOptions.IgnoreNamespaces)) > 0); _bIgnorePrefixes = (((int)options & (int)(XmlDiffOptions.IgnorePrefixes)) > 0); _bIgnoreDtd = (((int)options & (int)(XmlDiffOptions.IgnoreDtd)) > 0); if (_bIgnoreNamespaces) { _bIgnorePrefixes = true; } // read descriptors XmlNodeList children = diffgramDoc.DocumentElement.ChildNodes; IEnumerator e = children.GetEnumerator(); while (e.MoveNext()) { XmlElement desc = e.Current as XmlElement; if (desc != null && desc.LocalName == "descriptor") { int opid = int.Parse(desc.GetAttribute("opid")); OperationDescriptor.Type type; switch (desc.GetAttribute("type")) { case "move": type = OperationDescriptor.Type.Move; break; case "prefix change": type = OperationDescriptor.Type.PrefixChange; break; case "namespace change": type = OperationDescriptor.Type.NamespaceChange; break; default: throw new Exception("Invalid descriptor type."); } OperationDescriptor od = new OperationDescriptor(opid, type); _descriptors[opid] = od; } } }
private void PreprocessDiffgram(XmlDocument diffgramDoc) { var namedItem = (XmlAttribute)diffgramDoc.DocumentElement.Attributes.GetNamedItem("options"); if (namedItem == null) { throw new Exception("Missing 'options' attribute in the diffgram."); } var options = XmlDiff.ParseOptions(namedItem.Value); this._bIgnoreChildOrder = (options & XmlDiffOptions.IgnoreChildOrder) > XmlDiffOptions.None; this._bIgnoreComments = (options & XmlDiffOptions.IgnoreComments) > XmlDiffOptions.None; this._bIgnorePI = (options & XmlDiffOptions.IgnorePI) > XmlDiffOptions.None; this._bIgnoreWhitespace = (options & XmlDiffOptions.IgnoreWhitespace) > XmlDiffOptions.None; this._bIgnoreNamespaces = (options & XmlDiffOptions.IgnoreNamespaces) > XmlDiffOptions.None; this._bIgnorePrefixes = (options & XmlDiffOptions.IgnorePrefixes) > XmlDiffOptions.None; this._bIgnoreDtd = (options & XmlDiffOptions.IgnoreDtd) > XmlDiffOptions.None; if (this._bIgnoreNamespaces) { this._bIgnorePrefixes = true; } foreach (var childNode in diffgramDoc.DocumentElement.ChildNodes) { var xmlElement = childNode as XmlElement; if (xmlElement is XmlElement && xmlElement.LocalName == "descriptor") { var opid = int.Parse(xmlElement.GetAttribute("opid")); OperationDescriptor.Type type; switch (xmlElement.GetAttribute("type")) { case "move": type = OperationDescriptor.Type.Move; break; case "prefix change": type = OperationDescriptor.Type.PrefixChange; break; case "namespace change": type = OperationDescriptor.Type.NamespaceChange; break; default: throw new Exception("Invalid descriptor type."); } var operationDescriptor = new OperationDescriptor(opid, type); this._descriptors[opid] = operationDescriptor; } } }
private void Patch(ref XmlNode sourceNode, XmlDocument diffDoc) { var documentElement = diffDoc.DocumentElement; if (documentElement.LocalName != "xmldiff" || documentElement.NamespaceURI != "http://schemas.microsoft.com/xmltools/2002/xmldiff") { XmlPatchError.Error("Invalid XDL diffgram. Expecting xd:xmldiff as a root element with namespace URI 'http://schemas.microsoft.com/xmltools/2002/xmldiff'."); } XmlNamedNodeMap attributes = documentElement.Attributes; var namedItem1 = (XmlAttribute)attributes.GetNamedItem("srcDocHash"); if (namedItem1 == null) { XmlPatchError.Error("Invalid XDL diffgram. Missing srcDocHash attribute on the xd:xmldiff element."); } ulong hashValue = 0; try { hashValue = ulong.Parse(namedItem1.Value); } catch { XmlPatchError.Error("Invalid XDL diffgram. The srcDocHash attribute has an invalid value."); } var namedItem2 = (XmlAttribute)attributes.GetNamedItem("options"); if (namedItem2 == null) { XmlPatchError.Error("Invalid XDL diffgram. Missing options attribute on the xd:xmldiff element."); } var options = XmlDiffOptions.None; try { options = XmlDiff.ParseOptions(namedItem2.Value); } catch { XmlPatchError.Error("Invalid XDL diffgram. The options attribute has an invalid value."); } this._ignoreChildOrder = (options & XmlDiffOptions.IgnoreChildOrder) != XmlDiffOptions.None; if (!XmlDiff.VerifySource(sourceNode, hashValue, options)) { XmlPatchError.Error("The XDL diffgram is not applicable to this XML document; the srcDocHash value does not match."); } if (sourceNode.NodeType == XmlNodeType.Document) { var patch = this.CreatePatch(sourceNode, documentElement); var xmlDocument = (XmlDocument)sourceNode; var element = xmlDocument.CreateElement("tempRoot"); XmlNode nextSibling; for (var xmlNode = xmlDocument.FirstChild; xmlNode != null; xmlNode = nextSibling) { nextSibling = xmlNode.NextSibling; if (xmlNode.NodeType != XmlNodeType.XmlDeclaration && xmlNode.NodeType != XmlNodeType.DocumentType) { xmlDocument.RemoveChild(xmlNode); element.AppendChild(xmlNode); } } xmlDocument.AppendChild(element); XmlNode currentPosition = null; patch.Apply(element, ref currentPosition); if (sourceNode.NodeType != XmlNodeType.Document) { return; } xmlDocument.RemoveChild(element); XmlNode firstChild; while ((firstChild = element.FirstChild) != null) { element.RemoveChild(firstChild); xmlDocument.AppendChild(firstChild); } } else if (sourceNode.NodeType == XmlNodeType.DocumentFragment) { var patch = this.CreatePatch(sourceNode, documentElement); XmlNode currentPosition = null; patch.Apply(sourceNode, ref currentPosition); } else { var documentFragment = sourceNode.OwnerDocument.CreateDocumentFragment(); var parentNode = sourceNode.ParentNode; var previousSibling = sourceNode.PreviousSibling; parentNode?.RemoveChild(sourceNode); if (sourceNode.NodeType != XmlNodeType.XmlDeclaration) { documentFragment.AppendChild(sourceNode); } else { documentFragment.InnerXml = sourceNode.OuterXml; } var patch = this.CreatePatch(documentFragment, documentElement); XmlNode currentPosition = null; patch.Apply(documentFragment, ref currentPosition); var childNodes = documentFragment.ChildNodes; if (childNodes.Count != 1) { XmlPatchError.Error("Internal Error. {0} nodes left after patch, expecting 1.", childNodes.Count.ToString()); } sourceNode = childNodes.Item(0); documentFragment.RemoveAll(); parentNode?.InsertAfter(sourceNode, previousSibling); } }
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); } } }