Getting the full name for SimpleXMLElement with namespace

Viewed 52

When using SimpleXMLElement in PHP is there a way to get the namespace or the full name for an element that has a namespace?

For example, with the element

<namespace:name>...</namespace:name>

SimpleXMLElement::getName() only returns name and getNamespaces() returns an array of all the namespaces from the document. I would like to be able to get the specific namespace that the element uses, in this case namespace, or the full name, namespace:name.

2 Answers

There doesn't appear to be a way to do this directly in SimpleXML right now. Luckily, however, you can "re-wrap" a SimpleXMLElement object as a DOMNode object using dom_import_simplexml. This doesn't re-process the XML, it just puts a different PHP object around the same internal data structure.

You can then access the information you need from the properties of the DOMNode object:

$domNode = dom_import_simplexml($simpleXmlElement);
$nsPrefix = $domNode->prefix;
$nsUri = $domNode->namespaceURI;

Bear in mind that the prefix (namespace: in your example) is entirely local to the current XML document, and even the current section of the XML document, so should not be interpreted as having permanent meaning.

The "real" namespace of the element is the namespace URI, which is the permanent identifier the local prefix has been bound to. So if you want an unambiguous representation of the element, you might use the format {http://example.com}SomeElement, i.e. '{' . $domNode->namespaceURI . '}' . $domNode->localName

[SimpleXMLElement::]getNamespaces() returns an array of all the namespaces from the document

No, that is SimpleXMLElement::getDocNamespaces().

SimpleXMLElement::getNamespaces() returns the namespaces of the element.

The first key/value of the returned array is the namespace-prefix/namespace-uri of the element itself (if it has one which we assume in this case1), all following are additional ones, e.g. of element attributes.

Example:

<?php declare(strict_types=1);

$sx = simplexml_load_string(<<<XML
<x xmlns:aed="http://aecommerce.org/schema" xmlns:edi='http://ecommerce.org/schema'>
  <!-- the 'price' element's namespace is http://ecommerce.org/schema -->
  <edi:price units='Euro' aed:more="test">
    32.18
  </edi:price>
</x>
XML, null, 0, 'http://ecommerce.org/schema');
// XML example from https://www.w3.org/TR/1999/REC-xml-names-19990114/#ns-using

var_dump($sx->price->getNamespaces());
/usr/bin/php8.1 -dzend.assertions=1 -dassert.exception=1 /home/hakre/sxml-namespace.php
array(2) {
  ["edi"]=>
  string(27) "http://ecommerce.org/schema"
  ["aed"]=>
  string(28) "http://aecommerce.org/schema"
}

If you leave out the attribute in the XML, the array entry is gone:

<?php declare(strict_types=1);

$sx = simplexml_load_string(<<<XML
<x xmlns:aed="http://aecommerce.org/schema" xmlns:edi='http://ecommerce.org/schema'>
  <!-- the 'price' element's namespace is http://ecommerce.org/schema -->
  <edi:price units='Euro'>
    32.18
  </edi:price>
</x>
XML, null, 0, 'http://ecommerce.org/schema');
// XML example from https://www.w3.org/TR/1999/REC-xml-names-19990114/#ns-using

var_dump($sx->price->getNamespaces());
var_dump($sx->price->getDocNamespaces());
/usr/bin/php8.1 -dzend.assertions=1 -dassert.exception=1 /home/hakre/sxml-namespace.php
array(1) {
  ["edi"]=>
  string(27) "http://ecommerce.org/schema"
}
array(2) {
  ["aed"]=>
  string(28) "http://aecommerce.org/schema"
  ["edi"]=>
  string(27) "http://ecommerce.org/schema"
}

1 It would be otherwise in the default namespace.

Related