所以我想说我要比较两个DOMDocument对象。它们具有相同的内容,但订单和格式可能会关闭。例如,第一个输出此XML:
<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>
如您所见,它们包含相同的XML结构,但某些元素的顺序可能不同,格式完全是随机的。
如果我这样做:
$this->assertEquals();
测试当然会失败。我不想只测试XML结构,还要测试内容。
有什么想法吗?
答案 0 :(得分:3)
这是哪个版本的PHPUnit?我很确定最近的版本都支持DomDocument比较。
简短版本:使用$doc->preserveWhiteSpace
设置删除空格,然后使用$doc->C14N()
删除评论并获取可比较的字符串。
好的,这是一个你可以玩的脚本,注意EOD;
行不能有任何尾随或前导空格。
$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;
//下一个块是同一个文件的一部分,我只是进行格式化中断,以便StackOverflow语法高亮系统不会阻塞。
$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";
以$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>
以$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>
请注意,$doc->C14N()
可能会更慢,但我认为可能需要删除评论。请注意,所有这些都假设XML中的空格并不重要,并且可能存在一些假设不正确的用例......
答案 1 :(得分:2)
答案 2 :(得分:1)
我建议您将XML转换为DOMDocuments
,然后使用assertEquals
。 PHPUnit已经支持它了 - 但这可能无法满足您的所有需求。
您可以重新格式化文档并重新加载它们,请参阅PHP XML how to output nice format:
$doc->preserveWhiteSpace = false;
$doc->formatOutput = true;
另一个想法是按照标记名对孩子进行排序 - 不知道以前是否已经完成过。
答案 3 :(得分:0)
您可以使用PHPUnit的assertXmlFileEqualsXmlFile(),assertXmlStringEqualsXmlFile()和assertXmlStringEqualsXmlString()函数;然而,他们没有提供有关不同之处的信息,他们只让测试失败
Failed asserting that two DOM documents are equal.
所以你可能想要使用PHP的XMLDiff PECL extension,或编写自己的递归比较函数。如果时间很重要,我建议不要使用DOM而是使用SimpleXML,因为API更简单。
答案 4 :(得分:0)
我一直在玩这里提出的一些概念,并认为我可能会发布我的最终结果。我希望能够做的一件事是比较两个节点或两个文档的结果。 (从技术上讲,这个可以比较一个或多个类似文件的第一个孩子与另一个孩子进行比较)
基本上如果我发送了一个DomDocument,它会使用$ clone-&gt; loadXml($ obj-&gt; saveXml)克隆它,但如果它是一个发送的节点,它会执行$ clone-&gt; importNode($ obj) ); if的顺序变得很重要,因为DomDocument也是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));
}
答案 5 :(得分:0)
使用以下断言:
$this->assertXmlStringEqualsXmlString($expected, $actual);