private NodePosition CompareElements(XmlDiffElement elem1, XmlDiffElement elem2) { Debug.Assert(elem1 != null); Debug.Assert(elem2 != null); int nCompare = 0; if ((nCompare = CompareText(elem2.LocalName, elem1.LocalName)) == 0) { if (IgnoreNS || (nCompare = CompareText(elem2.NamespaceURI, elem1.NamespaceURI)) == 0) { if (IgnorePrefix || (nCompare = CompareText(elem2.Prefix, elem1.Prefix)) == 0) { if ((nCompare = CompareText(elem2.Value, elem1.Value)) == 0) { if ((nCompare = CompareAttributes(elem2, elem1)) == 0) { return(NodePosition.After); } } } } } if (nCompare > 0) { //elem2 > elem1 return(NodePosition.After); } else { //elem2 < elem1 return(NodePosition.Before); } }
private void SortChildren(XmlDiffElement elem) { if (elem.FirstChild != null) { XmlDiffNode _first = elem.FirstChild; XmlDiffNode _current = elem.FirstChild; XmlDiffNode _last = elem.LastChild; elem._firstChild = null; elem._lastChild = null; //set flag to ignore child order bool temp = IgnoreChildOrder; IgnoreChildOrder = true; XmlDiffNode _next = null; do { if (_current is XmlDiffElement) { _next = _current._next; } _current._next = null; InsertChild(elem, _current); if (_current == _last) { break; } _current = _next; }while (true); //restore flag for ignoring child order IgnoreChildOrder = temp; } }
private void LoadElement(XmlDiffNode parent, XmlReader reader, PositionInfo pInfo) { XmlDiffElement elem = null; bool bEmptyElement = reader.IsEmptyElement; if (bEmptyElement) { elem = new XmlDiffEmptyElement(reader.LocalName, reader.Prefix, reader.NamespaceURI); } else { elem = new XmlDiffElement(reader.LocalName, reader.Prefix, reader.NamespaceURI); } elem.LineNumber = pInfo.LineNumber; elem.LinePosition = pInfo.LinePosition; ReadAttributes(elem, reader, pInfo); if (!bEmptyElement) { // bool rtn = reader.Read(); // rtn = reader.Read(); reader.Read(); //move to child ReadChildNodes(elem, reader, pInfo); } InsertChild(parent, elem); }
private void ReadAttributes(XmlDiffElement parent, XmlReader reader, PositionInfo pInfo) { if (reader.MoveToFirstAttribute()) { do { XmlDiffAttribute attr = new XmlDiffAttribute(reader.LocalName, reader.Prefix, reader.NamespaceURI, reader.Value); attr.SetValueAsQName(reader, reader.Value); attr.LineNumber = pInfo.LineNumber; attr.LinePosition = pInfo.LinePosition; InsertAttribute(parent, attr); }while (reader.MoveToNextAttribute()); } }
private int CompareAttributes(XmlDiffElement elem1, XmlDiffElement elem2) { int count1 = elem1.AttributeCount; int count2 = elem2.AttributeCount; if (count1 > count2) { return(1); } else if (count1 < count2) { return(-1); } else { XmlDiffAttribute current1 = elem1.FirstAttribute; XmlDiffAttribute current2 = elem2.FirstAttribute; // NodePosition result = 0; int nCompare = 0; while (current1 != null && current2 != null && nCompare == 0) { if ((nCompare = CompareText(current2.LocalName, current1.LocalName)) == 0) { if (IgnoreNS || (nCompare = CompareText(current2.NamespaceURI, current1.NamespaceURI)) == 0) { if (IgnorePrefix || (nCompare = CompareText(current2.Prefix, current1.Prefix)) == 0) { if ((nCompare = CompareText(current2.Value, current1.Value)) == 0) { //do nothing! } } } } current1 = (XmlDiffAttribute)current1._next; current2 = (XmlDiffAttribute)current2._next; } if (nCompare > 0) { //elem1 > attr2 return(1); } else { //elem1 < elem2 return(-1); } } }
// This is a helper function for WriteResult. It gets the Xml representation of the different node we wants // to write out and all it's children. private String GetNodeText(XmlDiffNode diffNode, DiffType result) { string text = string.Empty; switch (diffNode.NodeType) { case XmlDiffNodeType.Element: if (result == DiffType.SourceExtra || result == DiffType.TargetExtra) { return(diffNode.OuterXml); } StringWriter str = new StringWriter(); XmlWriter writer = XmlWriter.Create(str); XmlDiffElement diffElem = diffNode as XmlDiffElement; Debug.Assert(diffNode != null); writer.WriteStartElement(diffElem.Prefix, diffElem.LocalName, diffElem.NamespaceURI); XmlDiffAttribute diffAttr = diffElem.FirstAttribute; while (diffAttr != null) { writer.WriteAttributeString(diffAttr.Prefix, diffAttr.LocalName, diffAttr.NamespaceURI, diffAttr.Value); diffAttr = (XmlDiffAttribute)diffAttr.NextSibling; } if (diffElem is XmlDiffEmptyElement) { writer.WriteEndElement(); text = str.ToString(); } else { text = str.ToString(); text += ">"; } writer.Dispose(); break; case XmlDiffNodeType.CData: text = ((XmlDiffCharacterData)diffNode).Value; break; default: text = diffNode.OuterXml; break; } return(text); }
private void InsertAttribute(XmlDiffElement parent, XmlDiffAttribute newAttr) { Debug.Assert(parent != null); Debug.Assert(newAttr != null); newAttr._parent = parent; if (IgnoreAttributeOrder) { XmlDiffAttribute attr = parent.FirstAttribute; XmlDiffAttribute prevAttr = null; while (attr != null && (CompareAttributes(attr, newAttr) == NodePosition.After)) { prevAttr = attr; attr = (XmlDiffAttribute)(attr.NextSibling); } parent.InsertAttributeAfter(prevAttr, newAttr); } else { parent.InsertAttributeAfter(parent.LastAttribute, newAttr); } }
private void SetElementEndPosition(XmlDiffElement elem, PositionInfo pInfo) { Debug.Assert(elem != null); elem.EndLineNumber = pInfo.LineNumber; elem.EndLinePosition = pInfo.LinePosition; }
// This function is used to compare the attributes of an element node according to the options set by the user. private bool CompareAttributes(XmlDiffElement sourceElem, XmlDiffElement targetElem) { Debug.Assert(sourceElem != null); Debug.Assert(targetElem != null); if (sourceElem.AttributeCount != targetElem.AttributeCount && !IgnoreNS) { return(false); } if (sourceElem.AttributeCount == 0) { return(true); } XmlDiffAttribute sourceAttr = sourceElem.FirstAttribute; XmlDiffAttribute targetAttr = targetElem.FirstAttribute; const string xmlnsNamespace = "http://www.w3.org/2000/xmlns/"; if (!IgnoreAttributeOrder) { while (sourceAttr != null && targetAttr != null) { if (!IgnoreNS) { if (sourceAttr.NamespaceURI != targetAttr.NamespaceURI) { return(false); } } if (!IgnorePrefix) { if (sourceAttr.Prefix != targetAttr.Prefix) { return(false); } } if (sourceAttr.NamespaceURI == xmlnsNamespace && targetAttr.NamespaceURI == xmlnsNamespace) { if (!IgnorePrefix && (sourceAttr.LocalName != targetAttr.LocalName)) { return(false); } if (!IgnoreNS && (sourceAttr.Value != targetAttr.Value)) { return(false); } } else { if (sourceAttr.LocalName != targetAttr.LocalName) { return(false); } if (sourceAttr.Value != targetAttr.Value) { if (ParseAttributeValuesAsQName) { if (sourceAttr.ValueAsQName != null) { if (!sourceAttr.ValueAsQName.Equals(targetAttr.ValueAsQName)) { return(false); } } else { if (targetAttr.ValueAsQName != null) { return(false); } } } else { return(false); } } } sourceAttr = (XmlDiffAttribute)(sourceAttr.NextSibling); targetAttr = (XmlDiffAttribute)(targetAttr.NextSibling); } } else { Hashtable sourceAttributeMap = new Hashtable(); Hashtable targetAttributeMap = new Hashtable(); while (sourceAttr != null && targetAttr != null) { if (IgnorePrefix && sourceAttr.NamespaceURI == xmlnsNamespace) { // do nothing } else { string localNameAndNamespace = sourceAttr.LocalName + "<&&>" + sourceAttr.NamespaceURI; sourceAttributeMap.Add(localNameAndNamespace, sourceAttr); } if (IgnorePrefix && targetAttr.NamespaceURI == xmlnsNamespace) { // do nothing } else { string localNameAndNamespace = targetAttr.LocalName + "<&&>" + targetAttr.NamespaceURI; targetAttributeMap.Add(localNameAndNamespace, targetAttr); } sourceAttr = (XmlDiffAttribute)(sourceAttr.NextSibling); targetAttr = (XmlDiffAttribute)(targetAttr.NextSibling); } if (sourceAttributeMap.Count != targetAttributeMap.Count) { return(false); } foreach (string sourceKey in sourceAttributeMap.Keys) { if (!targetAttributeMap.ContainsKey(sourceKey)) { return(false); } sourceAttr = (XmlDiffAttribute)sourceAttributeMap[sourceKey]; targetAttr = (XmlDiffAttribute)targetAttributeMap[sourceKey]; if (!IgnorePrefix) { if (sourceAttr.Prefix != targetAttr.Prefix) { return(false); } } if (sourceAttr.Value != targetAttr.Value) { if (ParseAttributeValuesAsQName) { if (sourceAttr.ValueAsQName != null) { if (!sourceAttr.ValueAsQName.Equals(targetAttr.ValueAsQName)) { return(false); } } else { if (targetAttr.ValueAsQName != null) { return(false); } } } else { return(false); } } } } return(true); }
// This function compares the two nodes passed to it, depending upon the options set by the user. private DiffType CompareNodes(XmlDiffNode sourceNode, XmlDiffNode targetNode) { if (sourceNode.NodeType != targetNode.NodeType) { return(DiffType.NodeType); } switch (sourceNode.NodeType) { case XmlDiffNodeType.Element: XmlDiffElement sourceElem = sourceNode as XmlDiffElement; XmlDiffElement targetElem = targetNode as XmlDiffElement; Debug.Assert(sourceElem != null); Debug.Assert(targetElem != null); if (!IgnoreNS) { if (sourceElem.NamespaceURI != targetElem.NamespaceURI) { return(DiffType.NS); } } if (!IgnorePrefix) { if (sourceElem.Prefix != targetElem.Prefix) { return(DiffType.Prefix); } } if (sourceElem.LocalName != targetElem.LocalName) { return(DiffType.Element); } if (!IgnoreEmptyElement) { if ((sourceElem is XmlDiffEmptyElement) != (targetElem is XmlDiffEmptyElement)) { return(DiffType.Element); } } if (!CompareAttributes(sourceElem, targetElem)) { return(DiffType.Attribute); } break; case XmlDiffNodeType.Text: case XmlDiffNodeType.Comment: case XmlDiffNodeType.WS: XmlDiffCharacterData sourceText = sourceNode as XmlDiffCharacterData; XmlDiffCharacterData targetText = targetNode as XmlDiffCharacterData; Debug.Assert(sourceText != null); Debug.Assert(targetText != null); if (ConcatenateAdjacentTextNodes) { DoConcatenateAdjacentTextNodes(sourceText); DoConcatenateAdjacentTextNodes(targetText); } if (IgnoreWhitespace) { if (sourceText.Value.Trim() == targetText.Value.Trim()) { return(DiffType.Success); } } else { if (sourceText.Value == targetText.Value) { return(DiffType.Success); } } if (sourceText.NodeType == XmlDiffNodeType.Text || sourceText.NodeType == XmlDiffNodeType.WS) //should ws nodes also as text nodes??? { return(DiffType.Text); } else if (sourceText.NodeType == XmlDiffNodeType.Comment) { return(DiffType.Comment); } else if (sourceText.NodeType == XmlDiffNodeType.CData) { return(DiffType.CData); } else { return(DiffType.None); } case XmlDiffNodeType.PI: XmlDiffProcessingInstruction sourcePI = sourceNode as XmlDiffProcessingInstruction; XmlDiffProcessingInstruction targetPI = targetNode as XmlDiffProcessingInstruction; Debug.Assert(sourcePI != null); Debug.Assert(targetPI != null); if (sourcePI.Name != targetPI.Name || sourcePI.Value != targetPI.Value) { return(DiffType.PI); } break; default: break; } return(DiffType.Success); }
// This function is being called recursively to compare the children of a certain node. // When calling this function the navigator should be pointing at the parent node whose children // we wants to compare and return the navigator back to the same node before exiting from it. private bool CompareChildren(XmlDiffNode sourceNode, XmlDiffNode targetNode) { XmlDiffNode sourceChild = sourceNode.FirstChild; XmlDiffNode targetChild = targetNode.FirstChild; bool flag = true; bool tempFlag = true; DiffType result; // Loop to compare all the child elements of the parent node while (sourceChild != null || targetChild != null) { if (sourceChild != null) { if (targetChild != null) { // Both Source and Target Read successful if ((result = CompareNodes(sourceChild, targetChild)) == DiffType.Success) { // Child nodes compared successfully, write out the result WriteResult(sourceChild, targetChild, DiffType.Success); // Check whether this Node has Children, if it does call CompareChildren recursively if (sourceChild.FirstChild != null) { tempFlag = CompareChildren(sourceChild, targetChild); } else if (targetChild.FirstChild != null) { WriteResult(null, targetChild, DiffType.TargetExtra); tempFlag = false; } // set the compare flag flag = (flag && tempFlag); // Writing out End Element to the result if (sourceChild.NodeType == XmlDiffNodeType.Element && !(sourceChild is XmlDiffEmptyElement)) { XmlDiffElement sourceElem = sourceChild as XmlDiffElement; XmlDiffElement targetElem = targetChild as XmlDiffElement; Debug.Assert(sourceElem != null); Debug.Assert(targetElem != null); if (!DontWriteMatchingNodesToOutput && !DontWriteAnythingToOutput) { _Writer.WriteStartElement(String.Empty, "Node", String.Empty); _Writer.WriteAttributeString(String.Empty, "SourceLineNum", String.Empty, sourceElem.EndLineNumber.ToString()); _Writer.WriteAttributeString(String.Empty, "SourceLinePos", String.Empty, sourceElem.EndLinePosition.ToString()); _Writer.WriteAttributeString(String.Empty, "TargetLineNum", String.Empty, targetElem.EndLineNumber.ToString()); _Writer.WriteAttributeString(String.Empty, "TargetLinePos", String.Empty, targetElem.EndLinePosition.ToString()); _Writer.WriteStartElement(String.Empty, "Diff", String.Empty); _Writer.WriteEndElement(); _Writer.WriteStartElement(String.Empty, "Lexical-equal", String.Empty); _Writer.WriteCData("</" + sourceElem.Name + ">"); _Writer.WriteEndElement(); _Writer.WriteEndElement(); } } // Move to Next child sourceChild = sourceChild.NextSibling; targetChild = targetChild.NextSibling; } else { // Child nodes not matched, start the recovery process bool recoveryFlag = false; // Try to match the source node with the target nodes at the same level XmlDiffNode backupTargetChild = targetChild.NextSibling; while (!recoveryFlag && backupTargetChild != null) { if (CompareNodes(sourceChild, backupTargetChild) == DiffType.Success) { recoveryFlag = true; do { WriteResult(null, targetChild, DiffType.TargetExtra); targetChild = targetChild.NextSibling; }while (targetChild != backupTargetChild); break; } backupTargetChild = backupTargetChild.NextSibling; } // If not recovered, try to match the target node with the source nodes at the same level if (!recoveryFlag) { XmlDiffNode backupSourceChild = sourceChild.NextSibling; while (!recoveryFlag && backupSourceChild != null) { if (CompareNodes(backupSourceChild, targetChild) == DiffType.Success) { recoveryFlag = true; do { WriteResult(sourceChild, null, DiffType.SourceExtra); sourceChild = sourceChild.NextSibling; }while (sourceChild != backupSourceChild); break; } backupSourceChild = backupSourceChild.NextSibling; } } // If still not recovered, write both of them as different nodes and move on if (!recoveryFlag) { WriteResult(sourceChild, targetChild, result); // Check whether this Node has Children, if it does call CompareChildren recursively if (sourceChild.FirstChild != null) { tempFlag = CompareChildren(sourceChild, targetChild); } else if (targetChild.FirstChild != null) { WriteResult(null, targetChild, DiffType.TargetExtra); tempFlag = false; } // Writing out End Element to the result bool bSourceNonEmpElemEnd = (sourceChild.NodeType == XmlDiffNodeType.Element && !(sourceChild is XmlDiffEmptyElement)); bool bTargetNonEmpElemEnd = (targetChild.NodeType == XmlDiffNodeType.Element && !(targetChild is XmlDiffEmptyElement)); if (bSourceNonEmpElemEnd || bTargetNonEmpElemEnd) { XmlDiffElement sourceElem = sourceChild as XmlDiffElement; XmlDiffElement targetElem = targetChild as XmlDiffElement; if (!DontWriteAnythingToOutput) { _Writer.WriteStartElement(String.Empty, "Node", String.Empty); _Writer.WriteAttributeString(String.Empty, "SourceLineNum", String.Empty, (sourceElem != null) ? sourceElem.EndLineNumber.ToString() : "-1"); _Writer.WriteAttributeString(String.Empty, "SourceLinePos", String.Empty, (sourceElem != null) ? sourceElem.EndLinePosition.ToString() : "-1"); _Writer.WriteAttributeString(String.Empty, "TargetLineNum", String.Empty, (targetElem != null) ? targetElem.EndLineNumber.ToString() : "-1"); _Writer.WriteAttributeString(String.Empty, "TargetLinePos", String.Empty, (targetElem != null) ? targetElem.EndLineNumber.ToString() : "-1"); _Writer.WriteStartElement(String.Empty, "Diff", String.Empty); _Writer.WriteAttributeString(String.Empty, "DiffType", String.Empty, GetDiffType(result)); if (bSourceNonEmpElemEnd) { _Writer.WriteStartElement(String.Empty, "File1", String.Empty); _Writer.WriteCData("</" + sourceElem.Name + ">"); _Writer.WriteEndElement(); } if (bTargetNonEmpElemEnd) { _Writer.WriteStartElement(String.Empty, "File2", String.Empty); _Writer.WriteCData("</" + targetElem.Name + ">"); _Writer.WriteEndElement(); } _Writer.WriteEndElement(); _Writer.WriteStartElement(String.Empty, "Lexical-equal", String.Empty); _Writer.WriteEndElement(); _Writer.WriteEndElement(); } } sourceChild = sourceChild.NextSibling; targetChild = targetChild.NextSibling; } flag = false; } } else { // SourceRead NOT NULL targetRead is NULL WriteResult(sourceChild, null, DiffType.SourceExtra); flag = false; sourceChild = sourceChild.NextSibling; } } else if (targetChild != null) { // SourceRead is NULL and targetRead is NOT NULL WriteResult(null, targetChild, DiffType.TargetExtra); flag = false; targetChild = targetChild.NextSibling; } else { //Both SourceRead and TargetRead is NULL Debug.Assert(false, "Impossible Situation for comparison"); } } return(flag); }