如何在命名空间环境中访问 SimpleXML 节点?
Posted
技术标签:
【中文标题】如何在命名空间环境中访问 SimpleXML 节点?【英文标题】:How do you access SimpleXML nodes in a namespace environment? 【发布时间】:2021-10-09 20:44:12 【问题描述】:如何在命名空间环境中访问 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');
【问题讨论】:
【参考方案1】:你在这里犯了一些常见的错误,所以我将依次进行。
让我们从您的第一次尝试开始:
$xml->Envelope->Body->...
SimpleXML 没有单独的文档对象,只有根元素 - 在本例中为 Envelope
。所以你不需要说->Envelope
,你已经在那里了。如果不涉及命名空间,您将编写:
$xml->Body->...
但是,对象不会自动“选择”该元素的命名空间,因此您必须立即调用 ->children()
,或者将要预选的命名空间传递给构造函数:
$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->...
这会失败,因为 Function
与 Body
不在同一个命名空间中。我喜欢的想法是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”方法不会让您深入到文档中 - 顾名思义,它为您提供元素的直接子元素,而不是孙子、曾孙-儿童等等。 $xml
变量指向“信封”节点,它没有名为“请求”的子节点。
没有“任何后代”的内置方法,除非使用 XPath...
虽然看起来完全不同,但您的第三次尝试实际上因同样的原因而失败:
$xml->registerXPathNamespace('swp', 'https://webservices.sveaekonomi.se/webpay');
$xml->xpath('/swp:request')->...
XPath 中的/
运算符同样表示“子级”; 是“任何后代”的运算符,即//
,因此您将几乎得到正确的结果:
$xml->registerXPathNamespace('swp', 'https://webservices.sveaekonomi.se/webpay');
$xml->xpath('//swp:request')->...
这会因为一个更微妙的原因而失败:SimpleXML 的the xpath()
method 总是返回一个数组,而不是一个对象,所以你必须要求它的第一个元素 ([0]
)数组。
所以工作的 XPath 代码是这样的:
$xml->registerXPathNamespace('swp', 'https://webservices.sveaekonomi.se/webpay');
$xml->xpath('//swp:request')[0]->addChild('param', 'value');
【讨论】:
哇,这个答案确实值得赞赏!非常感谢!投票并标记为问题的公认答案! :)【参考方案2】:由于您正在处理 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>
【讨论】:
有趣,我在这里学到了一些新东西:)以上是关于如何在命名空间环境中访问 SimpleXML 节点?的主要内容,如果未能解决你的问题,请参考以下文章
使用 SimpleXML 使用命名空间解析 XML [重复]