Get Attribute value from Soap Response PHP

Viewed 872

I am getting a soap response as expected and then converting to an array. Here is my code:

$response = $client->__getLastResponse();
$response = preg_replace("/(<\/?)(\w+):([^>]*>)/", "$1$2$3", $response);
$xml = new SimpleXMLElement($response);
$body = $xml->xpath('//soapBody')[0];
$array = json_decode( str_replace('@', '', json_encode((array)$body)), TRUE); 
print_r($array);

here is the output:

Array ( 
[GetCompanyCodeResponse] => Array ( 
    [GetCompanyCodeResult] => Array ( 
        [Customers] => Array ( 
            [Customer] => Array ( 
                [attributes] => Array ( 
                    [CustomerNo] => 103987 
                    [CustomerName] => epds api testers Inc 
                    [ContactId] => 219196 
                ) 
            ) 
        ) 
    ) 
) 

How do i echo the ContactId? Ive tried the following:

$att = $array->attributes();
$array->attributes()->{'ContactId'};
print_r($array);

I get the following error:

Fatal error: Uncaught Error: Call to a member function attributes() on array 

Also tried:

$array->Customer['CustomerId'];

I get following error:

Notice: Trying to get property 'Customer' of non-object

Expecting to get 219196

2 Answers

I found the solution to the above problem. Not sure if it is the most elegant way to do it, but it returns result as expected. If there is a more efficient way to get the ContactId, I am open to suggestions.

print_r($array['GetCompanyCodeResponse']['GetCompanyCodeResult']
['Customers']['Customer']['attributes']['ContactId']);

You have followed some very bad advice on how to parse the XML, and completely thrown away the functionality of SimpleXML.

Specifically, the reason you can't run the attributes() method is that you've converted the SimpleXML object to a plain array using this ugly hack:

$array = json_decode( str_replace('@', '', json_encode((array)$body)), TRUE); 

To use SimpleXML as its authors intended, I suggest you read:

Since you didn't paste the actual XML in the question, I'm going to take a guess that it looks like this:

<?xml version = "1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope">
   <soap:Body xmlns="http://www.example.org/companyInfo">
      <GetCompanyCodeResponse>
         <GetCompanyCodeResult>
            <Customers>
                <Customer CustomerNo="103987" CustomerName="epds api testers Inc" ContactId="219196" />
            </Customers>
         </GetCompanyCodeResult>
      </GetCompanyCodeResponse>
   </soap:Body>
</soap:Envelope>

If that is in $response, we don't need to do any weirdness with str_replace or json_encode, we can use the methods built into SimpleXML to navigate around the XML:

$xml = new SimpleXMLElement($response);
// The Body is in the SOAP Envelope namespace
$body = $xml->children('http://www.w3.org/2001/12/soap-envelope')->Body;
// The element inside that is in some other namespace
$innerResponse = $body->children('http://www.example.org/companyInfo')->GetCompanyCodeResponse;
// We need to traverse the XML to get to the node we're interested in
$customer = $innerResponse->GetCompanyCodeResult->Customers->Customer;
// Unprefixed attributes aren't technically in any namespace (an oddity in the XML namespace spec!)
$attributes = $customer->attributes(null);
// Here's the value you were looking for
echo $attributes['ContactId'];

Unlike your previous code, this won't break if:

  • The server starts using a different local prefix instead of soap:, or adding a prefix on the GetCompanyCodeResponse element
  • The response comes back with more than one Customer (the ->Customer always means the same as ->Customer[0], the first child element with that name)
  • The Customer element has child elements or text content as well as attributes

It also allows you to use other features of SimpleXML, like using an xpath expression to search the document or even switching to the full DOM API for more complex operations.

Related