Comparação XML de quatro vias em c #

5

Eu tenho 4 arquivos XML: A, B, C e D. Eu quero saber se a diferença entre A e B é a mesma diferença entre C e D.

Os arquivos XML são serializações do mesmo objeto .NET; Uma das principais diferenças será em uma lista específica que descreve os recursos disponíveis em um produto específico. (Uma descrição do recurso é em si outro objeto).

Todos os quatro têm estruturas muito semelhantes, mas pode haver valores presentes em um que não estão presentes em outro, e alguns valores podem ser alterados. Por exemplo, se considerarmos o documento A :

<xmldoc>
   <a></a>
   <c></c>
   <d></d>
<xmldoc>

Documento B :

<xmldoc>
   <a></a>
   <b></b> -- Added 
   <c></c> -- C and D are still ordered in the same way (except for the addition of <b>
   <d></d>
   <e></e> -- Also added, but it doesn't affect the sort of the other ones
<xmldoc>

Agora, suponha que eu tenha os seguintes documentos. O documento C é exatamente idêntico ao documento A :

<xmldoc>
   <a></a>
   <c></c>
   <d></d>
<xmldoc>

O documento D é idêntico ao documento B .

Como a diferença entre C e D é exatamente igual à diferença entre A e B , isso deve passar. No entanto, suponha que, em vez disso, tenhamos o documento D da seguinte forma:

<xmldoc>
   <a></a>
   <b></b> 
   <f></f> <!-- Added -->
   <c></c>
   <d></d>
   <e></e>
   <f></f>
<xmldoc>

A diferença entre C e D não é mais a mesma que a diferença entre A e B .

Tenho certeza de que não teremos um caso em que o documento A apareça como:

<xmldoc>
   <c></c>
   <a></a> -- This is the same as the original document A except that this was reordered - this shouldn't happen
   <d></d>
<xmldoc>

Meu primeiro pensamento foi usar a biblioteca XML Diff Patch da Microsoft, que compara dois arquivos e gera um DiffGram, que é um documento XML que descreve a diferença entre os dois arquivos que estão sendo comparados. Meu pensamento é que eu poderia comparar A para B para obter DiffGram X e C para D para obter DiffGram Y, e então fazer uma terceira comparação XML entre X e Y.

A ideia parece boa no papel; infelizmente não está se tornando tão simples. A diferença entre A e B é muito semelhante à diferença entre C e D, mas X e Y não se parecem em nada.

O problema é que ele dá DiffGrams como segue:

<xd:node match="4">
           <xd:node match="2">
              <xd:node match="1">
                 <xd:remove match="1-3" />
              </xd:node>
           </xd:node>

           <xd:node match="1">
              <xd:node match="1">
                 <xd:remove match="1-3" />
              </xd:node>
           </xd:node>
        </xd:node>

Isso tem dois problemas: primeiro, é extremamente enigmático - eu preferiria que fosse mais legível, mas não é o fim do mundo, se não for esse o caso (já que meu principal objetivo é programático aqui). Em segundo lugar (e muito mais criticamente), parece que isso é muito strongmente acoplado aos arquivos XML específicos que estão na essa comparação em particular .

Originalmente postei no Software Recommendation Stack Exchange pedindo recomendações para uma biblioteca .NET (de preferência disponível como pacote NuGet) que seria adequada para essa finalidade, mas que não teve muita sorte em receber uma recomendação. (Divulgação completa: ainda não deletei essa pergunta, mas pretendo fazê-lo em breve). Se tal biblioteca existe, eu não fui capaz de encontrá-lo (muitos deles parecem que não são projetados para o propósito que eu quero usá-los e / ou não são escritos para o framework .NET), mas se alguém estiver ciente de tal biblioteca que definitivamente seria uma solução aceitável também (no fafct, eu preferiria strongmente que tivesse que implementá-la eu mesmo).

Alguém fez algo assim com sucesso (seja criando sua própria solução, usando a biblioteca XML Diff da Microsoft ou usando outra biblioteca de terceiros)? Se sim, o que você fez?

Espero que esta não seja uma questão muito ampla (se é assim, deixe-me saber e eu vou editar), mas qual seria uma boa abordagem para isso se eu acabasse escrevendo isso sozinho?

    
por EJoshuaS 10.11.2016 / 18:04
fonte

3 respostas

3

My thought is that I could compare A to B to get DiffGram X and C to D to get DiffGram Y, and then do a third XML comparison between X and Y.

Isso parece ser um bom começo. Eu acho que o que está faltando aqui é algo como um programa ou script xslt para transformar "DiffGram X" para uma representação legível X '. Então você pode aplicar a mesma transformação ao Diffgram Y, levando a um Y 'legível. Comparando X 'e Y', você obtém um DiffGram Z final, que pode ser transformado em um Z 'legível.

Como este script ou programa irá parecer, provavelmente depende do tipo de suposições que você pode fazer sobre a estrutura dos arquivos de entrada. Eles realmente consistem em árvores XML aninhadas arbitrárias? Você precisa comparar atributos, nomes de elementos de diferenças de espaço e textos de elementos também? Eu ficaria surpreso se alguém não puder usar esse conhecimento para simplificar os DiffGrams.

    
por 10.11.2016 / 22:10
fonte
2

Apenas uma resposta ampla. Existe uma recomendação denominada XML Information Set:

link

Eu diria que a maneira mais precisa de calcular a diferença (ou "delta") entre dois documentos XML, e depois comparar essas diferenças, será depois de usar qualquer API / componente (fora da caixa, aumentada ou personalizado) suporta os construtos definidos nessa recomendação com mais fidelidade.

'HTH,

    
por 10.11.2016 / 22:58
fonte
1

A representação DiffGram de alterações não funciona bem para esta situação. É bom para corrigir arquivos, mas não para este tipo de aplicativo. O uso do DeltaXML oferece uma representação mais útil das diferenças entre seus documentos A e B:

<xmldoc deltaxml:deltaV2="A!=B" deltaxml:version="2.0" deltaxml:content-type="full-context" xmlns:deltaxml="http://www.deltaxml.com/ns/well-formed-delta-v1">
 <a deltaxml:deltaV2="A=B" />
 <b deltaxml:deltaV2="B" />
 <c deltaxml:deltaV2="A=B" />
 <d deltaxml:deltaV2="A=B" />
 <e deltaxml:deltaV2="B" />
</xmldoc>

Em seguida, você obteria algo muito semelhante para sua segunda comparação, C a D, onde C é como A, mas D tem um elemento adicionado (observe que chamamos A e B aqui para obtermos um resultado mais próximo do primeiro resultado como podemos):

<xmldoc deltaxml:deltaV2="A!=B" deltaxml:version="2.0" deltaxml:content-type="full-context" xmlns:deltaxml="http://www.deltaxml.com/ns/well-formed-delta-v1">
 <a deltaxml:deltaV2="A=B" />
 <b deltaxml:deltaV2="B" />
 <f deltaxml:deltaV2="B" />
 <c deltaxml:deltaV2="A=B" />
 <d deltaxml:deltaV2="A=B" />
 <e deltaxml:deltaV2="B" />
</xmldoc>

Esta é uma comparação bidirecional básica - disponível para .NET. Como você pode ver, você pode comparar esses dois resultados e obter um diff útil (algumas mudanças no namespace precisariam ser feitas para que os arquivos delta fossem tratados como arquivos regulares).

Também é possível usar a mesclagem de XML (embora seja apenas Java) para ir um estágio melhor e mostrar todos os três arquivos em um. Como A é o mesmo que C, podemos tratar isso como um, então queremos saber as mudanças entre A e B e entre A e D.

<xmldoc deltaxml:deltaV2="A!=B!=D" deltaxml:version="2.0" deltaxml:content-type="full-context" xmlns:deltaxml="http://www.deltaxml.com/ns/well-formed-delta-v1" xmlns:dxu="http://www.deltaxml.com/ns/unified-delta-v1">
 <a deltaxml:deltaV2="A=B=D" />
 <b deltaxml:deltaV2="B=D" />
 <f deltaxml:deltaV2="D" />
 <c deltaxml:deltaV2="A=B=D" />
 <d deltaxml:deltaV2="A=B=D" />
 <e deltaxml:deltaV2="B=D" />

Isso é provavelmente o que você precisa aqui. Você não diz qual é o seu objetivo final, talvez para fazer um estilo de edição concorrente de atualização, ou seja, mesclar as alterações feitas nos dois caminhos de edição. Como você descobriu, isso é bem difícil! Eu espero que isso ajude. Robin

    
por 15.11.2016 / 13:02
fonte