internal static int OrderSubTrees(XmlDiffElement elem1, XmlDiffElement elem2) { var node1_1 = elem1._attributes; var node2_1 = elem2._attributes; while (node1_1 != null && node1_1.NodeType == XmlDiffNodeType.Namespace) node1_1 = (XmlDiffAttributeOrNamespace) node1_1._nextSibling; while (node2_1 != null && node2_1.NodeType == XmlDiffNodeType.Namespace) node2_1 = (XmlDiffAttributeOrNamespace) node2_1._nextSibling; for (; node1_1 != null && node2_1 != null; node2_1 = (XmlDiffAttributeOrNamespace) node2_1._nextSibling) { int num; if ((num = XmlDiffDocument.OrderAttributesOrNamespaces(node1_1, node2_1)) != 0) return num; node1_1 = (XmlDiffAttributeOrNamespace) node1_1._nextSibling; } if (node1_1 == node2_1) { var node1_2 = elem1.FirstChildNode; XmlDiffNode node2_2; for (node2_2 = elem2.FirstChildNode; node1_2 != null && node2_2 != null; node2_2 = node2_2._nextSibling) { int num; if ((num = XmlDiffDocument.OrderChildren(node1_2, node2_2)) != 0) return num; node1_2 = node1_2._nextSibling; } if (node1_2 == node2_2) return 0; return node1_2 == null ? 1 : -1; } return node1_1 == null ? 1 : -1; }
// 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(); }
// compares the node to another one and returns true, if the nodes are identical; // on elements this method ignores namespace declarations internal override bool IsSameAs(XmlDiffNode node, XmlDiff xmlDiff) { // check node type Debug.Assert(node != null); if (node.NodeType != XmlDiffNodeType.Element) { return(false); } XmlDiffElement element = (XmlDiffElement)node; // check element name if (LocalName != element.LocalName) { return(false); } else if (!xmlDiff.IgnoreNamespaces) { if (NamespaceURI != element.NamespaceURI) { return(false); } else if (!xmlDiff.IgnorePrefixes) { if (Prefix != element.Prefix) { return(false); } } } // ignore namespace definitions - should be first in the list of attributes XmlDiffAttributeOrNamespace attr1 = _attributes; while (attr1 != null && attr1.NodeType == XmlDiffNodeType.Namespace) { attr1 = (XmlDiffAttributeOrNamespace)attr1._nextSibling; } XmlDiffAttributeOrNamespace attr2 = _attributes; while (attr2 != null && attr2.NodeType == XmlDiffNodeType.Namespace) { attr2 = (XmlDiffAttributeOrNamespace)attr2._nextSibling; } // check attributes while (attr1 != null && attr2 != null) { if (!attr1.IsSameAs(attr2, xmlDiff)) { return(false); } attr1 = (XmlDiffAttributeOrNamespace)attr1._nextSibling; attr2 = (XmlDiffAttributeOrNamespace)attr2._nextSibling; } return(attr1 == null && attr2 == null); }
// compares the node to another one and returns the xmldiff operation for changing this node to the other internal override XmlDiffOperation GetDiffOperation(XmlDiffNode changedNode, XmlDiff xmlDiff) { Debug.Assert(changedNode != null); if (changedNode.NodeType != XmlDiffNodeType.Element) { return(XmlDiffOperation.Undefined); } XmlDiffElement changedElement = (XmlDiffElement)changedNode; // name bool bNameMatches = false; if (LocalName == changedElement.LocalName) { if (xmlDiff.IgnoreNamespaces) { bNameMatches = true; } else { if (NamespaceURI == changedElement.NamespaceURI && (xmlDiff.IgnorePrefixes || Prefix == changedElement.Prefix)) { bNameMatches = true; } } } // attributes if (changedElement._allAttributesHash == _allAttributesHash) { return(bNameMatches ? XmlDiffOperation.Match : XmlDiffOperation.ChangeElementName); } int n = (changedElement._attributesHashAH == _attributesHashAH ? 0 : 1) + (changedElement._attributesHashIQ == _attributesHashIQ ? 0 : 1) + (changedElement._attributesHashRZ == _attributesHashRZ ? 0 : 1); Debug.Assert((int)XmlDiffOperation.ChangeElementName + 1 == (int)XmlDiffOperation.ChangeElementAttr1); Debug.Assert((int)XmlDiffOperation.ChangeElementAttr1 + 1 == (int)XmlDiffOperation.ChangeElementAttr2); Debug.Assert((int)XmlDiffOperation.ChangeElementAttr2 + 1 == (int)XmlDiffOperation.ChangeElementAttr3); Debug.Assert((int)XmlDiffOperation.ChangeElementAttr3 + 1 == (int)XmlDiffOperation.ChangeElementNameAndAttr1); Debug.Assert((int)XmlDiffOperation.ChangeElementNameAndAttr1 + 1 == (int)XmlDiffOperation.ChangeElementNameAndAttr2); Debug.Assert((int)XmlDiffOperation.ChangeElementNameAndAttr2 + 1 == (int)XmlDiffOperation.ChangeElementNameAndAttr3); Debug.Assert(n != 0); if (bNameMatches) { return((XmlDiffOperation)(((int)XmlDiffOperation.ChangeElementName) + n)); } else { return((XmlDiffOperation)(((int)XmlDiffOperation.ChangeElementAttr3) + n)); } }
internal ulong ComputeHashXmlDiffElement(XmlDiffElement el) { var ha = new HashAlgorithm(); this.HashElement(ha, el.LocalName, el.Prefix, el.NamespaceURI); this.ComputeHashXmlDiffAttributes(ha, el); this.ComputeHashXmlDiffChildren(ha, (XmlDiffParentNode)el); return(ha.Hash); }
internal ulong ComputeHashXmlDiffElement(XmlDiffElement el) { HashAlgorithm ha = new HashAlgorithm(); HashElement(ha, el.LocalName, el.Prefix, el.NamespaceURI); ComputeHashXmlDiffAttributes(ha, el); ComputeHashXmlDiffChildren(ha, el); return(ha.Hash); }
static internal int OrderElements(XmlDiffElement elem1, XmlDiffElement elem2) { Debug.Assert(elem1 != null && elem2 != null); int nCompare; if ((nCompare = OrderStrings(elem1.LocalName, elem2.LocalName)) == 0 && (nCompare = OrderStrings(elem1.NamespaceURI, elem2.NamespaceURI)) == 0) { return(OrderSubTrees(elem1, elem2)); } return(nCompare); }
private void ComputeHashXmlDiffAttributes(HashAlgorithm ha, XmlDiffElement el) { var i = 0; ulong u = 0; for (var attributeOrNamespace = el._attributes; attributeOrNamespace != null; attributeOrNamespace = (XmlDiffAttributeOrNamespace)attributeOrNamespace._nextSibling) { u += attributeOrNamespace.HashValue; ++i; } if (i <= 0) { return; } ha.AddULong(u); ha.AddInt(i); }
private void ComputeHashXmlDiffAttributes(HashAlgorithm ha, XmlDiffElement el) { int attrCount = 0; ulong attrHashAll = 0; XmlDiffAttributeOrNamespace curAttrOrNs = el._attributes; while (curAttrOrNs != null) { attrHashAll += curAttrOrNs.HashValue; attrCount++; curAttrOrNs = (XmlDiffAttributeOrNamespace)curAttrOrNs._nextSibling; } if (attrCount > 0) { ha.AddULong(attrHashAll); ha.AddInt(attrCount); } }
static internal int OrderElements( XmlDiffElement elem1, XmlDiffElement elem2 ) { Debug.Assert( elem1 != null && elem2 != null ); int nCompare; if ( ( nCompare = OrderStrings( elem1.LocalName, elem2.LocalName ) ) == 0 && ( nCompare = OrderStrings( elem1.NamespaceURI, elem2.NamespaceURI ) ) == 0 ) { return OrderSubTrees( elem1, elem2 ); } return nCompare; }
static internal int OrderSubTrees( XmlDiffElement elem1, XmlDiffElement elem2 ) { Debug.Assert( elem1 != null && elem2 != null ); int nCompare = 0; // attributes - ignore namespace nodes XmlDiffAttributeOrNamespace curAttr1 = elem1._attributes; XmlDiffAttributeOrNamespace curAttr2 = elem2._attributes; while ( curAttr1 != null && curAttr1.NodeType == XmlDiffNodeType.Namespace ) curAttr1 = (XmlDiffAttributeOrNamespace)curAttr1._nextSibling; while ( curAttr2 != null && curAttr2.NodeType == XmlDiffNodeType.Namespace ) curAttr2 = (XmlDiffAttributeOrNamespace)curAttr2._nextSibling; while ( curAttr1 != null && curAttr2 != null ) { if ( ( nCompare = OrderAttributesOrNamespaces( curAttr1, curAttr2 ) ) != 0 ) return nCompare; curAttr1 = (XmlDiffAttributeOrNamespace)curAttr1._nextSibling; curAttr2 = (XmlDiffAttributeOrNamespace)curAttr2._nextSibling; } // children if ( curAttr1 == curAttr2 ) { XmlDiffNode curChild1 = elem1.FirstChildNode; XmlDiffNode curChild2 = elem2.FirstChildNode; while ( curChild1 != null && curChild2 != null ) { if ( ( nCompare = OrderChildren( curChild1, curChild2 ) ) != 0 ) return nCompare; curChild1 = curChild1._nextSibling; curChild2 = curChild2._nextSibling; } if ( curChild1 == curChild2 ) return 0; else if ( curChild1 == null ) return 1; //elem2 > elem1; else return -1; //elem1 > elem1; } else if ( curAttr1 == null ) return 1; //elem2 > elem1; else { return -1; //elem1 > elem1; } }
static internal int OrderSubTrees(XmlDiffElement elem1, XmlDiffElement elem2) { Debug.Assert(elem1 != null && elem2 != null); int nCompare = 0; // attributes - ignore namespace nodes XmlDiffAttributeOrNamespace curAttr1 = elem1._attributes; XmlDiffAttributeOrNamespace curAttr2 = elem2._attributes; while (curAttr1 != null && curAttr1.NodeType == XmlDiffNodeType.Namespace) { curAttr1 = (XmlDiffAttributeOrNamespace)curAttr1._nextSibling; } while (curAttr2 != null && curAttr2.NodeType == XmlDiffNodeType.Namespace) { curAttr2 = (XmlDiffAttributeOrNamespace)curAttr2._nextSibling; } while (curAttr1 != null && curAttr2 != null) { if ((nCompare = OrderAttributesOrNamespaces(curAttr1, curAttr2)) != 0) { return(nCompare); } curAttr1 = (XmlDiffAttributeOrNamespace)curAttr1._nextSibling; curAttr2 = (XmlDiffAttributeOrNamespace)curAttr2._nextSibling; } // children if (curAttr1 == curAttr2) { XmlDiffNode curChild1 = elem1.FirstChildNode; XmlDiffNode curChild2 = elem2.FirstChildNode; while (curChild1 != null && curChild2 != null) { if ((nCompare = OrderChildren(curChild1, curChild2)) != 0) { return(nCompare); } curChild1 = curChild1._nextSibling; curChild2 = curChild2._nextSibling; } if (curChild1 == curChild2) { return(0); } else if (curChild1 == null) { return(1); //elem2 > elem1; } else { return(-1); //elem1 > elem1; } } else if (curAttr1 == null) { return(1); //elem2 > elem1; } else { return(-1); //elem1 > elem1; } }
internal XmlDiffNode LoadNode(XmlNode node, ref int childPosition) { switch (node.NodeType) { case XmlNodeType.Element: XmlDiffElement elem = new XmlDiffElement(++childPosition, node.LocalName, node.Prefix, node.NamespaceURI); LoadChildNodes(elem, node); elem.ComputeHashValue(_xmlHash); return(elem); case XmlNodeType.Attribute: Debug.Assert(false, "Attributes cannot be loaded by this method."); return(null); case XmlNodeType.Text: string textValue = (_XmlDiff.IgnoreWhitespace) ? XmlDiff.NormalizeText(node.Value) : node.Value; XmlDiffCharData text = new XmlDiffCharData(++childPosition, textValue, XmlDiffNodeType.Text); text.ComputeHashValue(_xmlHash); return(text); case XmlNodeType.CDATA: XmlDiffCharData cdata = new XmlDiffCharData(++childPosition, node.Value, XmlDiffNodeType.CDATA); cdata.ComputeHashValue(_xmlHash); return(cdata); case XmlNodeType.EntityReference: XmlDiffER er = new XmlDiffER(++childPosition, node.Name); er.ComputeHashValue(_xmlHash); return(er); case XmlNodeType.Comment: ++childPosition; if (_XmlDiff.IgnoreComments) { return(null); } XmlDiffCharData comment = new XmlDiffCharData(childPosition, node.Value, XmlDiffNodeType.Comment); comment.ComputeHashValue(_xmlHash); return(comment); case XmlNodeType.ProcessingInstruction: ++childPosition; if (_XmlDiff.IgnorePI) { return(null); } XmlDiffPI pi = new XmlDiffPI(childPosition, node.Name, node.Value); pi.ComputeHashValue(_xmlHash); return(pi); case XmlNodeType.SignificantWhitespace: ++childPosition; if (_XmlDiff.IgnoreWhitespace) { return(null); } XmlDiffCharData ws = new XmlDiffCharData(childPosition, node.Value, XmlDiffNodeType.SignificantWhitespace); ws.ComputeHashValue(_xmlHash); return(ws); case XmlNodeType.XmlDeclaration: ++childPosition; if (_XmlDiff.IgnoreXmlDecl) { return(null); } XmlDiffXmlDeclaration xmlDecl = new XmlDiffXmlDeclaration(childPosition, XmlDiff.NormalizeXmlDeclaration(node.Value)); xmlDecl.ComputeHashValue(_xmlHash); return(xmlDecl); case XmlNodeType.EndElement: return(null); case XmlNodeType.DocumentType: childPosition++; if (_XmlDiff.IgnoreDtd) { return(null); } XmlDocumentType docType = (XmlDocumentType)node; XmlDiffDocumentType diffDocType = new XmlDiffDocumentType(childPosition, docType.Name, docType.PublicId, docType.SystemId, docType.InternalSubset); diffDocType.ComputeHashValue(_xmlHash); return(diffDocType); default: Debug.Assert(false); return(null); } }
// Inserts an attribute or namespace node. The new node is sorted into the other attributes/namespace nodes. private void InsertAttributeOrNamespace(XmlDiffElement element, XmlDiffAttributeOrNamespace newAttrOrNs) { element.InsertAttributeOrNamespace(newAttrOrNs); }
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, 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 GenerateAddDiffgramForAttributes( DiffgramParentOperation diffgramParent, XmlDiffElement targetElement ) { XmlDiffAttributeOrNamespace attr = targetElement._attributes; while ( attr != null ) { diffgramParent.InsertAtBeginning( new DiffgramAddNode( attr, 0 ) ); attr = (XmlDiffAttributeOrNamespace)attr._nextSibling; } }
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; } }
internal XmlDiffNode LoadNode( XmlNode node, ref int childPosition ) { switch ( node.NodeType ) { case XmlNodeType.Element: XmlDiffElement elem = new XmlDiffElement( ++childPosition, node.LocalName, node.Prefix, node.NamespaceURI ); LoadChildNodes( elem, node ); elem.ComputeHashValue( _xmlHash ); return elem; case XmlNodeType.Attribute: Debug.Assert( false, "Attributes cannot be loaded by this method." ); return null; case XmlNodeType.Text: string textValue = ( _XmlDiff.IgnoreWhitespace ) ? XmlDiff.NormalizeText( node.Value ) : node.Value; XmlDiffCharData text = new XmlDiffCharData( ++childPosition, textValue, XmlDiffNodeType.Text ); text.ComputeHashValue( _xmlHash ); return text; case XmlNodeType.CDATA: XmlDiffCharData cdata = new XmlDiffCharData( ++childPosition, node.Value, XmlDiffNodeType.CDATA ); cdata.ComputeHashValue( _xmlHash ); return cdata; case XmlNodeType.EntityReference: XmlDiffER er = new XmlDiffER( ++childPosition, node.Name ); er.ComputeHashValue( _xmlHash ); return er; case XmlNodeType.Comment: ++childPosition; if ( _XmlDiff.IgnoreComments ) return null; XmlDiffCharData comment = new XmlDiffCharData( childPosition, node.Value, XmlDiffNodeType.Comment ); comment.ComputeHashValue( _xmlHash ); return comment; case XmlNodeType.ProcessingInstruction: ++childPosition; if ( _XmlDiff.IgnorePI ) return null; XmlDiffPI pi = new XmlDiffPI( childPosition, node.Name, node.Value ); pi.ComputeHashValue( _xmlHash ); return pi; case XmlNodeType.SignificantWhitespace: ++childPosition; if ( _XmlDiff.IgnoreWhitespace ) return null; XmlDiffCharData ws = new XmlDiffCharData( childPosition, node.Value, XmlDiffNodeType.SignificantWhitespace ); ws.ComputeHashValue( _xmlHash ); return ws; case XmlNodeType.XmlDeclaration: ++childPosition; if ( _XmlDiff.IgnoreXmlDecl ) return null; XmlDiffXmlDeclaration xmlDecl = new XmlDiffXmlDeclaration( childPosition, XmlDiff.NormalizeXmlDeclaration( node.Value ) ); xmlDecl.ComputeHashValue( _xmlHash ); return xmlDecl; case XmlNodeType.EndElement: return null; case XmlNodeType.DocumentType: childPosition++; if ( _XmlDiff.IgnoreDtd ) return null; XmlDocumentType docType = (XmlDocumentType)node; XmlDiffDocumentType diffDocType = new XmlDiffDocumentType( childPosition, docType.Name, docType.PublicId, docType.SystemId, docType.InternalSubset ); diffDocType.ComputeHashValue( _xmlHash ); return diffDocType; default: Debug.Assert( false ); return null; } }
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 ); }
internal ulong ComputeHashXmlDiffElement( XmlDiffElement el ) { HashAlgorithm ha = new HashAlgorithm(); HashElement( ha, el.LocalName, el.Prefix, el.NamespaceURI ); ComputeHashXmlDiffAttributes( ha, el ); ComputeHashXmlDiffChildren( ha, el ); return ha.Hash; }
private void ComputeHashXmlDiffAttributes( HashAlgorithm ha, XmlDiffElement el ) { int attrCount = 0; ulong attrHashAll = 0; XmlDiffAttributeOrNamespace curAttrOrNs = el._attributes; while ( curAttrOrNs != null ) { attrHashAll += curAttrOrNs.HashValue; attrCount++; curAttrOrNs = (XmlDiffAttributeOrNamespace)curAttrOrNs._nextSibling; } if ( attrCount > 0 ) { ha.AddULong( attrHashAll ); ha.AddInt( attrCount ); } }
internal XmlDiffNode LoadNode(XmlNode node, ref int childPosition) { switch (node.NodeType) { case XmlNodeType.Element: var xmlDiffElement = new XmlDiffElement(++childPosition, node.LocalName, node.Prefix, node.NamespaceURI); this.LoadChildNodes((XmlDiffParentNode) xmlDiffElement, node); xmlDiffElement.ComputeHashValue(this._xmlHash); return (XmlDiffNode) xmlDiffElement; case XmlNodeType.Attribute: return (XmlDiffNode) null; case XmlNodeType.Text: var str = this._XmlDiff.IgnoreWhitespace ? XmlDiff.NormalizeText(node.Value) : node.Value; var xmlDiffCharData1 = new XmlDiffCharData(++childPosition, str, XmlDiffNodeType.Text); xmlDiffCharData1.ComputeHashValue(this._xmlHash); return (XmlDiffNode) xmlDiffCharData1; case XmlNodeType.CDATA: var xmlDiffCharData2 = new XmlDiffCharData(++childPosition, node.Value, XmlDiffNodeType.CDATA); xmlDiffCharData2.ComputeHashValue(this._xmlHash); return (XmlDiffNode) xmlDiffCharData2; case XmlNodeType.EntityReference: var xmlDiffEr = new XmlDiffER(++childPosition, node.Name); xmlDiffEr.ComputeHashValue(this._xmlHash); return (XmlDiffNode) xmlDiffEr; case XmlNodeType.ProcessingInstruction: ++childPosition; if (this._XmlDiff.IgnorePI) return (XmlDiffNode) null; var xmlDiffPi = new XmlDiffPI(childPosition, node.Name, node.Value); xmlDiffPi.ComputeHashValue(this._xmlHash); return (XmlDiffNode) xmlDiffPi; case XmlNodeType.Comment: ++childPosition; if (this._XmlDiff.IgnoreComments) return (XmlDiffNode) null; var xmlDiffCharData3 = new XmlDiffCharData(childPosition, node.Value, XmlDiffNodeType.Comment); xmlDiffCharData3.ComputeHashValue(this._xmlHash); return (XmlDiffNode) xmlDiffCharData3; case XmlNodeType.DocumentType: ++childPosition; if (this._XmlDiff.IgnoreDtd) return (XmlDiffNode) null; var xmlDocumentType = (XmlDocumentType) node; var diffDocumentType = new XmlDiffDocumentType(childPosition, xmlDocumentType.Name, xmlDocumentType.PublicId, xmlDocumentType.SystemId, xmlDocumentType.InternalSubset); diffDocumentType.ComputeHashValue(this._xmlHash); return (XmlDiffNode) diffDocumentType; case XmlNodeType.SignificantWhitespace: ++childPosition; if (this._XmlDiff.IgnoreWhitespace) return (XmlDiffNode) null; var xmlDiffCharData4 = new XmlDiffCharData(childPosition, node.Value, XmlDiffNodeType.SignificantWhitespace); xmlDiffCharData4.ComputeHashValue(this._xmlHash); return (XmlDiffNode) xmlDiffCharData4; case XmlNodeType.EndElement: return (XmlDiffNode) null; case XmlNodeType.XmlDeclaration: ++childPosition; if (this._XmlDiff.IgnoreXmlDecl) return (XmlDiffNode) null; var diffXmlDeclaration = new XmlDiffXmlDeclaration(childPosition, XmlDiff.NormalizeXmlDeclaration(node.Value)); diffXmlDeclaration.ComputeHashValue(this._xmlHash); return (XmlDiffNode) diffXmlDeclaration; default: return (XmlDiffNode) null; } }
// Inserts an attribute or namespace node. The new node is sorted into the other attributes/namespace nodes. private void InsertAttributeOrNamespace( XmlDiffElement element, XmlDiffAttributeOrNamespace newAttrOrNs ) { element.InsertAttributeOrNamespace( newAttrOrNs ); }
// returns true if the two elements have at least 50% in common (common name & attributes) private bool GoForElementChange( XmlDiffElement sourceElement, XmlDiffElement targetElement ) { int identicalAttrCount = 0; int addedAttrCount = 0; int removedAttrCount = 0; int changedAttrCount = 0; bool bNameChange; bNameChange = ( sourceElement.LocalName != targetElement.LocalName ); XmlDiffAttributeOrNamespace sourceAttr = sourceElement._attributes; XmlDiffAttributeOrNamespace targetAttr = targetElement._attributes; while ( sourceAttr != null && targetAttr != null ) { if ( sourceAttr.LocalName == targetAttr.LocalName ) { if ( ( _xmlDiff.IgnorePrefixes || _xmlDiff.IgnoreNamespaces || sourceAttr.Prefix == targetAttr.Prefix ) && ( _xmlDiff.IgnoreNamespaces || sourceAttr.NamespaceURI == targetAttr.NamespaceURI ) ) { if ( sourceAttr.Value == targetAttr.Value ) { identicalAttrCount++; } else { changedAttrCount++; } } else { changedAttrCount++; } sourceAttr = (XmlDiffAttributeOrNamespace)sourceAttr._nextSibling; targetAttr = (XmlDiffAttributeOrNamespace)targetAttr._nextSibling; } else { int compare = XmlDiffDocument.OrderAttributesOrNamespaces( sourceAttr, targetAttr ); if ( compare < 0 ) { removedAttrCount++; sourceAttr = (XmlDiffAttributeOrNamespace)sourceAttr._nextSibling; } else { addedAttrCount++; targetAttr = (XmlDiffAttributeOrNamespace)targetAttr._nextSibling; } } } while ( sourceAttr != null ) { removedAttrCount++; sourceAttr = (XmlDiffAttributeOrNamespace)sourceAttr._nextSibling; } while ( targetAttr != null ) { addedAttrCount++; targetAttr = (XmlDiffAttributeOrNamespace)targetAttr._nextSibling; } if ( bNameChange ) { // total number of changes is less than 50% if ( removedAttrCount + addedAttrCount + changedAttrCount <= identicalAttrCount ) return true; return false; } else { // only added if ( removedAttrCount + changedAttrCount == 0 ) return true; // only removed if ( addedAttrCount + changedAttrCount == 0 ) return true; // no removed or added: if ( removedAttrCount + addedAttrCount == 0 ) { return true; } // total number of changes is less than 75% - or - // no other sibling node if ( removedAttrCount + addedAttrCount + changedAttrCount <= identicalAttrCount * 3 || sourceElement._nextSibling == null ) return true; return false; } }
// Methods internal override void WriteTo(XmlWriter xmlWriter, XmlDiff xmlDiff) { xmlWriter.WriteStartElement(XmlDiff.Prefix, "add", XmlDiff.NamespaceUri); switch (_targetNode.NodeType) { case XmlDiffNodeType.Element: { xmlWriter.WriteAttributeString("type", ((int)XmlNodeType.Element).ToString()); XmlDiffElement el = _targetNode as XmlDiffElement; xmlWriter.WriteAttributeString("name", el.LocalName); if (el.NamespaceURI != string.Empty) { xmlWriter.WriteAttributeString("ns", el.NamespaceURI); } if (el.Prefix != string.Empty) { xmlWriter.WriteAttributeString("prefix", el.Prefix); } if (_operationID != 0) { xmlWriter.WriteAttributeString("opid", _operationID.ToString()); } WriteChildrenTo(xmlWriter, xmlDiff); break; } case XmlDiffNodeType.Attribute: { xmlWriter.WriteAttributeString("type", ((int)XmlNodeType.Attribute).ToString()); XmlDiffAttribute at = _targetNode as XmlDiffAttribute; xmlWriter.WriteAttributeString("name", at.LocalName); if (at.NamespaceURI != string.Empty) { xmlWriter.WriteAttributeString("ns", at.NamespaceURI); } if (at.Prefix != string.Empty) { xmlWriter.WriteAttributeString("prefix", at.Prefix); } if (_operationID != 0) { xmlWriter.WriteAttributeString("opid", _operationID.ToString()); } xmlWriter.WriteString(at.Value); break; } case XmlDiffNodeType.Namespace: { xmlWriter.WriteAttributeString("type", ((int)XmlNodeType.Attribute).ToString()); XmlDiffNamespace ns = _targetNode as XmlDiffNamespace; if (ns.Prefix != string.Empty) { xmlWriter.WriteAttributeString("prefix", "xmlns"); xmlWriter.WriteAttributeString("name", ns.Prefix); } else { xmlWriter.WriteAttributeString("name", "xmlns"); } if (_operationID != 0) { xmlWriter.WriteAttributeString("opid", _operationID.ToString()); } xmlWriter.WriteString(ns.NamespaceURI); break; } case XmlDiffNodeType.CDATA: { Debug.Assert(false, "CDATA nodes should be added with DiffgramAddSubtrees class."); xmlWriter.WriteAttributeString("type", ((int)_targetNode.NodeType).ToString()); if (_operationID != 0) { xmlWriter.WriteAttributeString("opid", _operationID.ToString()); } xmlWriter.WriteCData((_targetNode as XmlDiffCharData).Value); break; } case XmlDiffNodeType.Comment: { Debug.Assert(false, "Comment nodes should be added with DiffgramAddSubtrees class."); xmlWriter.WriteAttributeString("type", ((int)_targetNode.NodeType).ToString()); if (_operationID != 0) { xmlWriter.WriteAttributeString("opid", _operationID.ToString()); } xmlWriter.WriteComment((_targetNode as XmlDiffCharData).Value); break; } case XmlDiffNodeType.Text: { Debug.Assert(false, "Text nodes should be added with DiffgramAddSubtrees class."); xmlWriter.WriteAttributeString("type", ((int)_targetNode.NodeType).ToString()); if (_operationID != 0) { xmlWriter.WriteAttributeString("opid", _operationID.ToString()); } xmlWriter.WriteString((_targetNode as XmlDiffCharData).Value); break; } case XmlDiffNodeType.ProcessingInstruction: { Debug.Assert(false, "Processing instruction nodes should be added with DiffgramAddSubtrees class."); xmlWriter.WriteAttributeString("type", ((int)_targetNode.NodeType).ToString()); if (_operationID != 0) { xmlWriter.WriteAttributeString("opid", _operationID.ToString()); } XmlDiffPI pi = _targetNode as XmlDiffPI; xmlWriter.WriteProcessingInstruction(pi.Name, pi.Value); break; } case XmlDiffNodeType.EntityReference: { xmlWriter.WriteAttributeString("type", ((int)XmlNodeType.EntityReference).ToString()); if (_operationID != 0) { xmlWriter.WriteAttributeString("opid", _operationID.ToString()); } xmlWriter.WriteAttributeString("name", ((XmlDiffER)_targetNode).Name); break; } case XmlDiffNodeType.SignificantWhitespace: { Debug.Assert(false, "Significant whitespace nodes should be added with DiffgramAddSubtrees class."); xmlWriter.WriteAttributeString("type", ((int)_targetNode.NodeType).ToString()); if (_operationID != 0) { xmlWriter.WriteAttributeString("opid", _operationID.ToString()); } xmlWriter.WriteString(((XmlDiffCharData)_targetNode).Value); break; } case XmlDiffNodeType.XmlDeclaration: { xmlWriter.WriteAttributeString("type", ((int)XmlNodeType.XmlDeclaration).ToString()); if (_operationID != 0) { xmlWriter.WriteAttributeString("opid", _operationID.ToString()); } xmlWriter.WriteString(((XmlDiffXmlDeclaration)_targetNode).Value); break; } case XmlDiffNodeType.DocumentType: { xmlWriter.WriteAttributeString("type", ((int)XmlNodeType.DocumentType).ToString()); XmlDiffDocumentType docType = (XmlDiffDocumentType)_targetNode; if (_operationID != 0) { xmlWriter.WriteAttributeString("opid", _operationID.ToString()); } xmlWriter.WriteAttributeString("name", docType.Name); if (docType.PublicId != string.Empty) { xmlWriter.WriteAttributeString("publicId", docType.PublicId); } if (docType.SystemId != string.Empty) { xmlWriter.WriteAttributeString("systemId", docType.SystemId); } if (docType.Subset != string.Empty) { xmlWriter.WriteCData(docType.Subset); } break; } default: Debug.Assert(false); break; } xmlWriter.WriteEndElement(); }
internal static int OrderElements(XmlDiffElement elem1, XmlDiffElement elem2) { int num; return (num = XmlDiffDocument.OrderStrings(elem1.LocalName, elem2.LocalName)) == 0 && (num = XmlDiffDocument.OrderStrings(elem1.NamespaceURI, elem2.NamespaceURI)) == 0 ? XmlDiffDocument.OrderSubTrees(elem1, elem2) : num; }
// Methods internal override void WriteTo(XmlWriter xmlWriter, XmlDiff xmlDiff) { xmlWriter.WriteStartElement(XmlDiff.Prefix, "change", XmlDiff.NamespaceUri); xmlWriter.WriteAttributeString("match", _sourceNode.GetRelativeAddress()); if (_operationID != 0) { xmlWriter.WriteAttributeString("opid", _operationID.ToString()); } switch (_op) { case XmlDiffOperation.ChangeAttr: { XmlDiffAttribute sourceAttr = (XmlDiffAttribute)_sourceNode; XmlDiffAttribute targetAttr = (XmlDiffAttribute)_targetNode; if (sourceAttr.Prefix != targetAttr.Prefix && !xmlDiff.IgnorePrefixes && !xmlDiff.IgnoreNamespaces) { xmlWriter.WriteAttributeString("prefix", targetAttr.Prefix); } if (sourceAttr.NamespaceURI != targetAttr.NamespaceURI && !xmlDiff.IgnoreNamespaces) { xmlWriter.WriteAttributeString("ns", targetAttr.NamespaceURI); } xmlWriter.WriteString(targetAttr.Value); break; } case XmlDiffOperation.ChangeElementName: { XmlDiffElement sourceEl = (XmlDiffElement)_sourceNode; XmlDiffElement targetEl = (XmlDiffElement)_targetNode; if (sourceEl.LocalName != targetEl.LocalName) { xmlWriter.WriteAttributeString("name", targetEl.LocalName); } if (sourceEl.Prefix != targetEl.Prefix && !xmlDiff.IgnorePrefixes && !xmlDiff.IgnoreNamespaces) { xmlWriter.WriteAttributeString("prefix", targetEl.Prefix); } if (sourceEl.NamespaceURI != targetEl.NamespaceURI && !xmlDiff.IgnoreNamespaces) { xmlWriter.WriteAttributeString("ns", targetEl.NamespaceURI); } WriteChildrenTo(xmlWriter, xmlDiff); break; } case XmlDiffOperation.ChangePI: { XmlDiffPI sourcePi = (XmlDiffPI)_sourceNode; XmlDiffPI targetPi = (XmlDiffPI)_targetNode; if (sourcePi.Value == targetPi.Value) { Debug.Assert(sourcePi.Name != targetPi.Name); xmlWriter.WriteAttributeString("name", targetPi.Name); } else { xmlWriter.WriteProcessingInstruction(targetPi.Name, targetPi.Value); } break; } case XmlDiffOperation.ChangeCharacterData: { XmlDiffCharData chd = (XmlDiffCharData)_targetNode; switch (_targetNode.NodeType) { case XmlDiffNodeType.Text: case XmlDiffNodeType.SignificantWhitespace: xmlWriter.WriteString(chd.Value); break; case XmlDiffNodeType.Comment: xmlWriter.WriteComment(chd.Value); break; case XmlDiffNodeType.CDATA: xmlWriter.WriteCData(chd.Value); break; default: Debug.Assert(false); break; } break; } case XmlDiffOperation.ChangeER: { xmlWriter.WriteAttributeString("name", ((XmlDiffER)_targetNode).Name); break; } case XmlDiffOperation.ChangeXmlDeclaration: { xmlWriter.WriteString(((XmlDiffXmlDeclaration)_targetNode).Value); break; } case XmlDiffOperation.ChangeDTD: { XmlDiffDocumentType sourceDtd = (XmlDiffDocumentType)_sourceNode; XmlDiffDocumentType targetDtd = (XmlDiffDocumentType)_targetNode; if (sourceDtd.Name != targetDtd.Name) { xmlWriter.WriteAttributeString("name", targetDtd.Name); } if (sourceDtd.SystemId != targetDtd.SystemId) { xmlWriter.WriteAttributeString("systemId", targetDtd.SystemId); } if (sourceDtd.PublicId != targetDtd.PublicId) { xmlWriter.WriteAttributeString("publicId", targetDtd.PublicId); } if (sourceDtd.Subset != targetDtd.Subset) { xmlWriter.WriteCData(targetDtd.Subset); } break; } default: Debug.Assert(false); break; } xmlWriter.WriteEndElement(); }
// 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; }