Question

So, I'm using PHP to talk to a Zimbra SOAP server. The response is in a <soap:Envelope> tag. I'm having trouble parsing the XML response because of the namespace(s).

The XML looks like this:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
  <soap:Header>
    <context xmlns="urn:zimbra">
      <change token="20333"/>
    </context>
  </soap:Header>
  <soap:Body>
    <CreateAccountResponse xmlns="urn:zimbraAdmin">
      <account id="83ebf344-dc51-47ae-9a36-3eb24281d53e" name="iamtesting@example.com">
        <a n="zimbraId">83ebf344-dc51-47ae-9a36-3eb24281d53e</a>
        <a n="zimbraMailDeliveryAddress">iamtesting@example.com</a>
      </account>
    </CreateAccountResponse>
  </soap:Body>
</soap:Envelope>

I make a new SimpleXMLElement object:

$xml = new SimpleXMLElement($data);

After Googling a bit, I found I need to register the namespace. So I do that:

$xml->registerXPathNamespace('soap', 'http://www.w3.org/2003/05/soap-envelope');

Then I can get the <soap:Body> tag easily.

$body = $xml->xpath('//soap:Body');

But I can't get any elements after that (using xpath):

$CreateAccountResponse = $xml->xpath('//soap:Body/CreateAccountResponse');

This returns an empty array. I can traverse the XML though, to get that element.

$CreateAccountResponse = $body[0]->CreateAccountResponse;

This works fine, but now I want to get the <a> tags, specifically the zimbraId one. So I tried this:

$zimbraId = $CreateAccountResponse->account->xpath('a[@n=zimbraId]');

No luck, I get a blank array. What's going on? Why can't I use xpath to get elements (that don't start with soap:)?

How can I get the <a> tags based on their n attribute?

P.S. I'm aware that the id and name are also in the <account> tag's attributes, but there are a bunch more <a> tags that I want to get using the n attribute.

Note: I'm trying to improve the Zimbra library for my application for work. The current code to get the <a> tags is as follows:

$zimbraId = strstr($data, "<a n=\"zimbraId\"");
$zimbraId = strstr($zimbraId, ">");
$zimbraId = substr($zimbraId, 1, strpos($zimbraId, "<") - 1);

Obviously, I want to remove this code (there's also some regexes (shudder) later on in the code), and use an XML parser.

Was it helpful?

Solution

The elements you want to retrieve have a namespace as well, namely urn:zimbraAdmin.

    <CreateAccountResponse xmlns="urn:zimbraAdmin">

The xmlns attribute states the default namespace for any child elements, so the elements you are trying to retrieve actually have a namespace, even though no prefix is used (see the wikipedia article for some examples). If you specify a namespace prefix as you did for http://www.w3.org/2003/05/soap-envelope you should be fine.

$xml->registerXPathNamespace('soap', 'http://www.w3.org/2003/05/soap-envelope');
$xml->registerXPathNamespace('zimbra', 'urn:zimbraAdmin');
$CreateAccountResponse = $xml->xpath('//soap:Body/zimbra:CreateAccountResponse');
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top