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

时间:2014-09-18 11:39:10

标签: php xml

这是我在http://pastebin.com/7FBysx2X

中使用的PHP代码
$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元素处。我需要改变什么来获得所需的结构?

1 个答案:

答案 0 :(得分:1)

这是通过将子节点添加到尚未添加到文档的节点引起的。

将代码更改为:

$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。也许还有更多漂亮的&#39;或者&#39;适当的&#39;这样做的方法,但可以肯定的是这个。