Comparar fragmentos XML e diferenças de retorno
Eu tenho uma lista de auditoria cheia de objetos serializados e gostaria de compará-los e retornar uma lista das diferenças. Por 'comparar' quero dizer que eu quero retornar onde o texto de um elemento foi alterado, ou onde um nó foi adicionado (por isso não é em Xml1, mas é em Xml2- isso não vai acontecer ao contrário)
Exemplo de xml:
<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>
Os namespaces e os nomes / casos das tags não serão alterados. Tudo o que pode mudar nesta amostra são os valores entre as tags e o número de 'CourseHotelLink' (é uma lista serializada).
O resultado final que eu gostaria é de uma lista de qual nó foi alterado - o valor antigo e o novo valor.
Qual é a melhor opção para compará-los? Eu estou usando o .net 4.0 para linq é uma opção. Eu preciso ser capaz de fazer a comparação sem necessariamente saber os nomes de todos os nós, embora eu só compare dois objetos do mesmo tipo. Eu tenho tentado usar o seguinte código, mas não consigo adaptá-lo para escolher alterações no texto, bem como nós extras.
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);
}
}
}
É provável que minhas tentativas de código estejam a milhas de distância e que haja uma maneira muito melhor de fazer, qualquer sugestão será bem-vinda!
Editado para adicionar: Acabei usando o MS Xml Diff Tool, o código a seguir produz uma grande lista de tabela html dos dois nós xml, com as diferenças destacadas em verde. Portanto, é possível (embora insano) produzir o html, depois classificá-lo para encontrar o texto 'lightgreen' (o valor destacado) e, em seguida, fazer algumas formações de strings para exibir apenas o nó filho alterado.
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();