Search code examples
phpnamespacessimplexml

How to get values from mix of namespace and non-namespace XML with


Given the XML and related PHP, below how can I get the namespaced values in the same way that I'm able to get the non-namespaced values? I've been referring to a number of other SE QAs about this, but can't seem to get it right. An help is appreciated. :)

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:psg="http://b3000.example.net:3000/psg_namespace/">
  <channel>
    <title>Example</title>
    <description>example stuff</description>
    <item>
      <psg:eventId>406589</psg:eventId>
      <psg:duration>3482</psg:duration>
    </item>
  </channel>
</rss>

$xml = new SimpleXMLElement($source, null, true);
foreach($xml->channel->item as $entry){
    echo $entry->title;          // This works
    echo $entry->description;    // This works
    echo $entry->item->duration  // Pseudo of what I need
}

How to get Duration? My attempts with variations such as this have failed

$namespaces = $item->getNameSpaces(true);
$psg = $item->children($namespaces['psg']);

Update

While it wasn't the answer I was actually looking for, I have to accept the first answer that got me trying things leading to the actual problem - "operator error"! This DOES work....my problem was in trying to figure it out, I was debugging with echo print_r($psg, true). That was showing the result as a SimpleXmlObject, which then got me chasing how to get those properties - All I had to do was assign the property instead of echoing it.

foreach($xml->channel->item as $entry){
    $psg = $item->children($ns['psg']);
    $title    = (string) $item->title;
    $duration = (string) $psg->duration;
}

Solution

  • One way to achieve this is to use a combination of XPath with namespaces:

    $xml = new SimpleXMLElement($source, null, true);
    $xml->registerXPathNamespace('psg', 'http://b3000.example.net:3000/psg_namespace/');
    
    foreach ($xml->xpath('//item/psg:duration') as $duration) {
        echo $duration, PHP_EOL;
    }
    

    If you don't want to declare the namespace literally, you can retrieve it from the document and add it/them dynamically:

    foreach ($xml->getDocNamespaces() as $key => $namespace) {
        $xml->registerXPathNamespace($key, $namespace);
    }