private void ComputeHashXmlDiffChildren(HashAlgorithm ha, XmlDiffParentNode parent) { var i = 0; if (this._bIgnoreChildOrder) { ulong u = 0; for (var xmlDiffNode = parent.FirstChildNode; xmlDiffNode != null; xmlDiffNode = xmlDiffNode._nextSibling) { u += xmlDiffNode.HashValue; ++i; } ha.AddULong(u); } else { for (var xmlDiffNode = parent.FirstChildNode; xmlDiffNode != null; xmlDiffNode = xmlDiffNode._nextSibling) { ha.AddULong(xmlDiffNode.HashValue); ++i; } } if (i == 0) { return; } ha.AddInt(i); }
// internal bool _nodeOrDescendantMatches = false; // Constructors internal XmlDiffNode( int position ) { _parent = null; _nextSibling = null; _position = position; _bExpanded = false; }
// internal bool _nodeOrDescendantMatches = false; // Constructors internal XmlDiffNode(int position) { _parent = null; _nextSibling = null; _position = position; _bExpanded = false; }
internal XmlDiffNode(int position) { this._parent = (XmlDiffParentNode)null; this._nextSibling = (XmlDiffNode)null; this._position = position; this._bExpanded = false; }
// Methods internal override void WriteTo(XmlWriter xmlWriter, XmlDiff xmlDiff) { if (!_bSorted) { Sort(); } xmlWriter.WriteStartElement(XmlDiff.Prefix, "add", XmlDiff.NamespaceUri); if (_operationID != 0) { xmlWriter.WriteAttributeString("opid", _operationID.ToString()); } // namespaces if (_bNeedNamespaces) { Hashtable definedPrefixes = new Hashtable(); XmlDiffParentNode parent = _firstTargetNode._parent; while (parent != null) { if (parent._bDefinesNamespaces) { XmlDiffElement el = (XmlDiffElement)parent; XmlDiffAttributeOrNamespace curNs = el._attributes; while (curNs != null && curNs.NodeType == XmlDiffNodeType.Namespace) { if (definedPrefixes[curNs.Prefix] == null) { if (curNs.Prefix == string.Empty) { xmlWriter.WriteAttributeString("xmlns", XmlDiff.XmlnsNamespaceUri, curNs.NamespaceURI); } else { xmlWriter.WriteAttributeString("xmlns", curNs.Prefix, XmlDiff.XmlnsNamespaceUri, curNs.NamespaceURI); } definedPrefixes[curNs.Prefix] = curNs.Prefix; } curNs = (XmlDiffAttributeOrNamespace)curNs._nextSibling; } } parent = parent._parent; } } // output nodes XmlDiffNode node = _firstTargetNode; for (;;) { node.WriteTo(xmlWriter); if (node == _lastTargetNode) { break; } node = node._nextSibling; } xmlWriter.WriteEndElement(); }
internal void LoadChildNodes(XmlDiffParentNode parent, XmlNode parentDomNode) { var curLastChild = this._curLastChild; this._curLastChild = (XmlDiffNode) null; var attributes = (XmlNamedNodeMap) parentDomNode.Attributes; if (attributes != null && attributes.Count > 0) { foreach (XmlAttribute xmlAttribute in attributes) { if (xmlAttribute.Prefix == "xmlns") { if (!this._XmlDiff.IgnoreNamespaces) { var xmlDiffNamespace = new XmlDiffNamespace(xmlAttribute.LocalName, xmlAttribute.Value); xmlDiffNamespace.ComputeHashValue(this._xmlHash); this.InsertAttributeOrNamespace((XmlDiffElement) parent, (XmlDiffAttributeOrNamespace) xmlDiffNamespace); } } else if (xmlAttribute.Prefix == string.Empty && xmlAttribute.LocalName == "xmlns") { if (!this._XmlDiff.IgnoreNamespaces) { var xmlDiffNamespace = new XmlDiffNamespace(string.Empty, xmlAttribute.Value); xmlDiffNamespace.ComputeHashValue(this._xmlHash); this.InsertAttributeOrNamespace((XmlDiffElement) parent, (XmlDiffAttributeOrNamespace) xmlDiffNamespace); } } else { var str = this._XmlDiff.IgnoreWhitespace ? XmlDiff.NormalizeText(xmlAttribute.Value) : xmlAttribute.Value; var xmlDiffAttribute = new XmlDiffAttribute(xmlAttribute.LocalName, xmlAttribute.Prefix, xmlAttribute.NamespaceURI, str); xmlDiffAttribute.ComputeHashValue(this._xmlHash); this.InsertAttributeOrNamespace((XmlDiffElement) parent, (XmlDiffAttributeOrNamespace) xmlDiffAttribute); } } } var childNodes = parentDomNode.ChildNodes; if (childNodes.Count != 0) { var childPosition = 0; var enumerator = childNodes.GetEnumerator(); while (enumerator.MoveNext()) { if (((XmlNode) enumerator.Current).NodeType != XmlNodeType.Whitespace) { var newChild = this.LoadNode((XmlNode) enumerator.Current, ref childPosition); if (newChild != null) this.InsertChild(parent, newChild); } } } this._curLastChild = curLastChild; }
private void InsertChild(XmlDiffParentNode parent, XmlDiffNode newChild) { if (this._XmlDiff.IgnoreChildOrder) { var node1 = parent.FirstChildNode; var childNode = (XmlDiffNode) null; for (; node1 != null && XmlDiffDocument.OrderChildren(node1, newChild) <= 0; node1 = node1._nextSibling) childNode = node1; parent.InsertChildNodeAfter(childNode, newChild); } else { parent.InsertChildNodeAfter(this._curLastChild, newChild); this._curLastChild = newChild; } }
// Inserts the 'newChild' node. If child order is significant, the new child is // inserted at the end of all child nodes. If the child order is not signoficant, // the new node is sorted into the other child nodes. private void InsertChild(XmlDiffParentNode parent, XmlDiffNode newChild) { if (_XmlDiff.IgnoreChildOrder) { XmlDiffNode curChild = parent.FirstChildNode; XmlDiffNode prevChild = null; while (curChild != null && (OrderChildren(curChild, newChild) <= 0)) { prevChild = curChild; curChild = curChild._nextSibling; } parent.InsertChildNodeAfter(prevChild, newChild); } else { parent.InsertChildNodeAfter(_curLastChild, newChild); _curLastChild = newChild; } }
private void ComputeHashXmlDiffChildren(HashAlgorithm ha, XmlDiffParentNode parent) { int childrenCount = 0; if (_bIgnoreChildOrder) { ulong totalHash = 0; XmlDiffNode curChild = parent.FirstChildNode; while (curChild != null) { Debug.Assert(!(curChild is XmlDiffAttributeOrNamespace)); Debug.Assert(curChild.HashValue != 0); totalHash += curChild.HashValue; childrenCount++; curChild = curChild._nextSibling; } ha.AddULong(totalHash); } else { XmlDiffNode curChild = parent.FirstChildNode; while (curChild != null) { Debug.Assert(!(curChild is XmlDiffAttributeOrNamespace)); Debug.Assert(curChild.HashValue != 0); ha.AddULong(curChild.HashValue); childrenCount++; curChild = curChild._nextSibling; } } if (childrenCount != 0) { ha.AddInt(childrenCount); } }
internal void LoadChildNodes(XmlDiffParentNode parent, XmlReader reader, bool bEmptyElement) { var curLastChild = this._curLastChild; this._curLastChild = (XmlDiffNode) null; while (reader.MoveToNextAttribute()) { if (reader.Prefix == "xmlns") { if (!this._XmlDiff.IgnoreNamespaces) { var xmlDiffNamespace = new XmlDiffNamespace(reader.LocalName, reader.Value); xmlDiffNamespace.ComputeHashValue(this._xmlHash); this.InsertAttributeOrNamespace((XmlDiffElement) parent, (XmlDiffAttributeOrNamespace) xmlDiffNamespace); } } else if (reader.Prefix == string.Empty && reader.LocalName == "xmlns") { if (!this._XmlDiff.IgnoreNamespaces) { var xmlDiffNamespace = new XmlDiffNamespace(string.Empty, reader.Value); xmlDiffNamespace.ComputeHashValue(this._xmlHash); this.InsertAttributeOrNamespace((XmlDiffElement) parent, (XmlDiffAttributeOrNamespace) xmlDiffNamespace); } } else { var str = this._XmlDiff.IgnoreWhitespace ? XmlDiff.NormalizeText(reader.Value) : reader.Value; var xmlDiffAttribute = new XmlDiffAttribute(reader.LocalName, reader.Prefix, reader.NamespaceURI, str); xmlDiffAttribute.ComputeHashValue(this._xmlHash); this.InsertAttributeOrNamespace((XmlDiffElement) parent, (XmlDiffAttributeOrNamespace) xmlDiffAttribute); } } if (!bEmptyElement) { var position = 0; if (reader.Read()) { do { if (reader.NodeType != XmlNodeType.Whitespace) { switch (reader.NodeType) { case XmlNodeType.Element: var isEmptyElement = reader.IsEmptyElement; var xmlDiffElement = new XmlDiffElement(++position, reader.LocalName, reader.Prefix, reader.NamespaceURI); this.LoadChildNodes((XmlDiffParentNode) xmlDiffElement, reader, isEmptyElement); xmlDiffElement.ComputeHashValue(this._xmlHash); this.InsertChild(parent, (XmlDiffNode) xmlDiffElement); break; case XmlNodeType.Text: var str = this._XmlDiff.IgnoreWhitespace ? XmlDiff.NormalizeText(reader.Value) : reader.Value; var xmlDiffCharData1 = new XmlDiffCharData(++position, str, XmlDiffNodeType.Text); xmlDiffCharData1.ComputeHashValue(this._xmlHash); this.InsertChild(parent, (XmlDiffNode) xmlDiffCharData1); break; case XmlNodeType.CDATA: var xmlDiffCharData2 = new XmlDiffCharData(++position, reader.Value, XmlDiffNodeType.CDATA); xmlDiffCharData2.ComputeHashValue(this._xmlHash); this.InsertChild(parent, (XmlDiffNode) xmlDiffCharData2); break; case XmlNodeType.EntityReference: var xmlDiffEr = new XmlDiffER(++position, reader.Name); xmlDiffEr.ComputeHashValue(this._xmlHash); this.InsertChild(parent, (XmlDiffNode) xmlDiffEr); break; case XmlNodeType.ProcessingInstruction: ++position; if (!this._XmlDiff.IgnorePI) { var xmlDiffPi = new XmlDiffPI(position, reader.Name, reader.Value); xmlDiffPi.ComputeHashValue(this._xmlHash); this.InsertChild(parent, (XmlDiffNode) xmlDiffPi); break; } break; case XmlNodeType.Comment: ++position; if (!this._XmlDiff.IgnoreComments) { var xmlDiffCharData3 = new XmlDiffCharData(position, reader.Value, XmlDiffNodeType.Comment); xmlDiffCharData3.ComputeHashValue(this._xmlHash); this.InsertChild(parent, (XmlDiffNode) xmlDiffCharData3); break; } break; case XmlNodeType.DocumentType: ++position; if (!this._XmlDiff.IgnoreDtd) { var diffDocumentType = new XmlDiffDocumentType(position, reader.Name, reader.GetAttribute("PUBLIC"), reader.GetAttribute("SYSTEM"), reader.Value); diffDocumentType.ComputeHashValue(this._xmlHash); this.InsertChild(parent, (XmlDiffNode) diffDocumentType); break; } break; case XmlNodeType.SignificantWhitespace: if (reader.XmlSpace == XmlSpace.Preserve) { ++position; if (!this._XmlDiff.IgnoreWhitespace) { var xmlDiffCharData3 = new XmlDiffCharData(position, reader.Value, XmlDiffNodeType.SignificantWhitespace); xmlDiffCharData3.ComputeHashValue(this._xmlHash); this.InsertChild(parent, (XmlDiffNode) xmlDiffCharData3); break; } break; } break; case XmlNodeType.EndElement: goto label_29; case XmlNodeType.XmlDeclaration: ++position; if (!this._XmlDiff.IgnoreXmlDecl) { var diffXmlDeclaration = new XmlDiffXmlDeclaration(position, XmlDiff.NormalizeXmlDeclaration(reader.Value)); diffXmlDeclaration.ComputeHashValue(this._xmlHash); this.InsertChild(parent, (XmlDiffNode) diffXmlDeclaration); break; } break; } } } while (reader.Read()); } } label_29: this._curLastChild = curLastChild; }
// Loads child nodes of the 'parent' node internal void LoadChildNodes( XmlDiffParentNode parent, XmlNode parentDomNode ) { XmlDiffNode savedLastChild = _curLastChild; _curLastChild = null; // load attributes & namespace nodes XmlNamedNodeMap attribs = parentDomNode.Attributes; if ( attribs != null && attribs.Count > 0 ) { IEnumerator attrEnum = attribs.GetEnumerator(); while ( attrEnum.MoveNext() ) { XmlAttribute attr = (XmlAttribute)attrEnum.Current; if ( attr.Prefix == "xmlns" ) { if ( !_XmlDiff.IgnoreNamespaces ) { XmlDiffNamespace nsNode = new XmlDiffNamespace( attr.LocalName, attr.Value ); nsNode.ComputeHashValue( _xmlHash ); InsertAttributeOrNamespace( (XmlDiffElement)parent, nsNode ); } } else if ( attr.Prefix == string.Empty && attr.LocalName == "xmlns" ) { if ( !_XmlDiff.IgnoreNamespaces ) { XmlDiffNamespace nsNode = new XmlDiffNamespace( string.Empty, attr.Value ); nsNode.ComputeHashValue( _xmlHash ); InsertAttributeOrNamespace( (XmlDiffElement)parent, nsNode ); } } else { string attrValue = _XmlDiff.IgnoreWhitespace ? XmlDiff.NormalizeText( attr.Value ) : attr.Value; XmlDiffAttribute newAttr = new XmlDiffAttribute( attr.LocalName, attr.Prefix, attr.NamespaceURI, attrValue ); newAttr.ComputeHashValue( _xmlHash ); InsertAttributeOrNamespace( (XmlDiffElement)parent, newAttr ); } } } // load children XmlNodeList children = parentDomNode.ChildNodes; if ( children.Count == 0 ) goto End; int childPosition = 0; IEnumerator childEnum = children.GetEnumerator(); while ( childEnum.MoveNext() ) { XmlNode node = (XmlNode)childEnum.Current; // ignore whitespaces between nodes if ( node.NodeType == XmlNodeType.Whitespace ) continue; XmlDiffNode newDiffNode = LoadNode( (XmlNode)childEnum.Current, ref childPosition ); if ( newDiffNode != null ) InsertChild( parent, newDiffNode ); } End: _curLastChild = savedLastChild; }
// Loads child nodes of the 'parent' node internal void LoadChildNodes(XmlDiffParentNode parent, XmlNode parentDomNode) { XmlDiffNode savedLastChild = _curLastChild; _curLastChild = null; // load attributes & namespace nodes XmlNamedNodeMap attribs = parentDomNode.Attributes; if (attribs != null && attribs.Count > 0) { IEnumerator attrEnum = attribs.GetEnumerator(); while (attrEnum.MoveNext()) { XmlAttribute attr = (XmlAttribute)attrEnum.Current; if (attr.Prefix == "xmlns") { if (!_XmlDiff.IgnoreNamespaces) { XmlDiffNamespace nsNode = new XmlDiffNamespace(attr.LocalName, attr.Value); nsNode.ComputeHashValue(_xmlHash); InsertAttributeOrNamespace((XmlDiffElement)parent, nsNode); } } else if (attr.Prefix == string.Empty && attr.LocalName == "xmlns") { if (!_XmlDiff.IgnoreNamespaces) { XmlDiffNamespace nsNode = new XmlDiffNamespace(string.Empty, attr.Value); nsNode.ComputeHashValue(_xmlHash); InsertAttributeOrNamespace((XmlDiffElement)parent, nsNode); } } else { string attrValue = _XmlDiff.IgnoreWhitespace ? XmlDiff.NormalizeText(attr.Value) : attr.Value; XmlDiffAttribute newAttr = new XmlDiffAttribute(attr.LocalName, attr.Prefix, attr.NamespaceURI, attrValue); newAttr.ComputeHashValue(_xmlHash); InsertAttributeOrNamespace((XmlDiffElement)parent, newAttr); } } } // load children XmlNodeList children = parentDomNode.ChildNodes; if (children.Count == 0) { goto End; } int childPosition = 0; IEnumerator childEnum = children.GetEnumerator(); while (childEnum.MoveNext()) { XmlNode node = (XmlNode)childEnum.Current; // ignore whitespaces between nodes if (node.NodeType == XmlNodeType.Whitespace) { continue; } XmlDiffNode newDiffNode = LoadNode((XmlNode)childEnum.Current, ref childPosition); if (newDiffNode != null) { InsertChild(parent, newDiffNode); } } End: _curLastChild = savedLastChild; }
// Loads child nodes of the 'parent' node internal void LoadChildNodes(XmlDiffParentNode parent, XmlReader reader, bool bEmptyElement) { XmlDiffNode savedLastChild = _curLastChild; _curLastChild = null; // load attributes & namespace nodes while (reader.MoveToNextAttribute()) { if (reader.Prefix == "xmlns") { if (!_XmlDiff.IgnoreNamespaces) { XmlDiffNamespace nsNode = new XmlDiffNamespace(reader.LocalName, reader.Value); nsNode.ComputeHashValue(_xmlHash); InsertAttributeOrNamespace((XmlDiffElement)parent, nsNode); } } else if (reader.Prefix == string.Empty && reader.LocalName == "xmlns") { if (!_XmlDiff.IgnoreNamespaces) { XmlDiffNamespace nsNode = new XmlDiffNamespace(string.Empty, reader.Value); nsNode.ComputeHashValue(_xmlHash); InsertAttributeOrNamespace((XmlDiffElement)parent, nsNode); } } else { string attrValue = _XmlDiff.IgnoreWhitespace ? XmlDiff.NormalizeText(reader.Value) : reader.Value; XmlDiffAttribute attr = new XmlDiffAttribute(reader.LocalName, reader.Prefix, reader.NamespaceURI, attrValue); attr.ComputeHashValue(_xmlHash); InsertAttributeOrNamespace((XmlDiffElement)parent, attr); } } // empty element -> return, do not load chilren if (bEmptyElement) { goto End; } int childPosition = 0; // load children if (!reader.Read()) { goto End; } do { // ignore whitespaces between nodes if (reader.NodeType == XmlNodeType.Whitespace) { continue; } switch (reader.NodeType) { case XmlNodeType.Element: { bool bEmptyEl = reader.IsEmptyElement; XmlDiffElement elem = new XmlDiffElement(++childPosition, reader.LocalName, reader.Prefix, reader.NamespaceURI); LoadChildNodes(elem, reader, bEmptyEl); elem.ComputeHashValue(_xmlHash); InsertChild(parent, elem); break; } case XmlNodeType.Attribute: { Debug.Assert(false, "We should never get to this point, attributes should be read at the beginning of thid method."); break; } case XmlNodeType.Text: { string textValue = (_XmlDiff.IgnoreWhitespace) ? XmlDiff.NormalizeText(reader.Value) : reader.Value; XmlDiffCharData charDataNode = new XmlDiffCharData(++childPosition, textValue, XmlDiffNodeType.Text); charDataNode.ComputeHashValue(_xmlHash); InsertChild(parent, charDataNode); break; } case XmlNodeType.CDATA: { XmlDiffCharData charDataNode = new XmlDiffCharData(++childPosition, reader.Value, XmlDiffNodeType.CDATA); charDataNode.ComputeHashValue(_xmlHash); InsertChild(parent, charDataNode); break; } case XmlNodeType.EntityReference: { XmlDiffER er = new XmlDiffER(++childPosition, reader.Name); er.ComputeHashValue(_xmlHash); InsertChild(parent, er); break; } case XmlNodeType.Comment: { ++childPosition; if (!_XmlDiff.IgnoreComments) { XmlDiffCharData charDataNode = new XmlDiffCharData(childPosition, reader.Value, XmlDiffNodeType.Comment); charDataNode.ComputeHashValue(_xmlHash); InsertChild(parent, charDataNode); } break; } case XmlNodeType.ProcessingInstruction: { ++childPosition; if (!_XmlDiff.IgnorePI) { XmlDiffPI pi = new XmlDiffPI(childPosition, reader.Name, reader.Value); pi.ComputeHashValue(_xmlHash); InsertChild(parent, pi); } break; } case XmlNodeType.SignificantWhitespace: { if (reader.XmlSpace == XmlSpace.Preserve) { ++childPosition; if (!_XmlDiff.IgnoreWhitespace) { XmlDiffCharData charDataNode = new XmlDiffCharData(childPosition, reader.Value, XmlDiffNodeType.SignificantWhitespace); charDataNode.ComputeHashValue(_xmlHash); InsertChild(parent, charDataNode); } } break; } case XmlNodeType.XmlDeclaration: { ++childPosition; if (!_XmlDiff.IgnoreXmlDecl) { XmlDiffXmlDeclaration xmlDecl = new XmlDiffXmlDeclaration(childPosition, XmlDiff.NormalizeXmlDeclaration(reader.Value)); xmlDecl.ComputeHashValue(_xmlHash); InsertChild(parent, xmlDecl); } break; } case XmlNodeType.EndElement: goto End; case XmlNodeType.DocumentType: childPosition++; if (!_XmlDiff.IgnoreDtd) { XmlDiffDocumentType docType = new XmlDiffDocumentType(childPosition, reader.Name, reader.GetAttribute("PUBLIC"), reader.GetAttribute("SYSTEM"), reader.Value); docType.ComputeHashValue(_xmlHash); InsertChild(parent, docType); } break; default: Debug.Assert(false); break; } } while (reader.Read()); End: _curLastChild = savedLastChild; }
private void WalkTreeGenerateDiffgramMatch( DiffgramParentOperation diffParent, XmlDiffParentNode sourceParent, XmlDiffParentNode targetParent ) { XmlDiffNode sourceNode = sourceParent.FirstChildNode; XmlDiffNode targetNode = targetParent.FirstChildNode; XmlDiffNode needPositionSourceNode = null; while ( sourceNode != null || targetNode != null ) { if ( sourceNode != null ) { if ( targetNode != null ) { XmlDiffOperation op = sourceNode.GetDiffOperation( targetNode, _xmlDiff ); // match if ( op == XmlDiffOperation.Match ) { WalkTreeOnMatchNode( diffParent, sourceNode, targetNode, ref needPositionSourceNode ); } // no match else { int walkNodesCount = ( sourceNode._parent.ChildNodesCount + targetNode._parent.ChildNodesCount ) / 2; walkNodesCount = (int)( LogMultiplier * Math.Log( (double)walkNodesCount ) + 1 ); XmlDiffNode sourceClosestMatchNode = targetNode; XmlDiffNode targetClosestMatchNode = sourceNode; XmlDiffOperation sourceOp = op; XmlDiffOperation targetOp = op; int sourceNodesToAddCount = targetNode.NodesCount; int targetNodesToRemoveCount = sourceNode.NodesCount; XmlDiffNode nextSourceNode = sourceNode._nextSibling; XmlDiffNode nextTargetNode = targetNode._nextSibling; // walk limited number of siblings to find the closest matching node for ( int i = 0; i < walkNodesCount && ( nextTargetNode != null || nextSourceNode != null ); i++ ) { if ( nextTargetNode != null && sourceOp != XmlDiffOperation.Match ) { XmlDiffOperation o = sourceNode.GetDiffOperation( nextTargetNode, _xmlDiff ); if ( MinimalTreeDistanceAlgo.OperationCost[(int)o] < MinimalTreeDistanceAlgo.OperationCost[(int)sourceOp] ) { sourceOp = o; sourceClosestMatchNode = nextTargetNode; } else { sourceNodesToAddCount += nextTargetNode.NodesCount; nextTargetNode = nextTargetNode._nextSibling; } } if ( nextSourceNode != null && targetOp != XmlDiffOperation.Match ) { XmlDiffOperation o = targetNode.GetDiffOperation( nextSourceNode, _xmlDiff ); if ( MinimalTreeDistanceAlgo.OperationCost[(int)o] < MinimalTreeDistanceAlgo.OperationCost[(int)targetOp] ) { targetOp = o; targetClosestMatchNode = nextSourceNode; } else { targetNodesToRemoveCount += nextSourceNode.NodesCount; nextSourceNode = nextSourceNode._nextSibling; } } if ( sourceOp == XmlDiffOperation.Match || targetOp == XmlDiffOperation.Match ) { break; } if ( _xmlDiff.IgnoreChildOrder ) { if ( nextTargetNode != null ) { if ( XmlDiffDocument.OrderChildren( sourceNode, nextTargetNode ) < 0 ) { nextTargetNode = null; } } if ( nextSourceNode != null ) { if ( XmlDiffDocument.OrderChildren( targetNode, nextSourceNode ) < 0 ) { nextSourceNode = null; } } } } // source match exists and is better if ( sourceOp == XmlDiffOperation.Match ) { if ( targetOp != XmlDiffOperation.Match || sourceNodesToAddCount < targetNodesToRemoveCount ) { while ( targetNode != sourceClosestMatchNode ) { WalkTreeOnAddNode( diffParent, targetNode, needPositionSourceNode ); needPositionSourceNode = null; targetNode = targetNode._nextSibling; } WalkTreeOnMatchNode( diffParent, sourceNode, targetNode, ref needPositionSourceNode ); goto MoveToNextPair; } } // target match exists and is better else if ( targetOp == XmlDiffOperation.Match ) { while ( sourceNode != targetClosestMatchNode ) { WalkTreeOnRemoveNode( diffParent, sourceNode ); sourceNode = sourceNode._nextSibling; } needPositionSourceNode = null; WalkTreeOnMatchNode( diffParent, sourceNode, targetNode, ref needPositionSourceNode ); goto MoveToNextPair; } // partial match else { Debug.Assert( sourceOp != XmlDiffOperation.Match && targetOp != XmlDiffOperation.Match ); int sourceOpCost = MinimalTreeDistanceAlgo.OperationCost[ (int)sourceOp ]; int targetOpCost = MinimalTreeDistanceAlgo.OperationCost[ (int)targetOp ]; if ( sourceOpCost < targetOpCost || ( sourceOpCost == targetOpCost && sourceNodesToAddCount < targetNodesToRemoveCount ) ) { while ( targetNode != sourceClosestMatchNode ) { WalkTreeOnAddNode( diffParent, targetNode, needPositionSourceNode ); needPositionSourceNode = null; targetNode = targetNode._nextSibling; } op = sourceOp; } else { while ( sourceNode != targetClosestMatchNode ) { WalkTreeOnRemoveNode( diffParent, sourceNode ); sourceNode = sourceNode._nextSibling; } op = targetOp; } } // decide whether do 'change' or 'add / delete' switch ( op ) { case XmlDiffOperation.ChangeElementName: WalkTreeOnChangeElement( diffParent, (XmlDiffElement)sourceNode, (XmlDiffElement)targetNode, op ); needPositionSourceNode = null; break; case XmlDiffOperation.ChangeElementAttr1: case XmlDiffOperation.ChangeElementAttr2: case XmlDiffOperation.ChangeElementAttr3: case XmlDiffOperation.ChangeElementNameAndAttr1: case XmlDiffOperation.ChangeElementNameAndAttr2: case XmlDiffOperation.ChangeElementNameAndAttr3: if ( GoForElementChange( (XmlDiffElement)sourceNode, (XmlDiffElement)targetNode ) ) { WalkTreeOnChangeElement( diffParent, (XmlDiffElement) sourceNode, (XmlDiffElement)targetNode, op ); needPositionSourceNode = null; } else { goto case XmlDiffOperation.Undefined; } break; case XmlDiffOperation.ChangePI: case XmlDiffOperation.ChangeER: case XmlDiffOperation.ChangeCharacterData: case XmlDiffOperation.ChangeXmlDeclaration: case XmlDiffOperation.ChangeDTD: diffParent.InsertAtEnd( new DiffgramChangeNode( sourceNode, targetNode, op, 0 ) ); needPositionSourceNode = null; break; case XmlDiffOperation.Undefined: // Prefer inserts against removes WalkTreeOnAddNode( diffParent, targetNode, needPositionSourceNode ); needPositionSourceNode = null; targetNode = targetNode._nextSibling; continue; default: Debug.Assert( false ); break; } } MoveToNextPair: sourceNode = sourceNode._nextSibling; targetNode = targetNode._nextSibling; } else { // targetNode == null do { WalkTreeOnRemoveNode( diffParent, sourceNode ); sourceNode = sourceNode._nextSibling; } while ( sourceNode != null ); } } else { // sourceNode == null Debug.Assert( targetNode != null ); while ( targetNode != null ) { WalkTreeOnAddNode( diffParent, targetNode, needPositionSourceNode ); needPositionSourceNode = null; targetNode = targetNode._nextSibling; } } } }
// Inserts the 'newChild' node. If child order is significant, the new child is // inserted at the end of all child nodes. If the child order is not signoficant, // the new node is sorted into the other child nodes. private void InsertChild( XmlDiffParentNode parent, XmlDiffNode newChild ) { if ( _XmlDiff.IgnoreChildOrder ) { XmlDiffNode curChild = parent.FirstChildNode; XmlDiffNode prevChild = null; while ( curChild != null && ( OrderChildren( curChild, newChild ) <= 0 ) ) { prevChild = curChild; curChild = curChild._nextSibling; } parent.InsertChildNodeAfter( prevChild, newChild ); } else { parent.InsertChildNodeAfter( _curLastChild, newChild ); _curLastChild = newChild; } }
// Loads child nodes of the 'parent' node internal void LoadChildNodes ( XmlDiffParentNode parent, XmlReader reader, bool bEmptyElement ) { XmlDiffNode savedLastChild = _curLastChild; _curLastChild = null; // load attributes & namespace nodes while ( reader.MoveToNextAttribute() ) { if ( reader.Prefix == "xmlns" ) { if ( !_XmlDiff.IgnoreNamespaces ) { XmlDiffNamespace nsNode = new XmlDiffNamespace( reader.LocalName, reader.Value ); nsNode.ComputeHashValue( _xmlHash ); InsertAttributeOrNamespace( (XmlDiffElement)parent, nsNode ); } } else if ( reader.Prefix == string.Empty && reader.LocalName == "xmlns" ) { if ( !_XmlDiff.IgnoreNamespaces ) { XmlDiffNamespace nsNode = new XmlDiffNamespace( string.Empty, reader.Value ); nsNode.ComputeHashValue( _xmlHash ); InsertAttributeOrNamespace( (XmlDiffElement)parent, nsNode ); } } else { string attrValue = _XmlDiff.IgnoreWhitespace ? XmlDiff.NormalizeText( reader.Value ) : reader.Value; XmlDiffAttribute attr = new XmlDiffAttribute( reader.LocalName, reader.Prefix, reader.NamespaceURI, attrValue ); attr.ComputeHashValue( _xmlHash ); InsertAttributeOrNamespace( (XmlDiffElement)parent, attr ); } } // empty element -> return, do not load chilren if ( bEmptyElement ) goto End; int childPosition = 0; // load children if ( !reader.Read()) goto End; do { // ignore whitespaces between nodes if ( reader.NodeType == XmlNodeType.Whitespace ) continue; switch ( reader.NodeType ) { case XmlNodeType.Element: { bool bEmptyEl = reader.IsEmptyElement; XmlDiffElement elem = new XmlDiffElement( ++childPosition, reader.LocalName, reader.Prefix, reader.NamespaceURI ); LoadChildNodes( elem, reader, bEmptyEl ); elem.ComputeHashValue( _xmlHash ); InsertChild( parent, elem ); break; } case XmlNodeType.Attribute: { Debug.Assert( false, "We should never get to this point, attributes should be read at the beginning of thid method." ); break; } case XmlNodeType.Text: { string textValue = ( _XmlDiff.IgnoreWhitespace ) ? XmlDiff.NormalizeText( reader.Value ) : reader.Value; XmlDiffCharData charDataNode = new XmlDiffCharData( ++childPosition, textValue, XmlDiffNodeType.Text ); charDataNode.ComputeHashValue( _xmlHash ); InsertChild( parent, charDataNode ); break; } case XmlNodeType.CDATA: { XmlDiffCharData charDataNode = new XmlDiffCharData( ++childPosition, reader.Value, XmlDiffNodeType.CDATA ); charDataNode.ComputeHashValue( _xmlHash ); InsertChild( parent, charDataNode ); break; } case XmlNodeType.EntityReference: { XmlDiffER er = new XmlDiffER( ++childPosition, reader.Name ); er.ComputeHashValue( _xmlHash ); InsertChild( parent, er ); break; } case XmlNodeType.Comment: { ++childPosition; if ( !_XmlDiff.IgnoreComments ) { XmlDiffCharData charDataNode = new XmlDiffCharData( childPosition, reader.Value, XmlDiffNodeType.Comment ); charDataNode.ComputeHashValue( _xmlHash ); InsertChild( parent, charDataNode ); } break; } case XmlNodeType.ProcessingInstruction: { ++childPosition; if ( !_XmlDiff.IgnorePI ) { XmlDiffPI pi = new XmlDiffPI( childPosition, reader.Name, reader.Value ); pi.ComputeHashValue( _xmlHash ); InsertChild( parent, pi ); } break; } case XmlNodeType.SignificantWhitespace: { if( reader.XmlSpace == XmlSpace.Preserve ) { ++childPosition; if (!_XmlDiff.IgnoreWhitespace ) { XmlDiffCharData charDataNode = new XmlDiffCharData( childPosition, reader.Value, XmlDiffNodeType.SignificantWhitespace ); charDataNode.ComputeHashValue( _xmlHash ); InsertChild( parent, charDataNode ); } } break; } case XmlNodeType.XmlDeclaration: { ++childPosition; if ( !_XmlDiff.IgnoreXmlDecl ) { XmlDiffXmlDeclaration xmlDecl = new XmlDiffXmlDeclaration( childPosition, XmlDiff.NormalizeXmlDeclaration( reader.Value ) ); xmlDecl.ComputeHashValue( _xmlHash ); InsertChild( parent, xmlDecl ); } break; } case XmlNodeType.EndElement: goto End; case XmlNodeType.DocumentType: childPosition++; if ( !_XmlDiff.IgnoreDtd ) { XmlDiffDocumentType docType = new XmlDiffDocumentType( childPosition, reader.Name, reader.GetAttribute("PUBLIC"), reader.GetAttribute("SYSTEM"), reader.Value ); docType.ComputeHashValue( _xmlHash ); InsertChild( parent, docType ); } break; default: Debug.Assert( false ); break; } } while ( reader.Read() ); End: _curLastChild = savedLastChild; }
private void ComputeHashXmlDiffChildren( HashAlgorithm ha, XmlDiffParentNode parent ) { int childrenCount = 0; if ( _bIgnoreChildOrder ) { ulong totalHash = 0; XmlDiffNode curChild = parent.FirstChildNode; while ( curChild != null ) { Debug.Assert( !( curChild is XmlDiffAttributeOrNamespace ) ); Debug.Assert ( curChild.HashValue != 0 ); totalHash += curChild.HashValue; childrenCount++; curChild = curChild._nextSibling; } ha.AddULong( totalHash ); } else { XmlDiffNode curChild = parent.FirstChildNode; while ( curChild != null ) { Debug.Assert( !( curChild is XmlDiffAttributeOrNamespace ) ); Debug.Assert ( curChild.HashValue != 0 ); ha.AddULong( curChild.HashValue ); childrenCount++; curChild = curChild._nextSibling; } } if ( childrenCount != 0 ) ha.AddInt( childrenCount ); }