2008-10-03 12 views
52

Como parte de la clase base para algunas pruebas unitarias exhaustivas, estoy escribiendo una función auxiliar que compara recursivamente los nodos de un objeto XmlDocument con otro en C# (.NET). Algunos requisitos de la presente:¿Cómo compararía dos documentos XML?

  • El primer documento es la fuente, por ejemplo lo que quiero que sea el documento XML. Por lo tanto, el segundo es aquel en el que quiero encontrar diferencias y no debe contener nodos adicionales que no estén en el primer documento.
  • Debe lanzar una excepción cuando se encuentran demasiadas diferencias significativas, y debe ser fácilmente comprendida por un ser humano que eche un vistazo a la descripción.
  • El orden de elementos secundarios es importante, los atributos pueden estar en cualquier orden.
  • Algunos atributos son ignorables; específicamente xsi:schemaLocation y xmlns:xsi, aunque me gustaría poder decir cuáles son.
  • Los prefijos de los espacios de nombres deben coincidir tanto en atributos como en elementos.
  • El espacio en blanco entre los elementos es irrelevante.
  • Los elementos tienen elementos secundarios oInnerText, pero no ambos.

Mientras estoy desguazando algo juntos: ¿Alguien ha escrito tal código y sería posible compartirlo aquí?

Por otro lado, ¿cómo llamarías el primer y el segundo documento? Me he estado refiriendo a ellos como "fuente" y "objetivo", pero se siente mal ya que la fuente es lo que quiero que se parezca al objetivo , sino arrojo una excepción.

+0

Pueden los nodos ser el mismo, pero se declaró en un orden diferente? – alexmac

+0

No, los nodos deben estar en el mismo orden. Además de ser un requisito de los documentos, hace que la diferencia sea un poco más simple (solo enumere los niños y verifique uno a uno). –

+0

> los atributos pueden estar en cualquier orden Lo bueno es que los atributos están desordenados por definición. –

Respuesta

51

Microsoft tiene una XML diff API que puede utilizar

+1

¡Esto es genial! Desafortunadamente, lo UNICO que no hace es permitirme ignorar ciertos atributos. –

+0

Olvidé mencionar en mi publicación, una de las otras cosas que hice en el XSLT fue filtrar ciertos atributos. – runrig

+0

Otro enlace para la herramienta está aquí http://msdn.microsoft.com/en-gb/library/aa302294.aspx –

4

La comparación de documentos XML es complicado. Google para xmldiff (incluso hay una solución de Microsoft) para algunas herramientas. He resuelto esto de varias maneras. Usé XSLT para ordenar elementos y atributos (porque a veces aparecerían en un orden diferente, y no me importaba eso), y eliminé los atributos que no quería comparar, y luego utilicé el XML::Diff o el XML::SemanticDiff perl módulo, o bien imprimió cada documento con cada elemento y atributo en una línea separada, y utilizando la diferencia de línea de comandos de Unix en los resultados.

3

Estoy usando ExamXML para comparar archivos XML. Puedes probarlo. Los autores, A7Soft, también proporcionan API para comparar archivos XML

4

Otra manera de hacer esto sería -

  1. obtener el contenido de ambos archivos en dos cadenas diferentes.
  2. Transforma las cadenas usando un XSLT (que simplemente copiará todo en dos cadenas nuevas). Esto asegurará que todos los espacios fuera de los elementos se eliminen. Esto dará como resultado dos nuevas cadenas.
  3. Ahora, simplemente compare las dos cadenas entre sí.

Esto no le dará la ubicación exacta de la diferencia, pero si solo desea saber si existe alguna diferencia, esto es fácil de hacer sin bibliotecas de terceros.

+1

-1: esto no responde la pregunta. –

+2

Esto no responde a la pregunta en particular, pero el concepto es relevante para el problema planteado en la pregunta. Mi +1. – yegor256

5

prueba XMLUnit. Esta biblioteca está disponible tanto para Java como .Net

5
4

