David David - 12 days ago 6
PHP Question

Retrieving an array of values from an XML content with multiple namespaces in PHP

I posted another question, which to my error was incomplete.
I have an XML with multiple namespaces, but I need to access the values of in a foreach.

My XML array is:

<ArrayOfSession xmlns:i='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://schemas.datacontract.org/2004/07/Vista.Online.BackOffice.Api.Models.V1'>
<Session>
<AreComplimentariesAllowed>true</AreComplimentariesAllowed>
<Attributes xmlns:d3p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d3p1:string>0000000009</d3p1:string>
<d3p1:string>0000000011</d3p1:string>
</Attributes>
</Session>
</ArrayOfSession>


I was helped by another user at: Retrieving an array of values from an XML content with a namespace in PHP

With that answer I have tried a few variations. This being my current one, which isn't working:

$xml->registerXPathNamespace('i', 'http://www.w3.org/2001/XMLSchema-instance');
$xml->registerXPathNamespace('j', 'http://schemas.datacontract.org/2004/07/Vista.Online.BackOffice.Api.Models.V1');
$xml->registerXPathNamespace('ns', 'http://schemas.microsoft.com/2003/10/Serialization/Arrays');

foreach($xml->xpath('//ns:d3p1') as $header){
var_export($header->xpath('//Attributes/ns:string'));
}


I also tried:

foreach($xml->xpath('//ns:d3p1') as $header){
var_export($header->xpath('//ns:string'));
}


This is stumping me!

In my current working version for the rest of code, I'm retrieving the elements with:

foreach($xml->Session as $event){
// Do Something with $event->AreComplimentariesAllowed
}


This works fine, but I just can't access those Attributes elements.

Thanks as ever.

ThW ThW
Answer

You have to register the namespaces it on each SimpleXMLElement before you call xpath(). You register them on the $xml variable, but not on $header.

Your XML has an default namespace, too. You do register the prefix j for it, but you do not use the prefix in the expressions. Last here are no elements d3p1. This is only a namespace prefix in the document.

So to iterate the Session elements and then the string values inside the Attributes

$sessions = new SimpleXMLElement($xml);
$sessions->registerXPathNamespace(
  'j', 
  'http://schemas.datacontract.org/2004/07/Vista.Online.BackOffice.Api.Models.V1'
);

foreach($sessions->xpath('//j:Session') as $session) {
  $session->registerXPathNamespace(
    'j', 
    'http://schemas.datacontract.org/2004/07/Vista.Online.BackOffice.Api.Models.V1'
  );
  $session->registerXPathNamespace(
    'ns', 
    'http://schemas.microsoft.com/2003/10/Serialization/Arrays'
  );
  var_export($session->xpath('.//j:Attributes/ns:string'));
}

In DOM this looks different:

$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
$xpath->registerNamespace(
  'j', 
  'http://schemas.datacontract.org/2004/07/Vista.Online.BackOffice.Api.Models.V1'
);
$xpath->registerNamespace(
  'ns', 
  'http://schemas.microsoft.com/2003/10/Serialization/Arrays'
);

foreach ($xpath->evaluate('//j:Session') as $session) {
  var_export(
    iterator_to_array($xpath->evaluate('.//j:Attributes/ns:string', $session))
  );
}

It has a dedicated Xpath object, so the namespace registration has to be done only once.

Comments