2012-04-25 14 views
6

Quindi supponiamo di voler confrontare due oggetti DOMDocument. Hanno lo stesso contenuto ma l'ordine e la formattazione potrebbero essere disattivati. Ad esempio, prima Risulterà XML:Come confrontare XML simili con PHPUnit?

<responses> 
    <response id="12"> 
     <foo>bar</foo> 


<lorem>ipsum</lorem> 
      <sit>dolor</sit> 

    </response></responses> 

Altre uscite uno:

<responses> 
<response id="12"> 

      <lorem>ipsum</lorem><sit>dolor</sit> 
     <foo>bar</foo> 
          </response> 
</responses> 

Come si può vedere, essi contengono la stessa struttura XML, ma alcuni elementi potrebbero essere in ordine e la formattazione diverso è completamente casuale.

Se lo faccio:

$this->assertEquals(); 

La prova sarà ovviamente sicuro. Non voglio testare solo la struttura XML ma anche i contenuti.

Qualche idea?

+0

come rimuovere tutti gli spazi bianchi e quindi confrontare gli hash sha1? –

risposta

3
+1

Sebbene ciò possa teoricamente rispondere alla domanda, [sarebbe preferibile] (http://meta.stackexchange.com/q/8259) includere qui le parti essenziali della risposta e fornire il link per riferimento. – Nanne

+1

In effetti, il collegamento è ora rotto, rendendo questa risposta inutile oggi. – nIcO

+0

@nIcO ha risolto il collegamento interrotto –

3

Quale versione di PHPUnit è questa? Sono abbastanza sicuro che le versioni recenti supportino tutti i confronti di DomDocument.

Versione corta: utilizzare l'impostazione $doc->preserveWhiteSpace per rimuovere gli spazi bianchi, quindi utilizzare $doc->C14N() per eliminare i commenti e ottenere una stringa che è possibile confrontare.


OK, ecco uno script si può giocare con, notare che le linee EOD; non possono avere alcuna finale o spazi bianchi.

$x1 = <<<EOD 
<responses> 
    <response id="12"> 
     <foo>bar</foo> 

<lorem>ipsum</lorem> 
      <sit>dolor</sit> 
     <!--This is a comment --> 

    </response></responses> 
EOD; 

$x2 = <<<EOD 
<responses> 
<response id="12"> 

      <lorem>ipsum</lorem><sit>dolor</sit> 
     <foo>bar</foo> 
     <!--This is another comment --> 
          </response> 
</responses> 
EOD; 

// Il blocco successivo è parte dello stesso file, sto solo facendo questa formattazione-break in modo che il sistema di evidenziazione della sintassi StackOverflow non soffocare.

$USE_C14N = true; // Try false, just to see the difference. 

$d1 = new DOMDocument(1.0); 
$d2 = new DOMDocument(1.0); 

$d1->preserveWhiteSpace = false; 
$d2->preserveWhiteSpace = false; 

$d1->formatOutput = false; // Only useful for "pretty" output with saveXML() 
$d2->formatOutput = false; // Only useful for "pretty" output with saveXML() 

$d1->loadXML($x1); // Must be done AFTER preserveWhiteSpace and formatOutput are set 
$d2->loadXML($x2); // Must be done AFTER preserveWhiteSpace and formatOutput are set 

if($USE_C14N){ 
    $s1 = $d1->C14N(true, false); 
    $s2 = $d2->C14N(true, false); 
} else { 
    $s1 = $d1->saveXML(); 
    $s2 = $d2->saveXML(); 
} 

echo $s1 . "\n"; 
echo $s2 . "\n"; 

Uscita con $USE_C14N=true;

<responses><response id="12"><foo>bar</foo><lorem>ipsum</lorem><sit>dolor</sit></response></responses> 
<responses><response id="12"><lorem>ipsum</lorem><sit>dolor</sit><foo>bar</foo></response></responses> 

Uscita con $USE_C14N=false;

<?xml version="1.0"?> 
<responses><response id="12"><foo>bar</foo><lorem>ipsum</lorem><sit>dolor</sit><!--This is a comment --></response></responses> 

<?xml version="1.0"?> 
<responses><response id="12"><lorem>ipsum</lorem><sit>dolor</sit><foo>bar</foo><!--This is another comment --></response></responses> 

noti che $doc->C14N() potrebbe essere più lento, ma penso sembra probabile che escludendo commenti è auspicabile. Nota che tutto questo presuppone anche che gli spazi bianchi nel tuo XML non siano importanti, e probabilmente ci sono alcuni casi d'uso in cui tale ipotesi non è giusta ...

1

Ti suggerisco di trasformare l'XML in DOMDocuments e poi usare assertEquals con quelli. È già supportato da PHPUnit, tuttavia potrebbe non essere già in grado di soddisfare tutte le tue esigenze.

È possibile riformattare i documenti e li ri-caricare pure, vedi PHP XML how to output nice format:

$doc->preserveWhiteSpace = false; 
$doc->formatOutput = true; 

Un'altra idea è quella di ordinare poi i bambini con la loro tagname - idea se che è stato fatto prima.

0

È possibile utilizzare di PHPUnit assertXmlFileEqualsXmlFile(), assertXmlStringEqualsXmlFile() e assertXmlStringEqualsXmlString() funzioni; tuttavia, non danno informazioni su ciò che è diverso, hanno lasciato solo il test non riuscire con

Failed asserting that two DOM documents are equal. 

Così si potrebbe desiderare di utilizzare PHP di XMLDiff PECL extension, o lascia la tua funzione di confronto ricorsiva. Se il tempo conta, ti consiglio di non usare DOM ma SimpleXML invece per via dell'API più semplice.

0

Ho giocato con alcune delle nozioni presentate qui e ho pensato che avrei potuto anche pubblicare il mio risultato finale. Una delle cose che volevo essere in grado di fare era confrontare i risultati di due nodi o due documenti. (tecnicamente, questo può essere comparato fino a quando il primo figlio di un documento simile viene confrontato con un altro)

Fondamentalmente se invio un DomDocument, lo clona usando un $ clone-> loadXml ($ obj -> saveXml) ma se è inviato un nodo, esegue $ clone-> importNode ($ obj); L'ordine dei if diventa importante perché DomDocument è anche un'istanza di DomNode.

/** 
* @param \DOMDocument|\DOMNode $n1 
* @param \DOMDocument|\DOMNode $n2 
* @return bool 
* @throws \Exception for invalid data 
*/ 
function compareNode($n1, $n2) 
{ 
    $nd1 = new \DOMDocument('1.0', "UTF-8"); 
    if ($n1 instanceof \DOMDocument) { 
     $nd1 = $n1->cloneNode(true); 
     $nd1->preserveWhiteSpace = false; 
     $nd1->formatOutput = false; 
     $nd1->loadXML($n1->saveXML()); 
    } elseif ($n1 instanceof \DOMNode) { 
     $nd1->preserveWhiteSpace = false; 
     $nd1->formatOutput = false; 
     $nd1->importNode($n1); 
    } else { 
     throw new \Exception(__METHOD__ . " node 1 is invalid"); 
    } 

    $nd2 = new \DOMDocument('1.0', "UTF-8"); 
    if ($n2 instanceof \DOMDocument) { 
     $nd2 = $n2->cloneNode(true); 
     $nd2->preserveWhiteSpace = false; 
     $nd2->formatOutput = false; 
     $nd2->loadXML($n2->saveXML()); 
    } elseif ($n1 instanceof \DOMNode) { 
     $nd2->preserveWhiteSpace = false; 
     $nd2->formatOutput = false; 
     $nd2->importNode($n2); 
    } else { 
     throw new \Exception(__METHOD__ . " node 2 is invalid"); 
    } 

    return ($nd1->C14N(true, false) == $nd2->C14N(true, false)); 
}