2012-05-07 10 views
5

Tengo una lista de auditoría llena de objetos serializados, y me gustaría compararlos y devolver una lista de las diferencias. Con 'comparar' quiero decir que quiero regresar donde ha cambiado el texto de un elemento, o donde se ha agregado un nodo (por lo tanto, no está en Xml1, pero está en Xml2, no ocurrirá al revés)Comparación de fragmentos XML y diferencias de resultado

xml

muestra:

<HotelBookingView xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Id>119</Id> 
    <RoomId>1</RoomId> 
    <ChangeRequested>false</ChangeRequested> 
    <CourseBookings>  
    <CourseHotelLink> 
     <Id>0</Id> 
    </CourseHotelLink> 
</CourseBookings> 
</HotelBookingView> 

los espacios de nombres y los nombres/caso de las etiquetas no va a cambiar. Todo lo que puede cambiar en esta muestra son los valores entre las etiquetas y el número de 'CourseHotelLink's (es una lista serializada).

El resultado final que me gustaría es una lista de qué nodo ha cambiado: el valor anterior y el nuevo.

¿Cuál es la mejor opción para compararlos? Estoy usando .Net 4.0 así que linq es una opción. Necesito poder hacer la comparación sin conocer necesariamente los nombres de todos los nodos, aunque solo compararé dos objetos del mismo tipo. He estado tratando de usar el siguiente código, pero no puedo adaptarlo para seleccionar cambios en el texto y nodos adicionales.

XmlDocument Xml1 = new XmlDocument(); 
XmlDocument Xml2 = new XmlDocument(); 
Xml1.LoadXml(list[1].Changes); 
Xml2.LoadXml(list[2].Changes); 
foreach (XmlNode chNode in Xml2.ChildNodes) 
{ 
    CompareLower(chNode); 
} 

protected void CompareLower(XmlNode aNode) 
{ 
    foreach (XmlNode chlNode in aNode.ChildNodes) 
    { 
     string Path = CreatePath(chlNode); 
     if (chlNode.Name == "#text") 
     { 
      //all my efforts at comparing text have failed 
      continue; 
     } 
     if (Xml1.SelectNodes(Path).Count == 0) 
     { 
      XmlNode TempNode = Xml1.ImportNode(chlNode, true); 
      //node didn't used to exist, this works- though doesn't return values 
      str = str + "New Node: " + TempNode.Name + ": " + TempNode.Value; 
     } 
     else 
     { 
      CompareLower(chlNode); 
     } 
    } 
} 

su probable mis intentos de código son millas de distancia y hay una mejor manera de hacerlo, todas las sugerencias son bienvenidas!

EDITADO para agregar: Terminé usando la herramienta MS Xml Diff Tool, el siguiente código produce una gran tabla html que enumera los dos nodos xml, con las diferencias resaltadas en verde. Entonces es posible (aunque loco) producir el html, luego ordenarlo para encontrar el texto 'lightgreen' (el valor resaltado), luego hacer algunas formaciones de cadena para mostrar solo el nodo hijo modificado.

var node1 = XElement.Parse("Xml string 1 here").CreateReader(); 
var node2 = XElement.Parse("Xml string 2 here").CreateReader(); 

MemoryStream diffgram = new MemoryStream(); 
XmlTextWriter diffgramWriter = new XmlTextWriter(new StreamWriter(diffgram)); 

XmlDiff xmlDiff = new XmlDiff(XmlDiffOptions.IgnoreChildOrder); 
xmlDiff.Algorithm = XmlDiffAlgorithm.Fast; 
xmlDiff.Compare(node1, node2,diffgramWriter); 

diffgram.Seek(0, SeekOrigin.Begin); 
XmlDiffView xmlDiffView = new Microsoft.XmlDiffPatch.XmlDiffView(); 
StringBuilder sb = new StringBuilder(); 
TextWriter resultHtml = new StringWriter(sb); 
xmlDiffView.Load("Xml string 1", new XmlTextReader(diffgram)); 

xmlDiffView.GetHtml(resultHtml); 
resultHtml.Close(); 
+1

Tome un vistazo a este post: http://stackoverflow.com/questions/167946/how-you-you-compare-two-xml-documents –

+0

Aún no he descubierto cómo obtener MS Diff y Patch para tomar cadenas XML: mi XML proviene de una base de datos y no quiero tener que crear archivos cada vez que quiero t o usarlo ... Podría ser que yo sea denso. – UglyTeapot

+0

No necesita crear archivos, viene con muchas sobrecargas para comparar archivos, XmlTextReader o XmlNode –

Respuesta

7

El uso de XMlDiff es el camino a seguir, para demostrarlo, aquí hay un código de trabajo. Estoy usando tu XML. Si el XML es diferente (o no es válido), es posible que esto no funcione.

original:

var xml1 = @"<HotelBookingView xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> 
<Id>119</Id> 
<RoomId>1</RoomId> 
<ChangeRequested>false</ChangeRequested> 
<CourseBookings>  
    <CourseHotelLink> 
    <Id>0</Id> 
    </CourseHotelLink> 
</CourseBookings> 
</HotelBookingView>"; 

diferente valor Id en CourseBookings:

var xml2 = @"<HotelBookingView xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> 
<Id>119</Id> 
<RoomId>1</RoomId> 
<ChangeRequested>false</ChangeRequested> 
<CourseBookings>  
    <CourseHotelLink> 
    <Id>1</Id> 
    </CourseHotelLink> 
</CourseBookings> 
</HotelBookingView>"; 

bajo forma de esfuerzo de crear lectores (cambiar a XDocument si es necesario):

var node1 = XElement.Parse(xml1).CreateReader(); 
var node2 = XElement.Parse(xml2).CreateReader(); 

Preparar el resultado escritor:

var result = new XDocument(); 
var writer = result.CreateWriter(); 

hacer el diff:

var diff = new Microsoft.XmlDiffPatch.XmlDiff();  
diff.Compare(node1, node2, writer); 
writer.Flush(); writer.Close(); 

result es ahora un XDocument que contiene un resumen de las diferencias:

<xd:xmldiff version="1.0" srcDocHash="14506386314386767543" options="None" fragments="no" xmlns:xd="http://schemas.microsoft.com/xmltools/2002/xmldiff"> 
    <xd:node match="1"> 
    <xd:node match="4"> 
     <xd:node match="1"> 
     <xd:node match="1"> 
      <xd:change match="1">1</xd:change> 
     </xd:node> 
     </xd:node> 
    </xd:node> 
    </xd:node> 
</xd:xmldiff> 
+0

¡Eso funciona, gracias! Así que solo necesito analizar el diffgram para que sea capaz de mostrar cosas como 'Id de CourseBookings era 0, ahora 1', ¡lo cual debería ser divertido! – UglyTeapot

+0

No olvides aceptar si responde la pregunta original :-) Hay mucha información sobre cómo interpretar el retorno de 'xmldiff'. – yamen

+0

Aceptado, ¡gracias! Y ... hay ejemplos de cómo interpretar los diffgrams para mostrar solo las diferencias? Mi débil google-fu no encuentra nada – UglyTeapot

Cuestiones relacionadas