cref - remarks c#
¿Cómo compararía dos documentos XML? (11)
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 esto:
- El primer documento es la fuente , por ejemplo, cómo quiero que se vea el documento XML. Por lo tanto, el segundo es en el que quiero encontrar diferencias y no debe contener nodos adicionales que no estén en el primer documento.
- Debe arrojar una excepción cuando se encuentran demasiadas diferencias significativas, y debe ser fácilmente comprensible cuando un humano 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
yxmlns:xsi
, aunque me gustaría poder transmitir cuáles son. - Los prefijos de los espacios de nombres deben coincidir tanto en atributos como en elementos.
- El espacio en blanco entre elementos es irrelevante.
- Los elementos tendrán elementos secundarios o
InnerText
, pero no ambos.
Mientras estoy eliminando algo: ¿ alguien ha escrito ese 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 el objetivo se vea, sino arrojo una excepción.
Basado @Two Cents responde y usa este enlace XMLSorting he creado mi propio XmlComparer
Compare el programa 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 XML de ordenación
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;
}
}
}
}
Comparar 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 eso no me importaba), y eliminé los atributos que no quería comparar, y luego utilicé XML::Diff o XML::SemanticDiff perl module, o bien imprimió cada documento con cada elemento y atributo en una línea separada, y usando la línea de comandos Unix diff en los resultados.
Escribí esta hoja de comparación basada en XSLT 1.0 que compara b.xml con la entrada xml y genera diferencias de elementos en la entrada que no están en b.xml.
Este código no satisface todos sus requisitos, pero es simple y lo 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;
}
Estoy usando ExamXML para comparar archivos XML. Puedes probarlo. Los autores, A7Soft, también proporcionan API para comparar archivos XML
Hoy busqué en Google una lista más completa de soluciones para este problema, voy a probar una de ellas pronto:
- XMLUnit
- http://msdn.microsoft.com/en-us/library/aa302294.aspx
- http://jolt.codeplex.com/wikipage?title=Jolt.Testing.Assertions.XML.Adaptors
- http://www.codethinked.com/checking-xml-for-semantic-equivalence-in-c
- https://vkreynin.wordpress.com/tag/xml/
- http://gandrusz.blogspot.com/2008/07/recently-i-have-run-into-usual-problem.html
- http://xmlspecificationcompare.codeplex.com/
- https://github.com/netbike/netbike.xmlunit
Microsoft tiene una API XML diff que puede usar
No es relevante para el OP, ya que actualmente ignora el orden secundario, pero si desea una solución de solo código, puede probar http://xmlspecificationcompare.codeplex.com/ que de alguna manera desarrollé erróneamente .
Otra forma de hacerlo sería:
- Obtenga el contenido de ambos archivos en dos cadenas diferentes.
- Transforme 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.
- Ahora, simplemente compara las dos cuerdas entre sí.
Esto no le dará la ubicación exacta de la diferencia, pero si solo desea saber si existe alguna diferencia, es fácil hacerlo sin bibliotecas de terceros.
prueba XMLUnit . Esta biblioteca está disponible para Java y .Net
https://github.com/CameronWills/FatAntelope Otra biblioteca alternativa a la API Microsoft XML Diff. Tiene un algoritmo de diferenciación XML para hacer una comparación desordenada de dos documentos XML y producir una coincidencia óptima.
Es un puerto C # del algoritmo X-Diff que se describe aquí: http://pages.cs.wisc.edu/~yuanwang/xdiff.html
Descargo de responsabilidad : lo escribí :)