6

所以假设我想比较两个 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 结构,还要测试内容。

有任何想法吗?

4

6 回答 6

4

这似乎解决了这个问题:

https://phpunit.de/manual/current/en/appendixes.assertions.html#appendixes.assertions.assertXmlStringEqualsXmlString

于 2012-04-26T09:26:30.153 回答
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 中的空格并不重要,并且可能存在一些用例,其中该假设是不正确的......

于 2012-04-25T16:53:25.580 回答
1

我建议您将 XML 转换为DOMDocuments然后assertEquals与它们一起使用。PHPUnit 已经支持它 - 但是它可能无法满足您的所有需求。

您也可以重新格式化文档并重新加载它们,请参阅PHP XML 如何输出漂亮的格式

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

另一个想法是按孩子的标记名对孩子进行排序——不知道以前是否这样做过。

于 2012-04-25T16:53:41.043 回答
0

您可以使用 PHPUnit 的 assertXmlFileEqualsXmlFile()、assertXmlStringEqualsXmlFile() 和 assertXmlStringEqualsXmlString() 函数;然而,他们没有提供有什么不同的信息,他们只是让测试失败

Failed asserting that two DOM documents are equal.

因此,您可能想使用 PHP 的XMLDiff PECL 扩展,或者编写自己的递归比较函数。如果时间很重要,我建议不要使用 DOM,而是使用 SimpleXML,因为 API 更简单。

于 2014-02-07T09:02:20.700 回答
0

我一直在玩这里提出的一些概念,并认为我不妨发布我的最终结果。我想做的一件事是比较两个节点或两个文档的结果。(从技术上讲,只要将类似文档的第一个孩子与另一个孩子进行比较,这个就可以进行比较)

基本上,如果我发送 DomDocument,它会使用 $clone->loadXml($obj->saveXml) 克隆它,但如果它是发送的节点,它会执行 $clone->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));
}
于 2015-11-24T21:46:10.067 回答
0

使用以下断言:

$this->assertXmlStringEqualsXmlString($expected, $actual);
于 2019-05-29T07:23:33.883 回答