Este código no satisface todas sus necesidades, pero es sencilla y estoy usando para mis pruebas unitarias. El orden de los atributos no importa, pero el orden de los elementos sí. El texto interno del elemento no se compara. También ignoré el caso al comparar atributos, pero puede eliminarlo fácilmente.

public bool XMLCompare(XElement primary, XElement secondary) 
{ 
    if (primary.HasAttributes) { 
     if (primary.Attributes.Count != secondary.Attributes.Count) 
      return false; 
     foreach (XAttribute attr in primary.Attributes) { 
      if (secondary.Attribute(attr.Name.LocalName) == null) 
       return false; 
      if (attr.Value.ToLower != secondary.Attribute(attr.Name.LocalName).Value.ToLower) 
       return false; 
     } 
    } 
    if (primary.HasElements) { 
     if (primary.Elements.Count != secondary.Elements.Count) 
      return false; 
     for (i = 0; i <= primary.Elements.Count - 1; i++) { 
      if (XMLCompare(primary.Nodes(i), secondary.Nodes(i)) == false) 
       return false; 
     } 
    } 
    return true; 
} 
0

Basado @Two centavos respuesta y usando este enlace XMLSorting he creado mi propia XmlComparer

Comparar programa de XML

private static bool compareXML(XmlNode node, XmlNode comparenode) 
    { 

     if (node.Value != comparenode.Value) 
      return false; 

      if (node.Attributes.Count>0) 
      { 
       foreach (XmlAttribute parentnodeattribute in node.Attributes) 
       { 
        string parentattributename = parentnodeattribute.Name; 
        string parentattributevalue = parentnodeattribute.Value; 
        if (parentattributevalue != comparenode.Attributes[parentattributename].Value) 
        { 
         return false; 
        } 

       } 

      } 

      if(node.HasChildNodes) 
      { 
      sortXML(comparenode); 
      if (node.ChildNodes.Count != comparenode.ChildNodes.Count) 
       return false; 
      for(int i=0; i<node.ChildNodes.Count;i++) 
       { 

       string name = node.ChildNodes[i].LocalName; 
       if (compareXML(node.ChildNodes[i], comparenode.ChildNodes[i]) == false) 
        return false; 
       } 

      } 



     return true; 
    } 

programa de XML Ordenar

private static void sortXML(XmlNode documentElement) 
    { 
     int i = 1; 
     SortAttributes(documentElement.Attributes); 
     SortElements(documentElement); 
     foreach (XmlNode childNode in documentElement.ChildNodes) 
     { 
      sortXML(childNode); 

     } 
    } 



    private static void SortElements(XmlNode rootNode) 
    { 



      for(int j = 0; j < rootNode.ChildNodes.Count; j++) { 
       for (int i = 1; i < rootNode.ChildNodes.Count; i++) 
       { 
        if (String.Compare(rootNode.ChildNodes[i].Name, rootNode.ChildNodes[1 - 1].Name) < 0) 
        { 
         rootNode.InsertBefore(rootNode.ChildNodes[i], rootNode.ChildNodes[i - 1]); 

        } 


       } 
      } 
      // Console.WriteLine(j++); 


    } 
private static void SortAttributes(XmlAttributeCollection attribCol) 
    { 
     if (attribCol == null) 
      return; 
     bool changed = true; 
     while (changed) 
     { 
      changed = false; 
      for (int i = 1; i < attribCol.Count; i++) 
     { 
       if (String.Compare(attribCol[i].Name, attribCol[i - 1].Name) < 0) 
       { 
        //Replace 
        attribCol.InsertBefore(attribCol[i], attribCol[i - 1]); 
        changed = true; 

       } 
      } 
     } 
    } 
+0

XSLT sería una forma más rápida de ordenar xml. Además, ¿por qué no ordena los documentos en lugar de ordenar en el ciclo? –

+0

@PankajJaju sé que xslt es más rápido, pero no tengo ningún conocimiento de programación xslt, también estoy ordenando ambos documentos, estoy llamando al elemento raíz de ambos documentos como primer nodo del método compareXML 'compareXML (document1. rootnode, document2.rootnode); 'y ordenando cada nodo de ambos documentos –

Cuestiones relacionadas