PHP DomDocument错误 - 不在文档开头的XML声明

时间:2013-03-11 20:43:34

标签: xml domdocument php

我想用PHP DomDocument类创建站点地图。 当我尝试使用Kohana模型从数据库获取数据时它显示内容错误:

  

XML声明不在文档的开头

当我通过模型访问删除这两行时 - 一切正常,有什么问题?我需要这些数据来创建我的网址。

我正在使用此功能:

public function sitemap()
{
    $doc = new DOMDocument();
    $doc->formatOutput = true;


    $r = $doc->createElementNS("http://www.sitemaps.org/schemas/sitemap/0.9","urlset" );
    $r->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance',
            'xsi:schemaLocation',
            'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd'
            );

    $doc->appendChild( $r );

    $model = new Data_Model; // THESE TWO LINES CAUSES ERROR
    $arrayofdata = $model->get_all();

for($i=0; $i<10; $i++)
{
    $b = $doc->createElement( "url" );
    $loc = $doc->createElement("loc");
    $loc->appendChild($doc->createTextNode('www.example.com'));
    $b->appendChild( $loc );
        $priority = $doc->createElement( "priority" );
        $priority->appendChild(
                    $doc->createTextNode('1.0')
                    );
        $b->appendChild( $priority );


        $r->appendChild( $b );


        $changefreq = $doc->createElement( "changefreq" );
        $changefreq->appendChild(
                    $doc->createTextNode('Daily')
                    );
        $b->appendChild( $changefreq );

        $lastmod = $doc->createElement( "lastmod" );
        $lastmod->appendChild(
                    $doc->createTextNode(date('Y-m-d'))
                    );
    $b->appendChild( $lastmod );

    $r->appendChild( $b );
}
    $output = $doc->saveXML();
    header("Content-type:text/xml");  
    echo $output;

}

1 个答案:

答案 0 :(得分:1)

错误

  

XML声明不在文档的开头

只是意味着你在XML声明之前得到了一些输出(数据)(即<?xml version="1.0" ... ?>部分)。而是将该输出放入文档中。这是一个例子:

<?php
error_reporting(~0);
ini_set('display_errors', 1);

class Data_Model {
    public function __construct() {
        echo "I output something just because I can!\n";
    }

    public function get_all() {
        trigger_error('Yes I can trigger notices baby!', E_USER_NOTICE);
        echo "Output, I love it! Just put it out!\n";
        return array();
    }
}

$doc                     = new DOMDocument();
$doc->formatOutput       = TRUE;
$doc->preserveWhiteSpace = FALSE;

$r = $doc->createElementNS("http://www.sitemaps.org/schemas/sitemap/0.9", "urlset");
$r->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance',
    'xsi:schemaLocation',
    'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd'
);
$doc->appendChild($r);

// capture leaked output and create a <buffer> element containing the output (if any) with the
// output XML

ob_start();
$model       = new Data_Model; // THESE TWO LINES CAUSES ERROR
$arrayofdata = $model->get_all();
$buffer      = ob_get_clean();

$bufferElement = $doc->createElement('buffer');
$bufferElement->setAttribute('strlen', strlen($buffer));
$bufferElement->appendChild($doc->createCDATASection($buffer));
$bufferElement = $doc->documentElement->appendChild($bufferElement);

# ... 

// output XML
header("Content-Type: text/xml");
$doc->save('php://stdout');

正如您所看到的,它与您的代码类似。 Data_Model类的模拟只泄漏了一些数据 - 因为它可以!是啊!并触发一个通知,这就是为什么错误报告被打开并显示错误的原因(不要在生产中这样做,这是为了示例)。

以下内容基本上是您的代码,直到ob_start()行,然后使用ob_get_clean()将新的XML元素添加到out。

然后有输出。如果你仔细阅读,你会发现一些小提示,如何改进你的代码。无论如何这里是迄今为止的示例性输出:

<?xml version="1.0"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
  <buffer strlen="640"><![CDATA[I output something just because I can!

Notice: Yes I can trigger notices baby! in \home\user\test-parts.php on line 14

Call Stack:
    0.0006     147024   1. {main}() \home\user\test-parts.php:0
    0.0007     165016   2. Data_Model->get_all() \home\user\test-parts.php:36
    0.0007     165128   3. trigger_error() \home\user\test-parts.php:14

Output, I love it! Just put it out!
]]></buffer>
</urlset>

如您所见,所有输出现在都在XML文档中,而不是在它之前。错误消失了。

自己动手(或者开始排查故障,找出你的模型输出到Stdout的原因而不是。)


额外注意:当您向文档添加元素节点并且您希望稍后在文档中将子节点添加到该节点时,您需要重新分配变量:

$r = $doc->appendChild( $r );
^^^^^

否则$r仍然是添加到文档中的元素。所以你需要稍后再添加 ,这不是你想要的。有关详细说明和示例代码,请参阅DOMDocument::appendChild()