PHP DOMDocument在错误的元素上生成命名空间声明


PHP DOMDocument generates namespace declarations on wrong elements

以下是我使用的PHP代码http://pastebin.com/7FBysx2X

$doc = new DOMDocument('1.0', 'UTF-8');
$xns = 'http://www.w3.org/2000/xmlns/';
$mns = 'http://example.com/aBc/2/';
$ons = 'http://example.com/test/2005/something';
$ns =  'http://example.com/main/';
$firstChild = $doc->createElement('firstChild');
$firstChild->setAttributeNS($xns, 'xmlns:cns1', $mns);
$firstChild->setAttributeNS($xns, 'xmlns:i', $ons);
$elements = $doc->createElementNS($mns, 'cns1:elements');
for($i = 0; $i < 3; $i++) {
    $e = $doc->createElementNS($mns, 'cns1:element');
    for($k = 0; $k < 2; $k++) {
        $r = rand(100, 999);
        $value = round(($r*rand(1,9))/rand(1,9), 2);
        $ce = $doc->createElementNS($mns, "cns1:elementValue$r", $value);
        $e->appendChild($ce);
    }
    $elements->appendChild($e);
}
$firstChild->appendChild($elements);
$otherTag = $doc->createElementNS($mns, 'cns1:otherTag', 'some_value');
$emptyTag = $doc->createElementNS($mns, 'cns1:emptyTag');
$emptyTag->setAttributeNS($ons, 'i:nil', 'true');
$firstChild->appendChild($otherTag);
$firstChild->appendChild($emptyTag);
$main = $doc->createElementNS($ns, 'main');
$main->appendChild($firstChild);
$doc->appendChild($main);

header('Content-Type: text/xml');
echo $doc->saveXML();

上面的代码生成如下的XML:

<?xml version="1.0" encoding="UTF-8"?>
<main xmlns:cns1="http://example.com/aBc/2/" xmlns:i="http://example.com/test/2005/something" xmlns="http://example.com/main/">
  <firstChild xmlns:cns1="http://example.com/aBc/2/" xmlns:i="http://example.com/test/2005/something">
    <cns1:elements>
      <cns1:element>
        <cns1:elementValue303>101</cns1:elementValue303>
        <cns1:elementValue608>304</cns1:elementValue608>
      </cns1:element>
      <cns1:element>
        <cns1:elementValue735>147</cns1:elementValue735>
        <cns1:elementValue901>4505</cns1:elementValue901>
      </cns1:element>
    </cns1:elements>
    <cns1:otherTag>some_value</cns1:otherTag>
    <cns1:emptyTag i:nil="true"/>
  </firstChild>
</main>

文件应如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<main xmlns="http://example.com/main/">
  <firstChild xmlns:cns1="http://example.com/aBc/2/" xmlns:i="http://example.com/test/2005/something">
    <cns1:elements>
      <cns1:element>
        <cns1:elementValue303>101</cns1:elementValue303>
        <cns1:elementValue608>304</cns1:elementValue608>
      </cns1:element>
      <cns1:element>
        <cns1:elementValue735>147</cns1:elementValue735>
        <cns1:elementValue901>4505</cns1:elementValue901>
      </cns1:element>
    </cns1:elements>
    <cns1:otherTag>some_value</cns1:otherTag>
    <cns1:emptyTag i:nil="true"/>
  </firstChild>
</main>

问题出现在<main>标签上。为什么它有cns1i命名空间声明?它们应该仅在firstChild元素处。我需要改变什么才能获得所需的结构?

这是由于向尚未添加到文档中的节点添加子节点造成的。

将代码更改为:

$doc = new DOMDocument('1.0', 'UTF-8');
$doc->formatOutput = true;
$xns = 'http://www.w3.org/2000/xmlns/';
$mns = 'http://example.com/aBc/2/';
$ons = 'http://example.com/test/2005/something';
$ns =  'http://example.com/main/';
$main = $doc->createElementNS($ns, 'main');
$doc->appendChild($main);
$firstChild = $doc->createElement('firstChild');
$firstChild->setAttributeNS($xns, 'xmlns:cns1', $mns);
$firstChild->setAttributeNS($xns, 'xmlns:i', $ons);
$doc->getElementsByTagName('main')->item(0)->appendChild($firstChild);
$elements = $doc->createElementNS($mns, 'cns1:elements');
$doc->getElementsByTagName('firstChild')->item(0)->appendChild($elements);
for($i = 0; $i < 3; $i++) {
    $e = $doc->createElementNS($mns, 'cns1:element');
    $doc->getElementsByTagName('elements')->item(0)->appendChild($e);
    for($k = 0; $k < 2; $k++) {
        $r = rand(100, 999);
        $value = round(($r*rand(1,9))/rand(1,9), 2);
        $ce = $doc->createElementNS($mns, "cns1:elementValue$r", $value);
        $doc->getElementsByTagName('element')->item($i)->appendChild($ce);
    }
}
$otherTag = $doc->createElementNS($mns, 'cns1:otherTag', 'some_value');
$emptyTag = $doc->createElementNS($mns, 'cns1:emptyTag');
$emptyTag->setAttributeNS($ons, 'i:nil', 'true');
$doc->getElementsByTagName('firstChild')->item(0)->appendChild($otherTag);
$doc->getElementsByTagName('firstChild')->item(0)->appendChild($emptyTag);

echo $doc->saveXML();

生成与您期望的完全相同的XML。也许还有更"漂亮"或"合适"的方法可以做到这一点,但可以肯定的是,这一方法正在发挥作用。