【问题标题】:Why php simplexml allow addChild in one of these examples but not the other?为什么 php simplexml 在其中一个示例中允许 addChild 而在另一个示例中不允许?
【发布时间】:2016-11-15 12:35:41
【问题描述】:

我想知道是否有人可以清楚地解释为什么这段代码不起作用:

<?php
$base = '<?xml version="1.0" encoding="UTF-8"?>' . "\n" .
    '<ns:RootNode xmlns:ns="http://www.bogus.com/bogus/">' .
    '<ns:RequestHeader/>' .
    '<ns:ContractInfo/>' .
    '</ns:RootNode>' . "\n";
$xml = simplexml_load_string($base);
$header = $xml->RequestHeader;

echo get_class($header) . "\n";

$header->addChild('SourceID', '123456');
echo $xml->asXML() . "\n\n";

...产生这个输出:

SimpleXMLElement
PHP Warning:  SimpleXMLElement::addChild(): Cannot add child. Parent is not
a permanent member of the XML tree in 
C:\yadayada\test.php on line 12

Warning: SimpleXMLElement::addChild(): Cannot add child. Parent is not a permanent member of the XML tree in 
C:\yadayada\test.php on line 12
<?xml version="1.0" encoding="UTF-8"?>
<ns:RootNode xmlns:ns="http://www.bogus.com/bogus/"><ns:RequestHeader/><ns:ContractInfo/></ns:RootNode>

...但是这段代码可以:

$base = '<?xml version="1.0" encoding="UTF-8"?>' . "\n" .
    '<ns:RootNode xmlns:ns="http://www.bogus.com/bogus/">' .
    '<ns:ContractInfo/>' .
    '</ns:RootNode>' . "\n";
$xml = simplexml_load_string($base);
$header = $xml->addChild('RequestHeader');

echo get_class($header) . "\n";

$header->addChild('SourceID', '123456');
echo $xml->asXML() . "\n\n";

...产生这个输出:

SimpleXMLElement
<?xml version="1.0" encoding="UTF-8"?>
<ns:RootNode xmlns:ns="http://www.bogus.com/bogus/"><ns:ContractInfo/><ns:RequestHeader><ns:SourceID>123456</ns:SourceID></ns:RequestHeader></ns:RootNode>

基本上我能看到的唯一区别是,在第二种情况下,我将节点添加到根元素,而在第一个示例中,我将它们添加到子元素中。

我已经阅读了 PHP.net 上的相关 SimpleXML 文档,它使用的示例更像是第二种方法,但我没有看到任何明确禁止第一种方法的内容。我还发现许多 SO 文章都在讨论类似的问题,但没有一个能够真正解释为什么我不能使用 SimpleXML 直接将子节点添加到现有节点。

我觉得奇怪的是,在这两种情况下,代码试图修改的对象都是相同的类型,SimpleXMLElement,但它们显然不共享相同的属性,因为一个允许 addChild 而另一个不允许.

在这种情况下,我已经找到了一种让我的代码工作的方法,但我真的很想了解它为什么会这样工作。


编辑:

感谢 BeetleJuice 指出 PHP 的 SimpleXML 处理器没有自动处理命名空间。 Kevin Yank 建议对代码稍作修改,使其正常工作。线

$header = $xml->RequestHeader;

变成

$header = $xml->children('http://www.bogus.com/bogus/')->RequestHeader;

问题解决了,额外的好处是子节点被添加到正确的命名空间中而无需额外的工作:

SimpleXMLElement
<?xml version="1.0" encoding="UTF-8"?>
<ns:RootNode xmlns:ns="http://www.bogus.com/bogus/"><ns:RequestHeader><ns:Source
ID>123456</ns:SourceID></ns:RequestHeader><ns:ContractInfo/></ns:RootNode>

【问题讨论】:

    标签: php namespaces simplexml xml-namespaces


    【解决方案1】:

    在您的第一个实例中,您认为 $xml-&gt;RequestHeader 指的是源中的 &lt;ns:RequestHeader/&gt; 节点,但事实并非如此。您可以使用任何假名而不改变$xml-&gt;asXML() 的输出;因此,当您尝试添加孩子时会收到警告,因为 $header 实际上不是您的 $xml 树的成员。

    在第二种情况下,您将孩子直接添加到已解析的 $xml 树中,因此您不会收到任何警告:

    $header = $xml->addChild('RequestHeader');
    

    看来,SimpleXML -&gt; 运算符并非旨在整理您的 ns: 标志。如果您将它们从 $base 中删除,您的第一个代码块将起作用

    $base = '<?xml version="1.0" encoding="UTF-8"?>' . "\n" .
        '<RootNode xmlns="http://www.bogus.com/bogus/">' .
        '<RequestHeader/>' .
        '<ContractInfo/>' .
        '</RootNode>' . "\n";
    $xml = simplexml_load_string($base);
    $header = $xml->RequestHeader;
    
    $header->addChild('SourceID', '123456');
    echo $xml->asXML() . "\n\n";
    

    这不会引发任何警告

    【讨论】:

    • 谢谢你,你说得对。我看了很久,没想到命名空间把我搞砸了。有时,您只需要第二双眼睛。 :-) 真正令人误解的部分是 get_class 将 $header 元素显示为 SimpleXMLElement,这让我相信它正在找到该元素,但无法修改它。再次感谢。
    猜你喜欢
    • 2017-01-18
    • 2014-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-14
    • 1970-01-01
    • 1970-01-01
    • 2018-06-20
    相关资源
    最近更新 更多