private void OnRemove( DiffgramParentOperation parent ) { EditScriptRemove remOp = _editScript as EditScriptRemove; Debug.Assert( remOp._endSourceIndex == _curSourceIndex ); XmlDiffNode sourceRoot = _sourceNodes[ remOp._endSourceIndex ]; // remove subtree or leaf node and no descendant node matches (=has been moved somewhere else) if ( remOp._startSourceIndex <= sourceRoot.Left ) { bool bShrankNode = sourceRoot is XmlDiffShrankNode; if ( sourceRoot._bSomeDescendantMatches && !bShrankNode ) { DiffgramOperation newDiffOp = GenerateDiffgramRemoveWhenDescendantMatches( (XmlDiffParentNode)sourceRoot ); if ( _bBuildingAddTree ) { PostponedOperation( newDiffOp, sourceRoot.Left, remOp._endSourceIndex ); } else { parent.InsertAtBeginning( newDiffOp ); } } else { ulong opid = 0; // shrank node -> output as 'move' operation if ( bShrankNode ) { XmlDiffShrankNode shrankNode = (XmlDiffShrankNode) sourceRoot; if ( shrankNode.MoveOperationId == 0 ) shrankNode.MoveOperationId = GenerateOperationID( XmlDiffDescriptorType.Move ); opid = shrankNode.MoveOperationId; Debug.Assert( sourceRoot == _sourceNodes[ sourceRoot.Left ] ); } // insert 'remove' operation if ( _bBuildingAddTree ) { PostponedRemoveSubtrees( sourceRoot, opid, //AddToPosponedOperations( new DiffgramRemoveSubtrees( sourceRoot, opid ), sourceRoot.Left, remOp._endSourceIndex ); } else { if ( opid != 0 || !parent.MergeRemoveSubtreeAtBeginning( sourceRoot ) ) { parent.InsertAtBeginning( new DiffgramRemoveSubtrees( sourceRoot, opid, !_xmlDiff.IgnoreChildOrder ) ); } } } // adjust current position _curSourceIndex = sourceRoot.Left - 1; // adjust boundaries in the edit script or move to next edit script operation remOp._endSourceIndex = sourceRoot.Left - 1; if ( remOp._startSourceIndex > remOp._endSourceIndex ) _editScript = _editScript._nextEditScript; } // remove single but non-leaf node or some descendant matches (=has been moved somewhere else) // -> recursively process diffgram subtree else { Debug.Assert( !( sourceRoot is XmlDiffShrankNode) ); // adjust current position _curSourceIndex--; // adjust boundaries in the edit script or move to next edit script operation remOp._endSourceIndex--; if ( remOp._startSourceIndex > remOp._endSourceIndex ) _editScript = _editScript._nextEditScript; bool bRemoveSubtree = sourceRoot.NodeType != XmlDiffNodeType.Element; if ( _bBuildingAddTree ) { // add 'remove' to postponed operations PostponedRemoveNode( sourceRoot, bRemoveSubtree, 0, //AddToPosponedOperations( new DiffgramRemoveNode( sourceRoot, bRemoveSubtree, 0 ), remOp._endSourceIndex + 1, remOp._endSourceIndex + 1 ); // recursively parse subtree GenerateDiffgramAdd( parent, sourceRoot.Left, _targetNodes[ _curTargetIndex ].Left ); } else { // 'remove' operation DiffgramRemoveNode remNode = new DiffgramRemoveNode( sourceRoot, bRemoveSubtree, 0 ); // parse subtree GenerateDiffgramMatch( remNode, sourceRoot.Left, _targetNodes[ _curTargetIndex ].Left ); parent.InsertAtBeginning( remNode ); } } }
void OnEditScriptPostponed( DiffgramParentOperation parent, int targetBorderIndex ) { EditScriptPostponed esp = (EditScriptPostponed)_editScript; Debug.Assert( _curSourceIndex == esp._endSourceIndex ); DiffgramOperation diffOp = esp._diffOperation; int sourceStartIndex = esp._startSourceIndex; int sourceLeft = _sourceNodes[ esp._endSourceIndex ].Left; // adjust current source index _curSourceIndex = esp._startSourceIndex - 1; // move to next edit script _editScript = esp._nextEditScript; // not a subtree or leaf node operation -> process child operations if ( sourceStartIndex > sourceLeft ) { GenerateDiffgramPostponed( (DiffgramParentOperation)diffOp, ref _editScript, sourceLeft, targetBorderIndex ); } parent.InsertAtBeginning( diffOp ); }
private void OnMatch( DiffgramParentOperation parent, bool bNeedPosition ) { EditScriptMatch matchOp = _editScript as EditScriptMatch; Debug.Assert( _curSourceIndex == matchOp._firstSourceIndex + matchOp._length - 1 ); Debug.Assert( _curTargetIndex == matchOp._firstTargetIndex + matchOp._length - 1 ); // cache int endTargetIndex = matchOp._firstTargetIndex + matchOp._length - 1; int endSourceIndex = matchOp._firstSourceIndex + matchOp._length - 1; XmlDiffNode targetRoot = _targetNodes[ endTargetIndex ]; XmlDiffNode sourceRoot = _sourceNodes[ endSourceIndex ]; // a subtree or leaf node matches if ( matchOp._firstTargetIndex <= targetRoot.Left && matchOp._firstSourceIndex <= sourceRoot.Left ) { if ( _bBuildingAddTree ) { Debug.Assert( !bNeedPosition ); ulong opid = GenerateOperationID( XmlDiffDescriptorType.Move ); // output <add match=" "> to diffgram and "remove" to substitute script parent.InsertAtBeginning( new DiffgramCopy( sourceRoot, true, opid ) ); // add 'remove' operation to postponed operations PostponedRemoveSubtrees( sourceRoot, opid, //AddToPosponedOperations( new DiffgramRemoveSubtrees( sourceRoot, opid ), sourceRoot.Left, endSourceIndex ); } else { // matched element -> check attributes if they really match (hash values of attributes matches) if ( sourceRoot.NodeType == XmlDiffNodeType.Element ) { DiffgramPosition diffPos = _cachedDiffgramPosition; diffPos._sourceNode = sourceRoot; GenerateChangeDiffgramForAttributes( diffPos, (XmlDiffElement)sourceRoot, (XmlDiffElement)targetRoot ); if ( diffPos._firstChildOp != null || bNeedPosition ) { parent.InsertAtBeginning( diffPos ); _cachedDiffgramPosition = new DiffgramPosition( null ); bNeedPosition = false; } } // otherwise output <node> - only if we need the position (<=> preceding operation was 'add') else { if ( bNeedPosition ) { parent.InsertAtBeginning( new DiffgramPosition( sourceRoot ) ); bNeedPosition = false; } // xml declaration, DTD else if ( !_bChildOrderSignificant && (int)sourceRoot.NodeType < 0 ) { DiffgramOperation op = parent._firstChildOp; if ( op is DiffgramAddNode || op is DiffgramAddSubtrees || op is DiffgramCopy ) { parent.InsertAtBeginning( new DiffgramPosition( sourceRoot ) ); } } } } // adjust current position _curSourceIndex = sourceRoot.Left - 1; _curTargetIndex = targetRoot.Left - 1; // adjust boundaries in the edit script or move to next edit script operation matchOp._length -= endTargetIndex - targetRoot.Left + 1; if ( matchOp._length <= 0 ) _editScript = _editScript._nextEditScript; } // single but non-leaf node matches (-> recursively generate the diffgram subtree) else { // adjust current position _curSourceIndex--; _curTargetIndex--; // adjust boundaries in the edit script or move to next edit script operation matchOp._length--; if ( matchOp._length <= 0 ) _editScript = _editScript._nextEditScript; DiffgramParentOperation diffgramNode; if ( _bBuildingAddTree ) { Debug.Assert( !bNeedPosition ); ulong opid = GenerateOperationID( XmlDiffDescriptorType.Move ); bool bCopySubtree = sourceRoot.NodeType != XmlDiffNodeType.Element; // output <add match=".." subtree="no"> diffgramNode = new DiffgramCopy( sourceRoot, bCopySubtree, opid ); // add 'remove' operation to postponed operations PostponedRemoveNode( sourceRoot, bCopySubtree, opid, endSourceIndex, endSourceIndex ); // recursively generate the diffgram subtree GenerateDiffgramAdd( diffgramNode, sourceRoot.Left, targetRoot.Left ); // insert to diffgram tree parent.InsertAtBeginning( diffgramNode ); } else { // output <node> diffgramNode = new DiffgramPosition( sourceRoot ); // recursively generate the diffgram subtree GenerateDiffgramMatch( diffgramNode, sourceRoot.Left, targetRoot.Left ); // insert to diffgram tree if ( diffgramNode._firstChildOp != null ) parent.InsertAtBeginning( diffgramNode ); } } }
// returns true if a positioning <node> element is needed in diffgram private bool OnAdd( DiffgramParentOperation parent, int sourceBorderIndex, int targetBorderIndex ) { EditScriptAdd addOp = _editScript as EditScriptAdd; Debug.Assert( addOp._endTargetIndex == _curTargetIndex ); XmlDiffNode targetRoot = _targetNodes[ addOp._endTargetIndex ]; // add subtree or leaf node and no descendant node matches (= has been moved from somewhere else) if ( addOp._startTargetIndex <= targetRoot.Left && !targetRoot._bSomeDescendantMatches ) { switch ( targetRoot.NodeType ) { case XmlDiffNodeType.ShrankNode: XmlDiffShrankNode shrankNode = (XmlDiffShrankNode)targetRoot; if ( shrankNode.MoveOperationId == 0 ) shrankNode.MoveOperationId = GenerateOperationID( XmlDiffDescriptorType.Move ); parent.InsertAtBeginning( new DiffgramCopy( shrankNode.MatchingShrankNode, true, shrankNode.MoveOperationId ) ); break; case XmlDiffNodeType.XmlDeclaration: case XmlDiffNodeType.DocumentType: case XmlDiffNodeType.EntityReference: parent.InsertAtBeginning( new DiffgramAddNode( targetRoot, 0 ) ); break; default: if ( !parent.MergeAddSubtreeAtBeginning( targetRoot ) ) { parent.InsertAtBeginning( new DiffgramAddSubtrees( targetRoot, 0, !_xmlDiff.IgnoreChildOrder ) ); } break; } // adjust current position _curTargetIndex = targetRoot.Left - 1; // adjust boundaries in the edit script or move to next edit script operation addOp._endTargetIndex = targetRoot.Left - 1; if ( addOp._startTargetIndex > addOp._endTargetIndex ) _editScript = _editScript._nextEditScript; } // add single but non-leaf node, or some descendant matches (= has been moved from somewhere else ) // -> recursively process diffgram subtree else { Debug.Assert( !( targetRoot is XmlDiffShrankNode) ); DiffgramAddNode addNode = new DiffgramAddNode( targetRoot, 0 ); // adjust current position _curTargetIndex--; // adjust boundaries in the edit script or move to next edit script operation addOp._endTargetIndex--; if ( addOp._startTargetIndex > addOp._endTargetIndex ) _editScript = _editScript._nextEditScript; if ( _bBuildingAddTree ) { GenerateDiffgramAdd( addNode, sourceBorderIndex, targetRoot.Left ); } else { // switch to 'building add-tree' mode _postponedEditScript.Reset(); _bBuildingAddTree = true; // generate new tree GenerateDiffgramAdd( addNode, sourceBorderIndex, targetRoot.Left ); _bBuildingAddTree = false; // attach postponed edit script to _editScript for futher processing if ( _postponedEditScript._firstES != null ) { Debug.Assert( _postponedEditScript._lastES != null ); Debug.Assert( _postponedEditScript._startSourceIndex != 0 ); Debug.Assert( _postponedEditScript._endSourceIndex != 0 ); _curSourceIndex = _postponedEditScript._endSourceIndex; _postponedEditScript._lastES._nextEditScript = _editScript; _editScript = _postponedEditScript._firstES; } } // add attributes if ( targetRoot.NodeType == XmlDiffNodeType.Element ) GenerateAddDiffgramForAttributes( addNode, (XmlDiffElement)targetRoot ); parent.InsertAtBeginning( addNode ); } // return true if positioning <node> element is needed in diffgram if ( _bChildOrderSignificant ) { return !_bBuildingAddTree; } else { return false; } }
// produces <change> element in diffgram private void OnChange( DiffgramParentOperation parent ) { EditScriptChange chOp = _editScript as EditScriptChange; Debug.Assert( chOp._targetIndex == _curTargetIndex ); Debug.Assert( chOp._sourceIndex == _curSourceIndex ); XmlDiffNode sourceRoot = _sourceNodes[ chOp._sourceIndex ]; XmlDiffNode targetRoot = _targetNodes[ chOp._targetIndex ]; Debug.Assert( !( sourceRoot is XmlDiffShrankNode) ); Debug.Assert( !( targetRoot is XmlDiffShrankNode) ); // adjust current position _curSourceIndex--; _curTargetIndex--; // move to next edit script operation _editScript = _editScript._nextEditScript; DiffgramOperation diffgramNode = null; if ( _bBuildingAddTree ) { // <add> changed node to the new location if ( targetRoot.NodeType == XmlDiffNodeType.Element ) diffgramNode = new DiffgramAddNode( targetRoot, 0 ); else diffgramNode = new DiffgramAddSubtrees( targetRoot, 0, !_xmlDiff.IgnoreChildOrder ); // <remove> old node from old location -> add to postponed operations bool bSubtree = sourceRoot.NodeType != XmlDiffNodeType.Element; PostponedRemoveNode( sourceRoot, bSubtree, 0, //AddToPosponedOperations( new DiffgramRemoveNode( sourceRoot, bSubtree, 0 ), chOp._sourceIndex, chOp._sourceIndex ); // recursively process children if ( sourceRoot.Left < chOp._sourceIndex || targetRoot.Left < chOp._targetIndex ) { Debug.Assert( targetRoot.NodeType == XmlDiffNodeType.Element ); GenerateDiffgramAdd( (DiffgramParentOperation)diffgramNode, sourceRoot.Left, targetRoot.Left ); } // add attributes, if element if ( targetRoot.NodeType == XmlDiffNodeType.Element ) GenerateAddDiffgramForAttributes( (DiffgramParentOperation)diffgramNode, (XmlDiffElement)targetRoot ); } else { ulong opid = 0; // change of namespace or prefix -> get the appropriate operation id if ( !_xmlDiff.IgnoreNamespaces && sourceRoot.NodeType == XmlDiffNodeType.Element ) { XmlDiffElement sourceEl = (XmlDiffElement)sourceRoot; XmlDiffElement targetEl = (XmlDiffElement)targetRoot; if ( sourceEl.LocalName == targetEl.LocalName ) { opid = GetNamespaceChangeOpid( sourceEl.NamespaceURI, sourceEl.Prefix, targetEl.NamespaceURI, targetEl.Prefix ); } } if ( sourceRoot.NodeType == XmlDiffNodeType.Element ) { if ( XmlDiff.IsChangeOperationOnAttributesOnly( chOp._changeOp ) ) diffgramNode = new DiffgramPosition( sourceRoot ); else { Debug.Assert( (int)chOp._changeOp == (int)XmlDiffOperation.ChangeElementName || ( (int)chOp._changeOp >= (int)XmlDiffOperation.ChangeElementNameAndAttr1 && (int)chOp._changeOp <= (int)XmlDiffOperation.ChangeElementNameAndAttr2 ) ); diffgramNode = new DiffgramChangeNode( sourceRoot, targetRoot, XmlDiffOperation.ChangeElementName, opid ); } // recursively process children if ( sourceRoot.Left < chOp._sourceIndex || targetRoot.Left < chOp._targetIndex ) { GenerateDiffgramMatch( (DiffgramParentOperation) diffgramNode, sourceRoot.Left, targetRoot.Left ); } GenerateChangeDiffgramForAttributes( (DiffgramParentOperation)diffgramNode, (XmlDiffElement)sourceRoot, (XmlDiffElement)targetRoot ); } else { // '<change>' diffgramNode = new DiffgramChangeNode( sourceRoot, targetRoot, chOp._changeOp, opid ); Debug.Assert( !sourceRoot.HasChildNodes ); } } parent.InsertAtBeginning( diffgramNode ); }
private void GenerateDiffgramMatch( DiffgramParentOperation parent, int sourceBorderIndex, int targetBorderIndex ) { bool bNeedPosition = false; while ( _curSourceIndex >= sourceBorderIndex || _curTargetIndex >= targetBorderIndex ) { Debug.Assert( _editScript != null ); switch ( _editScript.Operation ) { case EditScriptOperation.Match: OnMatch( parent, bNeedPosition ); bNeedPosition = false; break; case EditScriptOperation.Add: bNeedPosition = OnAdd( parent, sourceBorderIndex, targetBorderIndex ); break; case EditScriptOperation.Remove: if ( _curSourceIndex < sourceBorderIndex ) return; OnRemove( parent ); break; case EditScriptOperation.ChangeNode: if ( _curSourceIndex < sourceBorderIndex ) return; OnChange( parent ); break; case EditScriptOperation.EditScriptPostponed: if ( _curSourceIndex < sourceBorderIndex ) return; OnEditScriptPostponed( parent, targetBorderIndex ); break; default: Debug.Assert( false, "Invalid edit script operation type in final edit script." ); break; } } }
private void GenerateDiffgramPostponed( DiffgramParentOperation parent, ref EditScript editScript, int sourceBorderIndex, int targetBorderIndex ) { while ( _curSourceIndex >= sourceBorderIndex && editScript != null ) { EditScriptPostponed esp = editScript as EditScriptPostponed; if ( esp == null ) { GenerateDiffgramMatch( parent, sourceBorderIndex, targetBorderIndex ); return; } Debug.Assert( esp._endSourceIndex == _curSourceIndex ); int sourceStartIndex = esp._startSourceIndex; int sourceLeft = _sourceNodes[ esp._endSourceIndex ].Left; DiffgramOperation diffOp = esp._diffOperation; // adjust current source index _curSourceIndex = esp._startSourceIndex - 1; // move to next edit script editScript = esp._nextEditScript; // not a subtree or leaf node operation -> process child operations if ( sourceStartIndex > sourceLeft ) { GenerateDiffgramPostponed( (DiffgramParentOperation) diffOp, ref editScript, sourceLeft, targetBorderIndex ); } // insert operation parent.InsertAtBeginning( diffOp ); } }
private void GenerateChangeDiffgramForAttributes( DiffgramParentOperation diffgramParent, XmlDiffElement sourceElement, XmlDiffElement targetElement) { XmlDiffAttributeOrNamespace sourceAttr = sourceElement._attributes; XmlDiffAttributeOrNamespace targetAttr = targetElement._attributes; int nCompare; ulong opid; while ( sourceAttr != null && targetAttr != null ) { opid = 0; if ( sourceAttr.NodeType == targetAttr.NodeType ) { if ( sourceAttr.NodeType == XmlDiffNodeType.Attribute ) { if ( (nCompare = XmlDiffDocument.OrderStrings( sourceAttr.LocalName, targetAttr.LocalName )) == 0 ) { if ( _xmlDiff.IgnoreNamespaces ) { if ( XmlDiffDocument.OrderStrings( sourceAttr.Value, targetAttr.Value ) == 0 ) { // attributes match goto Next; } } else { if ( XmlDiffDocument.OrderStrings( sourceAttr.NamespaceURI, targetAttr.NamespaceURI ) == 0 && (_xmlDiff.IgnorePrefixes || XmlDiffDocument.OrderStrings( sourceAttr.Prefix, targetAttr.Prefix ) == 0 ) && XmlDiffDocument.OrderStrings( sourceAttr.Value, targetAttr.Value ) == 0 ) { // attributes match goto Next; } } diffgramParent.InsertAtBeginning( new DiffgramChangeNode( sourceAttr, targetAttr, XmlDiffOperation.ChangeAttr, 0 ) ); goto Next; } goto AddRemove; } else // sourceAttr.NodeType != XmlDiffNodeType.Attribute { if ( _xmlDiff.IgnorePrefixes ) { if ( ( nCompare = XmlDiffDocument.OrderStrings( sourceAttr.NamespaceURI, targetAttr.NamespaceURI ) ) == 0 ) goto Next; else goto AddRemove; } else if ( ( nCompare = XmlDiffDocument.OrderStrings( sourceAttr.Prefix, targetAttr.Prefix ) ) == 0 ) { if ( ( nCompare = XmlDiffDocument.OrderStrings( sourceAttr.NamespaceURI, targetAttr.NamespaceURI ) ) == 0 ) goto Next; else { // change of namespace opid = GetNamespaceChangeOpid( sourceAttr.NamespaceURI, sourceAttr.Prefix, targetAttr.NamespaceURI, targetAttr.Prefix ); goto AddRemoveBoth; } } else { if ( ( nCompare = XmlDiffDocument.OrderStrings( sourceAttr.NamespaceURI, targetAttr.NamespaceURI ) ) == 0 ) { // change of prefix opid = GetNamespaceChangeOpid( sourceAttr.NamespaceURI, sourceAttr.Prefix, targetAttr.NamespaceURI, targetAttr.Prefix ); goto AddRemoveBoth; } else { goto AddRemove; } } } } else // ( sourceAttr.NodeType != targetAttr.NodeType ) { if ( sourceAttr.NodeType == XmlDiffNodeType.Namespace ) goto RemoveSource; else goto AddTarget; } Next: sourceAttr = (XmlDiffAttributeOrNamespace)sourceAttr._nextSibling; targetAttr = (XmlDiffAttributeOrNamespace)targetAttr._nextSibling; continue; AddRemove: if ( nCompare == -1 ) goto RemoveSource; else { Debug.Assert( nCompare == 1 ); goto AddTarget; } AddRemoveBoth: if ( !diffgramParent.MergeRemoveAttributeAtBeginning( sourceAttr ) ) diffgramParent.InsertAtBeginning( new DiffgramRemoveNode( sourceAttr, true, opid ) ); sourceAttr = (XmlDiffAttributeOrNamespace)sourceAttr._nextSibling; diffgramParent.InsertAtBeginning( new DiffgramAddNode( targetAttr, opid ) ); targetAttr = (XmlDiffAttributeOrNamespace)targetAttr._nextSibling; continue; RemoveSource: if ( !diffgramParent.MergeRemoveAttributeAtBeginning( sourceAttr ) ) diffgramParent.InsertAtBeginning( new DiffgramRemoveNode( sourceAttr, true, opid ) ); sourceAttr = (XmlDiffAttributeOrNamespace)sourceAttr._nextSibling; continue; AddTarget: diffgramParent.InsertAtBeginning( new DiffgramAddNode( targetAttr, opid ) ); targetAttr = (XmlDiffAttributeOrNamespace)targetAttr._nextSibling; continue; } while ( sourceAttr != null ) { if ( !diffgramParent.MergeRemoveAttributeAtBeginning( sourceAttr ) ) diffgramParent.InsertAtBeginning( new DiffgramRemoveNode( sourceAttr, true, 0 ) ); sourceAttr = (XmlDiffAttributeOrNamespace)sourceAttr._nextSibling; } while ( targetAttr != null ) { diffgramParent.InsertAtBeginning( new DiffgramAddNode( targetAttr, 0 ) ); targetAttr = (XmlDiffAttributeOrNamespace)targetAttr._nextSibling; } }
private void GenerateDiffgramAdd( DiffgramParentOperation parent, int sourceBorderIndex, int targetBorderIndex ) { while ( _curTargetIndex >= targetBorderIndex ) { Debug.Assert( _editScript != null ); switch ( _editScript.Operation ) { case EditScriptOperation.Match: OnMatch( parent, false ); break; case EditScriptOperation.Add: OnAdd( parent, sourceBorderIndex, targetBorderIndex ); break; case EditScriptOperation.Remove: OnRemove( parent ); break; case EditScriptOperation.ChangeNode: OnChange( parent ); break; case EditScriptOperation.EditScriptPostponed: OnEditScriptPostponed( parent, targetBorderIndex ); break; default: Debug.Assert( false, "Invalid edit script operation type in final edit script." ); break; } } }
private void WalkTreeOnRemoveNode( DiffgramParentOperation diffParent, XmlDiffNode sourceNode ) { bool bShrankNode = sourceNode is XmlDiffShrankNode; if ( sourceNode._bSomeDescendantMatches && !bShrankNode ) { DiffgramOperation removeOp = GenerateDiffgramRemoveWhenDescendantMatches( (XmlDiffParentNode)sourceNode ); diffParent.InsertAtEnd( removeOp ); } else { ulong opid = 0; // shrank node -> output as 'move' operation if ( bShrankNode ) { XmlDiffShrankNode shrankNode = (XmlDiffShrankNode) sourceNode; if ( shrankNode.MoveOperationId == 0 ) shrankNode.MoveOperationId = GenerateOperationID( XmlDiffDescriptorType.Move ); opid = shrankNode.MoveOperationId; } if ( opid != 0 || !diffParent.MergeRemoveSubtreeAtEnd( sourceNode ) ) { diffParent.InsertAtEnd( new DiffgramRemoveSubtrees( sourceNode, opid, !_xmlDiff.IgnoreChildOrder ) ); } } }
private void GenerateAddDiffgramForAttributes( DiffgramParentOperation diffgramParent, XmlDiffElement targetElement ) { XmlDiffAttributeOrNamespace attr = targetElement._attributes; while ( attr != null ) { diffgramParent.InsertAtBeginning( new DiffgramAddNode( attr, 0 ) ); attr = (XmlDiffAttributeOrNamespace)attr._nextSibling; } }
private void WalkTreeOnMatchNode( DiffgramParentOperation diffParent, XmlDiffNode sourceNode, XmlDiffNode targetNode, ref XmlDiffNode needPositionSourceNode ) { if ( sourceNode.HasChildNodes || targetNode.HasChildNodes ) { DiffgramPosition diffMatch = new DiffgramPosition( sourceNode ); WalkTreeGenerateDiffgramMatch( diffMatch, (XmlDiffParentNode)sourceNode, (XmlDiffParentNode)targetNode ); diffParent.InsertAtEnd( diffMatch ); needPositionSourceNode = null; } else { if ( sourceNode.NodeType == XmlDiffNodeType.ShrankNode ) { needPositionSourceNode = ((XmlDiffShrankNode)sourceNode)._lastNode; } else { needPositionSourceNode = sourceNode; } } }
private void WalkTreeOnChangeNode( DiffgramParentOperation diffParent, XmlDiffNode sourceNode, XmlDiffNode targetNode, XmlDiffOperation op ) { Debug.Assert( sourceNode.NodeType != XmlDiffNodeType.Element && targetNode.NodeType != XmlDiffNodeType.Element ); DiffgramChangeNode changeOp = new DiffgramChangeNode( sourceNode, targetNode, op, 0 ); if ( sourceNode.HasChildNodes || targetNode.HasChildNodes ) { WalkTreeGenerateDiffgramMatch( changeOp, (XmlDiffParentNode) sourceNode, (XmlDiffParentNode) targetNode ); } diffParent.InsertAtEnd( changeOp ); }
private void WalkTreeOnChangeElement( DiffgramParentOperation diffParent, XmlDiffElement sourceElement, XmlDiffElement targetElement, XmlDiffOperation op ) { DiffgramParentOperation diffOp; if ( XmlDiff.IsChangeOperationOnAttributesOnly( op ) ) { diffOp = new DiffgramPosition( sourceElement ); } else { ulong opid = 0; if ( !_xmlDiff.IgnoreNamespaces && sourceElement.LocalName == targetElement.LocalName) { opid = GetNamespaceChangeOpid( sourceElement.NamespaceURI, sourceElement.Prefix, targetElement.NamespaceURI, targetElement.Prefix ); } Debug.Assert( (int)op >= (int)XmlDiffOperation.ChangeElementName && (int)op <= (int)XmlDiffOperation.ChangeElementNameAndAttr3 ); diffOp = new DiffgramChangeNode( sourceElement, targetElement, XmlDiffOperation.ChangeElementName, opid ); } GenerateChangeDiffgramForAttributes( diffOp, sourceElement, targetElement ); if ( sourceElement.HasChildNodes || targetElement.HasChildNodes ) { WalkTreeGenerateDiffgramMatch( diffOp, sourceElement, targetElement ); } diffParent.InsertAtEnd( diffOp ); }
private void WalkTreeOnAddNode( DiffgramParentOperation diffParent, XmlDiffNode targetNode, XmlDiffNode sourcePositionNode ) { bool bShrankNode = targetNode is XmlDiffShrankNode; if ( _bChildOrderSignificant ) { if ( sourcePositionNode != null ) { diffParent.InsertAtEnd( new DiffgramPosition( sourcePositionNode ) ); } } else { if ( diffParent._firstChildOp == null && diffParent is Diffgram ) { diffParent.InsertAtEnd( new DiffgramPosition( sourcePositionNode ) ); } } if ( targetNode._bSomeDescendantMatches && !bShrankNode ) { DiffgramOperation addOp = GenerateDiffgramAddWhenDescendantMatches( (XmlDiffParentNode)targetNode ); diffParent.InsertAtEnd( addOp ); } else { // shrank node -> output as 'move' operation if ( bShrankNode ) { ulong opid = 0; XmlDiffShrankNode shrankNode = (XmlDiffShrankNode) targetNode; if ( shrankNode.MoveOperationId == 0 ) shrankNode.MoveOperationId = GenerateOperationID( XmlDiffDescriptorType.Move ); opid = shrankNode.MoveOperationId; diffParent.InsertAtEnd( new DiffgramCopy( shrankNode.MatchingShrankNode, true, opid ) ); } else { switch ( targetNode.NodeType ) { case XmlDiffNodeType.XmlDeclaration: case XmlDiffNodeType.DocumentType: case XmlDiffNodeType.EntityReference: diffParent.InsertAtEnd( new DiffgramAddNode( targetNode, 0 ) ); break; default: if ( !diffParent.MergeAddSubtreeAtEnd( targetNode ) ) { diffParent.InsertAtEnd( new DiffgramAddSubtrees( targetNode, 0, !_xmlDiff.IgnoreChildOrder ) ); } break; } } } }
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; } } } }