【问题标题】:How do you access SimpleXML nodes in a namespace environment?如何在命名空间环境中访问 SimpleXML 节点?
【发布时间】: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');

【问题讨论】:

    标签: php xml dom soap simplexml


    【解决方案1】:

    你在这里犯了一些常见的错误,所以我将依次进行。

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

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

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

    $xml->Body->...
    

    但是,对象不会自动“选择”该元素的命名空间,因此您必须立即调用 -&gt;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->...
    

    这会失败,因为 FunctionBody 不在同一个命名空间中。我喜欢的想法是the -&gt;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>
    

    【讨论】:

    • 有趣,我在这里学到了一些新东西:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-05
    • 1970-01-01
    • 2012-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多