This question is intended as a reference to answer a particularly common question, which might take different forms:
If your question has been closed as a duplicate of this, it may not be identical to these examples, but this page should tell you what you need to know.
Here is an illustrative example:
$xml =
<<<XML
<?xml version="1.0" encoding="utf-8"?>
<document xmlns="http://example.com" xmlns:ns2="https://namespaces.example.org/two" xmlns:seq="urn:example:sequences">
<list type="short">
<ns2:item seq:position="1">A thing</ns2:item>
<ns2:item seq:position="2">Another thing</ns2:item>
</list>
</document>
XML;
$sx = simplexml_load_string($xml);
This code will not work; why not?
foreach ( $sx->list->ns2:item as $item ) {
echo 'Position: ' . $item['seq:position'] . "\n";
echo 'Item: ' . (string)$item . "\n";
}
The first problem is that->ns2:item
is invalid syntax; but changing it to this doesn't work either:
foreach ( $sx->list->{'ns2:item'} as $item ) { ... }
Why not, and what should you use instead?
A colon (:
) in a tag or attribute name means that the element or attribute is in an XML namespace. Namespaces are a way of combining different XML formats / standards in one document, and keeping track of which names come from which format. The colon, and the part before it, aren't really part of the tag / attribute name, they just indicate which namespace it's in.
An XML namespace has a namespace identifier, which is identified by a URI (a URL or URN). The URI doesn't point at anything, it's just a way for someone to "own" the namespace. For instance, the SOAP standard uses the namespacehttp://www.w3.org/2003/05/soap-envelope
and an OpenDocument file uses (among others)urn:oasis:names:tc:opendocument:xmlns:meta:1.0
. The example in the question uses the namespaceshttp://example.com
andhttps://namespaces.example.org/two
.
Within a document, or a section of a document, a namespace is given a local prefix, which is the part you see before the colon. For instance, in different documents, the SOAP namespace might be given the local prefixsoap:
,SOAP:
,SOAP-ENV:
,env:
, or justns1:
. These names are linked back to the identifier of the namespace using a specialxmlns
attribute, e.g.xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
. The choice of prefix in a particular document is completely arbitrary, and could change each time it was generated without changing the meaning.
Finally, there is a default namespace in each document, or section of a document, which is the namespace used for elements with no prefix. It is defined by anxmlns
attribute with no:
, e.g.xmlns="http://www.w3.org/2003/05/soap-envelope"
. In the example above,<list>
is in the default namespace, which is defined ashttp://example.com
.
Somewhat peculiarly, un-prefixed attributes are never in the default namespace, but in a kind of "void namespace", which the standard doesn't clearly define. See: XML Namespaces and Unprefixed Attributes
If you useprint_r
,var_dump
, or similar "dump structure" functions on a SimpleXML object with namespaces in, some of the contents will not display. It is still there, and can be accessed as described below.
SimpleXML provides two main methods for using namespaces:
allows you to access child elements in a particular namespace. It effectively switches your object to look at that namespace, until you call it again to switch back, or to another namespace.
works in a similar way, but allows you to access attributes in a particular namespace.
For instance, the example above might become:
define('XMLNS_EG1', 'http://example.com');
define('XMLNS_EG2', 'https://namespaces.example.org/two');
define('XMLNS_SEQ', 'urn:example:sequences');
foreach ( $sx->children(XMLNS_EG1)->list->children(XMLNS_EG2)->item as $item ) {
echo 'Position: ' . $item->attributes(XMLNS_SEQ)->position . "\n";
echo 'Item: ' . (string)$item . "\n";
}
You can also select the initial namespace when you first parse the XML, using the$namespace_or_prefix
parameter, which is the fourth parameter tosimplexml_load_string
,simplexml_load_file
, ornew SimpleXMLElement
.
For instance, if we created the object this way, we wouldn't need the->children(XMLNS_EG1)
call to access thelist
element:
$sx = simplexml_load_string($xml, null, 0, XMLNS_EG1);
(Note that if the root element uses a default namespace rather than a prefix, SimpleXML will select it automatically; but since you can't predict which namespace will be the default in future, it's best to always include the$namespace_or_prefix
parameter or initial->children()
call.)
As a short-hand, you can also pass the methods the local alias of the namespace, by giving the second parameter astrue
. Remember that this prefix could change at any time, for instance, a generator might assign prefixesns1
,ns2
, etc, and assign them in a different order if the code changes slightly. Relying on the full namespace URIs is always the best approach.
Using this short-hand, the code would become:
foreach ( $sx->list->children('ns2', true)->item as $item ) {
echo 'Position: ' . $item->attributes('seq', true)->position . "\n";
echo 'Item: ' . (string)$item . "\n";
}
(This short-hand was added in PHP 5.2, and you may see really old examples using a more long-winded version using$sx->getNamespaces
to get a list of prefix-identifier pairs. This is the worst of both worlds, as you're still hard-coding the prefix rather than the identifier.)
SimpleXML has an which allows you to search an element with XPath 1.0 syntax. To access namespaced nodes, you have to choose your own prefixes by calling the
.
Remember that even if an element doesn't have a prefix and a colon, it can be in a "default namespace" declared withxmlns
.
For example:
define('XMLNS_EG2', 'https://namespaces.example.org/two');
define('XMLNS_SEQ', 'urn:example:sequences');
$sx->registerXPathNamespace('EG2', XMLNS_EG2);
$sx->registerXPathNamespace('SEQ', XMLNS_SEQ);
foreach ( $sx->xpath('//EG2:item[@SEQ:position=2]') as $item ) {
echo 'Item: ' . (string)$item . "\n";
}
Note that the prefix you choose does not need to match what's used in the XML, it is your local alias for the namespaces you're interested in.
Note also thatregisterXPathNamespace
has no effect on anything other than thexpath
method. If you are not using XPath, you need to usechildren()
andattributes()
as discussed elsewhere on this page.
xpath()
on and are not inherited or copied to other objects. If you want to search based on different starting points, you'll have to runregisterXPathNamespace
every time.Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.
Find the answer in similar questions on our website.
Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.
PHP (from the English Hypertext Preprocessor - hypertext preprocessor) is a scripting programming language for developing web applications. Supported by most hosting providers, it is one of the most popular tools for creating dynamic websites.
The PHP scripting language has gained wide popularity due to its processing speed, simplicity, cross-platform, functionality and distribution of source codes under its own license.
https://www.php.net/
Welcome to the Q&A site for web developers. Here you can ask a question about the problem you are facing and get answers from other experts. We have created a user-friendly interface so that you can quickly and free of charge ask a question about a web programming problem. We also invite other experts to join our community and help other members who ask questions. In addition, you can use our search for questions with a solution.
Ask about the real problem you are facing. Describe in detail what you are doing and what you want to achieve.
Our goal is to create a strong community in which everyone will support each other. If you find a question and know the answer to it, help others with your knowledge.