SimpleXML xpath有空元素

时间:2017-02-23 01:36:28

标签: php xml xpath simplexml

我目前正在构建一个PHP脚本,它将采用Salesforce webhook POST,目前正在努力正确解析Soap XML字符串并使其进入可用状态。

我正在使用的XML字符串如下:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
        <notifications
            xmlns="http://soap.sforce.com/2005/09/outbound">
            <OrganizationId>00DN0000000XXXXXXX</OrganizationId>
            <ActionId>04kN0000000XXXXXXX</ActionId>
            <SessionId xsi:nil="true"/>
            <EnterpriseUrl>https://cs6.salesforce.com/services/Soap/c/38.0/00DN0000000XXXXXXX</EnterpriseUrl>
            <PartnerUrl>https://cs6.salesforce.com/services/Soap/u/38.0/00DN0000000XXXXXXX</PartnerUrl>
            <Notification>
                <Id>00DN0000000XXXXXXX</Id>
                <sObject xsi:type="sf:Account"
                    xmlns:sf="urn:sobject.enterprise.soap.sforce.com">
                    <sf:Id>00DN0000000XXXXXXX</sf:Id>
                    <sf:FirstName>Bill</sf:FirstName>
                    <sf:LastName>Jack</sf:LastName>
                    <sf:PersonEmail>abc@xyz.net</sf:PersonEmail>
                    <sf:PersonMobilePhone>0400000000</sf:PersonMobilePhone>
                </sObject>
            </Notification>
        </notifications>
    </soapenv:Body>
</soapenv:Envelope>

我用来提取数据的代码如下:

$xml = simplexml_load_string($xmlString);

$xml->registerXPathNamespace('soapenv', 'http://schemas.xmlsoap.org/soap/envelope/');
$xml->registerXPathNamespace('ob', 'http://soap.sforce.com/2005/09/outbound');
$xml->registerXPathNamespace('sf', 'urn:sobject.enterprise.soap.sforce.com');

$notifications = $xml->xpath('//soapenv:Envelope/soapenv:Body/ob:notifications/ob:Notification/*');

我可以获得Notification标记的子项,但无论我做什么,我都无法提取sObject子项及其相关数据。

我试图摆弄名称空间,这是我怀疑我出错的地方,我试过的其他事情涉及使用通配符和其他XPath运算符无济于事。

我做错了什么意味着我无法通过xpath()方法获取sObject?

1 个答案:

答案 0 :(得分:0)

好的,所以我已经弄清楚发生了什么,并把它留在这里,希望任何遇到同一问题的人都会发现这个答案很有帮助。感谢IMSoP帮助我找到答案。

首先,SimpleXML的xpath()方法返回一个数组,而不是XML对象,这从一开始就让生活变得困难。其次,如果您查看<notifications>标记,您会看到它使用outbound命名空间,在我的示例中,我将其别名为ob。因此,NotificationsObject也被认为是同名命名空间的一部分,因为它们是命名空间元素的子元素,这意味着正确的xpath是

//soapenv:Envelope/soapenv:Body/ob:notifications/ob:Notification/ob:sObject

如上所述,在SimpleXML中,将返回一个数组,因此抓取第一个索引,并在children()方法调用中使用提供的命名空间url for sObject,您将获得数据。

所以使用上面的例子XML

<soapenv:Envelope
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
        <notifications
            xmlns="http://soap.sforce.com/2005/09/outbound">
            <OrganizationId>00DN0000000XXXXXXX</OrganizationId>
            <ActionId>04kN0000000XXXXXXX</ActionId>
            <SessionId xsi:nil="true"/>
            <EnterpriseUrl>https://cs6.salesforce.com/services/Soap/c/38.0/00DN0000000XXXXXXX</EnterpriseUrl>
            <PartnerUrl>https://cs6.salesforce.com/services/Soap/u/38.0/00DN0000000XXXXXXX</PartnerUrl>
            <Notification>
                <Id>00DN0000000XXXXXXX</Id>
                <sObject xsi:type="sf:Account"
                    xmlns:sf="urn:sobject.enterprise.soap.sforce.com">
                    <sf:Id>00DN0000000XXXXXXX</sf:Id>
                    <sf:FirstName>Bill</sf:FirstName>
                    <sf:LastName>Jack</sf:LastName>
                    <sf:PersonEmail>abc@xyz.net</sf:PersonEmail>
                    <sf:PersonMobilePhone>0400000000</sf:PersonMobilePhone>
                </sObject>
            </Notification>
        </notifications>
    </soapenv:Body>
</soapenv:Envelope>

我们可以通过以下方式获取数据:

$xml = simplexml_load_string($xmlString);

$xml->registerXPathNamespace('soapenv', 'http://schemas.xmlsoap.org/soap/envelope/');
$xml->registerXPathNamespace('ob', 'http://soap.sforce.com/2005/09/outbound');

$sObject = $xml->xpath('//soapenv:Envelope/soapenv:Body/ob:notifications/ob:Notification/ob:sObject')[0];

$data = $sObject->children('urn:sobject.enterprise.soap.sforce.com');
var_dump($data);