2012-04-25 31 views
6

Vì vậy, giả sử tôi muốn so sánh hai đối tượng DOMDocument. Họ có cùng nội dung nhưng thứ tự và định dạng có thể bị tắt. Ví dụ, một đầu kết quả đầu ra XML này:Làm cách nào để so sánh các XML tương tự với PHPUnit?

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


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

    </response></responses> 

khác một đầu ra:

<responses> 
<response id="12"> 

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

Như bạn thấy, chúng chứa cấu trúc XML tương tự, nhưng một số yếu tố có thể là theo thứ tự và định dạng khác nhau là hoàn toàn ngẫu nhiên.

Nếu tôi làm:

$this->assertEquals(); 

Xét nghiệm này tất nhiên sẽ thất bại. Tôi không muốn thử nghiệm cấu trúc XML mà còn là nội dung.

Bất kỳ ý tưởng nào?

+0

cách xóa tất cả các khoảng trắng và sau đó so sánh có dấu băm sha1? –

Trả lời

3
+1

Trong khi điều này về lý thuyết có thể trả lời câu hỏi, [nó sẽ là thích hợp hơn] (http://meta.stackexchange.com/q/8259) để bao gồm các phần thiết yếu của câu trả lời ở đây, và cung cấp liên kết để tham khảo. – Nanne

+1

Thật vậy, liên kết đã bị hỏng, làm cho câu trả lời này vô dụng ngày nay. – nIcO

+0

@nIcO cố định liên kết bị hỏng –

3

Phiên bản PHPUnit nào đây? Tôi khá chắc chắn các phiên bản gần đây tất cả hỗ trợ so sánh DomDocument.

Phiên bản ngắn: Sử dụng cài đặt $doc->preserveWhiteSpace để xóa khoảng trắng và sau đó sử dụng $doc->C14N() để tách nhận xét và nhận chuỗi mà bạn có thể so sánh.


OK, đây là tập lệnh bạn có thể phát, lưu ý rằng các dòng EOD; không thể có bất kỳ dấu cách hoặc khoảng trắng phía trước nào.

$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; 

// Khối tiếp theo là một phần của cùng một tệp, tôi chỉ thực hiện việc định dạng này sao cho hệ thống đánh dấu cú pháp StackOverflow không bị nghẹt thở.

$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"; 

Output với $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> 

Output với $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> 

Lưu ý rằng $doc->C14N() có thể chậm hơn, nhưng tôi nghĩ rằng có vẻ như khả năng tước ra ý kiến ​​là mong muốn. Lưu ý rằng tất cả điều này cũng giả định rằng khoảng trống trong XML của bạn không quan trọng và có thể một số trường hợp sử dụng mà giả định đó không đúng ...

1

Tôi đề nghị bạn chuyển XML thành DOMDocuments và sau đó sử dụng assertEquals với những người. Nó đã được hỗ trợ bởi PHPUnit - Tuy nhiên điều đó có thể không bao gồm tất cả các nhu cầu của bạn rồi.

Bạn có thể định dạng lại tài liệu và tái nạp cho họ là tốt, thấy PHP XML how to output nice format:

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

ý tưởng khác là để sắp xếp sau đó những đứa trẻ bởi tagname của họ - không có ý tưởng nếu điều đó đã được thực hiện trước đó.

0

Bạn có thể sử dụng assertXmlFileEqualsXmlFile PHPUnit của(), chức năng assertXmlStringEqualsXmlFile() và assertXmlStringEqualsXmlString(); nêu ra, họ không đưa ra thông tin về những gì khác nhau, họ chỉ để cho các thử nghiệm thất bại với

Failed asserting that two DOM documents are equal. 

Vì vậy, bạn có thể muốn sử dụng PHP XMLDiff PECL extension, hoặc viết chức năng so sánh đệ quy của riêng bạn. Nếu thời gian quan trọng, tôi khuyên bạn không nên sử dụng DOM nhưng SimpleXML thay vì vì API đơn giản hơn.

0

Tôi đã chơi với một số khái niệm được trình bày ở đây và tôi cũng có thể đăng kết quả cuối cùng của mình. Một trong những điều tôi muốn có thể làm là so sánh kết quả của hai nút hoặc hai tài liệu. (về mặt kỹ thuật, cái này có thể so sánh hoặc miễn là đứa con đầu tiên của một tài liệu tương tự được so sánh với một tài liệu khác)

Về cơ bản nếu tôi gửi trong DomDocument, nó sẽ sao chép nó bằng cách sử dụng $ clone-> loadXml ($ obj -> saveXml) nhưng nếu đó là một nút được gửi vào, nó thực hiện một $ clone-> importNode ($ obj); Thứ tự của if trở nên quan trọng vì DomDocument cũng là một thể hiện của 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)); 
} 
Các vấn đề liên quan