The Surrican
The Surrican

Reputation: 29866

How can I select an xml element by attribute without iterating using PHP?

I have this XML from http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml

<?xml version="1.0" encoding="UTF-8"?>
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
    <gesmes:subject>Reference rates</gesmes:subject>
    <gesmes:Sender>
        <gesmes:name>European Central Bank</gesmes:name>
    </gesmes:Sender>
    <Cube>
        <Cube time='2013-08-23'>
            <Cube currency='USD' rate='1.3355'/>
            <Cube currency='GBP' rate='0.85910'/>
            <Cube currency='HUF' rate='298.98'/>
        </Cube>
    </Cube>
</gesmes:Envelope>

(I removed some values for demonstrational purposes)

I want to get the conversion rate, for lets say, GBP using PHP.

HI can load it using simplexml like this:

$XML=simplexml_load_file("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml");

    foreach($XML->Cube->Cube->Cube as $rate){
...

But I would like to get the value without iterating, and i really dont want to use regex...

I tried something like this but it didnt work:

$sxe=simplexml_load_file("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml");

$sxe->registerXPathNamespace('c', 'http://www.gesmes.org/xml/2002-08-01');
$result = $sxe->xpath('//c:Cube[@currency="USD"]');

Upvotes: 3

Views: 1246

Answers (1)

IMSoP
IMSoP

Reputation: 97718

The Cube elements are not in the http://www.gesmes.org/xml/2002-08-01 namespace, which has been given the prefix gesmes, they are in the default namespace, which is http://www.ecb.int/vocabulary/2002-08-01/eurofxref.

Therefore rather than:

$sxe->registerXPathNamespace('c', 'http://www.gesmes.org/xml/2002-08-01');
$result = $sxe->xpath('//c:Cube[@currency="USD"]');

You need to register the other namespace:

$sxe->registerXPathNamespace('c', 'http://www.ecb.int/vocabulary/2002-08-01/eurofxref');
$result = $sxe->xpath('//c:Cube[@currency="USD"]');

Here is a live demo showing a result count of 1 with the corrected namespace.


To attempt to give this an authoritative explanation, consider the following excerpts from the Namespaces in XML specification:

The Prefix provides the namespace prefix part of the qualified name, and MUST be associated with a namespace URI reference in a namespace declaration [...] Note that the prefix functions only as a placeholder for a namespace name.

The expanded name corresponding to a prefixed element or attribute name has the URI to which the prefix is bound as its namespace name [...]

A default namespace declaration applies to all unprefixed element names within its scope.

If there is a default namespace declaration in scope, the expanded name corresponding to an unprefixed element name has the URI of the default namespace as its namespace name. If there is no default namespace declaration in scope, the namespace name has no value. [...] In all cases, the local name is [...] the same as the unprefixed name itself.

The element Cube has no prefix, so we look for a default namespace declaration that is in scope; reaching the outermost element, we find xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref", so the "namespace name" of the Cube element is the URI http://www.ecb.int/vocabulary/2002-08-01/eurofxref, and the "local name" is Cube.

If we looked instead at the element gesmes:Sender, we would see that it has a prefix, gesmes, so we would look for a definition of that prefix. Finding xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01", we would conclude that the "expanded name" has the "namespace name" http://www.gesmes.org/xml/2002-08-01, and the "local name" Sender.

In order to use these "namespace names" with XPath, we have to assign prefixes for use in the XPath expression, which needn't correspond to the prefixes in the actual document. In this case, we chose to assign the namespace http://www.ecb.int/vocabulary/2002-08-01/eurofxref the prefix c, so that the expression //c:Cube will match any element with a "namespace name" of http://www.ecb.int/vocabulary/2002-08-01/eurofxref and a "local name" of Cube.

Upvotes: 4

Related Questions