0

I read the following XML: http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml

controller:

$ECB_rates = array();
$currencies = explode(',', 'GBP,USD,RUB,AUD');
foreach($currencies as $currency) {
    $ECB_rates[$currency] = $ECB_XML->xpath('//Cube/Cube/Cube[@currency="' . $currency . '"]/@rate');
}
$this->set('ECB_rates', $ECB_rates);

view:

var_dump($ECB_rates);

and I get the following:

array(4) { ["GBP"]=> array(0) { } ["USD"]=> array(0) { } ["RUB"]=> array(0) { } ["AUD"]=> array(0) { } } 

I can't figure out why the rates are returned as empty array.

2
  • Because @rate and @currency are on the same level? Commented Apr 8, 2018 at 7:54
  • yes. I followed numerous posts, e.g. stackoverflow.com/questions/15158314/…, that's how they show you get to the same level attribute. Is this not correct? Commented Apr 8, 2018 at 8:02

1 Answer 1

0

The document has a default namespace, which can commonly confuse XPath expressions if not done correctly. The other part is that xpath() returns an array of SimpleXMLElements which also doesn't help your cause.

The following code first registers the default namespace with the prefix 'def' and then (I've simplified the expression as well) uses this as a prefix to find the <Cube> element with the currency you want. Then it takes the first result (there should only be one anyway) and casts it to a string to make it more useful.

$ECB_XML->registerXPathNamespace("def", "http://www.ecb.int/vocabulary/2002-08-01/eurofxref");
$ECB_rates = array();
$currencies = explode(',', 'GBP,USD,RUB,AUD');
foreach($currencies as $currency) {
    $ECB_rates[$currency] = (string)$ECB_XML->xpath('//def:Cube[@currency="' . $currency . '"]/@rate')[0];
}
var_dump($ECB_rates);

Which gives...

array(4) {
  'GBP' =>
  string(7) "0.87295"
  'USD' =>
  string(6) "1.2234"
  'RUB' =>
  string(7) "70.8270"
  'AUD' =>
  string(6) "1.5934"
}

Update:

You could (if the XML format is stable) just use SimpleXML element/attribute access. Checking if the currency is in the array of currencies your after...

foreach($ECB_XML->Cube->Cube->Cube as $rate) {
    $currency = (string)$rate["currency"];
    if ( in_array($currency, $currencies))   {
        $ECB_rates[$currency] = (string)$rate["rate"];
    }
}

This may give you the items in a different order, but this might not be an issue.

Sign up to request clarification or add additional context in comments.

3 Comments

I read the xml with simplexml_load_string, the same way as an example on the ECB site: ecb.europa.eu/stats/policy_and_exchange_rates/…. Doesn't the simplexml_load_string take care of the namespace?
The following works fine to list all nodes: foreach($ECB_XML->Cube->Cube->Cube as $rate) { $ECB_rates[(string)$rate["currency"]] = $rate["rate"]; }. But I need to list only those from my list.
I've added another example. As for the namespace - SimpleXML does take it into account, but this doesn't necessarily work with XPath.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.