您如何访问名称空间环境中的 SimpleXML 节点?

How do you access SimpleXML nodes in a namespace environment?

如何在命名空间环境中访问 PHP SimpleXML 节点?

我想务实地在<request>下添加<param>value</param>。不只是在字符串中编辑它。

$xml = \SimpleXMLElement(
    '<?xml version="1.0" encoding="utf-8"?>' . PHP_EOL
  . '<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' . PHP_EOL
  . '  <soap:Body>' . PHP_EOL
  . '    <Function xmlns="https://webservices.sveaekonomi.se/webpay">' . PHP_EOL
  . '      <request />' . PHP_EOL
  . '    </Function>' . PHP_EOL
  . '  </soap:Body>' . PHP_EOL
  . '</soap:Envelope>'
);

我尝试了以下操作:

#1
$xml->Envelope->Body->Function->request->addChild('param', 'value');

#2
$xml->children('https://webservices.sveaekonomi.se/webpay')->request->addChild('param', 'value');

#3
$xml->registerXPathNamespace('swp', 'https://webservices.sveaekonomi.se/webpay');
$xml->xpath('/swp:request')->addChild('param', 'value');

由于您正在处理 xml 一种方法是使用 xpath 和 local-name():

$xml = '<?xml version="1.0" encoding="utf-8"?> 
  <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> 
    <soap:Body> 
      <Function xmlns="https://webservices.sveaekonomi.se/webpay"> 
        <request/>
      </Function> 
    </soap:Body> 
  </soap:Envelope>
';
$doc = new SimpleXMLElement($xml);
$destination = ($doc->xpath('//*[local-name()="request"]'));
$destination[0]->addChild('param', 'value');
echo $doc->asXML();

输出:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> 
    <soap:Body> 
      <Function xmlns="https://webservices.sveaekonomi.se/webpay"> 
        <request><param>value</param></request>
      </Function> 
    </soap:Body> 
  </soap:Envelope>

你在这里犯了一些常见的错误,所以我将逐一逐一介绍。

让我们从第一次尝试开始:

$xml->Envelope->Body->...

SimpleXML 没有单独的文档 object,只有根元素 - 在本例中为 Envelope。所以你不需要说 ->Envelope,你已经在那里了。如果不涉及名称空间,您将编写:

$xml->Body->...

但是,object 不会 自动“select”该元素的名称空间,因此您必须立即调用 ->children(),或者将你想要pre-select的命名空间传递给构造函数:

$xml->children('http://schemas.xmlsoap.org/soap/envelope/')->Body->...
// Or
$xml = new SimpleXMLElement($xmlString, 0, false, 'http://schemas.xmlsoap.org/soap/envelope/');
$xml->Body->...

考虑到这一点,我们可以:

$xml->children('http://schemas.xmlsoap.org/soap/envelope/')->Body->Function->...

这失败了,因为 FunctionBody 不在同一个命名空间中。我喜欢的思路是the ->children() method是一个“切换命名空间”的方法,所以我们切换到正确的命名空间继续:

$xml->children('http://schemas.xmlsoap.org/soap/envelope/')->Body
    ->children('https://webservices.sveaekonomi.se/webpay')->Function->request
    ->addChild('param', 'value');

这行得通!


你的第二次尝试犯了不同的错误:

$xml->children('https://webservices.sveaekonomi.se/webpay')->request->...

“children”方法不会让你跳到文档的深处——顾名思义,它给你 直接 children 的元素,而不是 grand-children,伟大的 grand-children,等等。 $xml 变量指向“信封”节点,并且没有 child 称为“请求”的节点。

没有 built-in 方法用于“任何后代”,除非使用 XPath...


虽然看起来完全不同,但你的第三次尝试实际上失败的原因是一样的:

$xml->registerXPathNamespace('swp', 'https://webservices.sveaekonomi.se/webpay');
$xml->xpath('/swp:request')->...

XPath 中的 / 运算符类似地表示“children of”; 一个“任何后代”的运算符,即//,所以你会nearly得到正确的结果:

$xml->registerXPathNamespace('swp', 'https://webservices.sveaekonomi.se/webpay');
$xml->xpath('//swp:request')->...

由于一个更微妙的原因,这将失败:SimpleXML 的 the xpath() method 总是 returns 一个 数组 ,而不是 object,所以您必须要求该数组的第一个元素 ([0])。

所以有效的 XPath 代码是这样的:

$xml->registerXPathNamespace('swp', 'https://webservices.sveaekonomi.se/webpay');
$xml->xpath('//swp:request')[0]->addChild('param', 'value');