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 ); } } }
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; } } }
// 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 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 ); }