// 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 DiffgramOperation GenerateDiffgramAddWhenDescendantMatches( XmlDiffNode targetParent ) { Debug.Assert( targetParent.HasChildNodes ); Debug.Assert( targetParent._bSomeDescendantMatches ); Debug.Assert( targetParent.NodeType != XmlDiffNodeType.ShrankNode ); DiffgramParentOperation diffOp = new DiffgramAddNode( targetParent, 0 ); if ( targetParent.NodeType == XmlDiffNodeType.Element ) { XmlDiffAttributeOrNamespace attr = ((XmlDiffElement)targetParent)._attributes; while ( attr != null ) { diffOp.InsertAtEnd( new DiffgramAddNode( attr, 0 ) ); attr = (XmlDiffAttributeOrNamespace) attr._nextSibling; } } XmlDiffNode child = ((XmlDiffParentNode)targetParent)._firstChildNode; while ( child != null ) { if ( child.NodeType == XmlDiffNodeType.ShrankNode ) { XmlDiffShrankNode shrankNode = (XmlDiffShrankNode) child; if ( shrankNode.MoveOperationId == 0 ) shrankNode.MoveOperationId = GenerateOperationID( XmlDiffDescriptorType.Move ); diffOp.InsertAtEnd( new DiffgramCopy( shrankNode.MatchingShrankNode, true, shrankNode.MoveOperationId ) ); } else if ( child.HasChildNodes && child._bSomeDescendantMatches ) { diffOp.InsertAtEnd( GenerateDiffgramAddWhenDescendantMatches( (XmlDiffParentNode)child ) ); } else { if ( !diffOp.MergeAddSubtreeAtEnd( child ) ) diffOp.InsertAtEnd( new DiffgramAddSubtrees( child, 0, !_xmlDiff.IgnoreChildOrder ) ); } child = child._nextSibling; } return diffOp; }