PHP DOMDocument不能正确格式化输出

3

我目前正在处理一个网站的网站地图,并使用SimpleXML导入并对原始XML文件进行一些检查。之后,我使用simplexml_load_file("small.xml");将其转换为DOMDocument,以便更容易地精确添加和操作XML元素。以下是我正在使用的测试XML网站地图:

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:52:32-Orouke.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:53:23-castle technology.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:53:38-banana split.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:53:42-Waveney.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:55:12-pure orange.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:57:54-tau press.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:59:21-E.f.m.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:59:31-apple.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:59:45-townhouse communications.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
</urlset>

现在,这是我正在使用的测试代码进行修改的代码段:
<?php

$root = simplexml_load_file("small.xml");

$domRoot = dom_import_simplexml($root);

$dom = $domRoot->ownerDocument;

$urlElement = $dom->createElement("url");

    $locElement = $dom->createElement("loc");

        $locElement->appendChild($dom->createTextNode("www.google.co.uk"));

    $urlElement->appendChild($locElement);

    $lastmodElement = $dom->createElement("lastmod");

        $lastmodElement->appendChild($dom->createTextNode("2011-08-02"));

    $urlElement->appendChild($lastmodElement);

$domRoot->appendChild($urlElement);

$dom->formatOutput = true;
echo $dom->saveXML();

?>

主要问题在于,无论我把 $dom->formatOutput = true; 放在哪里,从SimpleXML导入的现有XML都会正确地格式化,但任何新内容都会以“一行全部”样式格式化,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:52:32-Orouke.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:53:23-castle technology.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:53:38-banana split.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:53:42-Waveney.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:55:12-pure orange.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:57:54-tau press.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:59:21-E.f.m.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:59:31-apple.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
  <url>
    <loc>http://www.companycheck.co.uk/searches/2011/08/22/23:59:45-townhouse communications.html</loc>
    <lastmod>2011-08-23</lastmod>
  </url>
<url><loc>www.google.co.uk</loc><lastmod>2011-08-02</lastmod></url></urlset>

如果有人知道为什么会出现这种情况,并且知道如何解决,我将非常感激。

出于好奇,空格是否影响了您的站点地图? - ajreal
我不确定它们是否真的会引起问题,但为了以防万一,我宁愿解决这个问题。目前我们在某些特定术语上拥有谷歌搜索排名第一的位置,我不想冒险破坏这个成果。(我知道它仍然是有效的XML,但为了避免任何解析问题,我更希望它能够正确地排版) - Tom Busby
Sitemap XML是为机器而设计的,我认为空格对Google并不重要。最好你去webmaster.stackexchange.com上问这个问题。 - ajreal
1
我现在知道问题的部分原因了。在加载文件之前,需要设置formatOutputpreserveWhiteSpace标志。问题是,我正在将预加载的SimpleXML对象转换为DOMDocument,因此它继承了该对象中保留的所有空格等内容,我只是想找出是否有可能告诉SimpleXML在加载文档时不要格式化输出或保留空格,这样一旦我转换它,就可以向DOMDocument传递“干净”的XML节点集。 - Tom Busby
3个回答

4

有一种解决方法。您可以通过先将新的xml保存为字符串,然后在设置formatOutput属性后再加载它来强制重新格式化,例如:

$strXml = $dom->saveXML();
$dom->formatOutput = true;
$dom->loadXML($strXml);
echo $dom->saveXML();

2
为了让输出的格式更加美观,您需要在加载前将preserveWhiteSpace变量设置为false,如文档所述。
示例:
$Xhtml = "<div><span></span></div>";
$doc = new DOMDocument('1.0','UTF-8');
$doc->preserveWhiteSpace = false;
$doc->formatOutput = true;
$doc->loadXML($Xhtml);
$formattedXhtml = $doc->saveXML($doc->documentElement, LIBXML_NOXMLDECL);
$expectedFormatting =<<<EOF
<div>
  <span/>
</div>
EOF;
$this->assertEquals($expectedFormatting,$formattedXhtml,"The XHTML is formatted");   

对于来到这里的访客,这是谷歌搜索的第一个答案。


0

我使用了类似Simon的代码,遇到了同样的问题。

事实证明,当你禁用错误(使用$doc->loadHTML(..., LIBXML_NOERROR)libxml_use_internal_errors(true);),它就不会再格式化了(例如:https://3v4l.org/ur76E)。

解决方案是不要禁用错误,并在PHP端抑制它们(使用@)。

虽然不太美观,但它确实有效:https://3v4l.org/BSJVu

最终的银弹函数如下:

function beautifyDoc(DOMDocument $doc): void
{
    $previousLibXmlState = libxml_use_internal_errors(false);
    $previousErrorHandler = set_error_handler(null);
    try {
        $html = $doc->saveHTML();
        $doc->preserveWhiteSpace = false;
        $doc->formatOutput = true;
        @$doc->loadHTML($html);
    } finally {
        libxml_use_internal_errors($previousLibXmlState);
        set_error_handler($previousErrorHandler);
    }
}

// usage
$doc = new DOMDocument();
// ...load html and do stuff...
beautifyDoc($doc);
echo $doc->saveHTML(); // done

(如果已经设置)它还会处理PHP错误处理程序。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接