php xpath возвращает массив (0)

avatar
linuxoid
8 апреля 2018 в 07:51
127
1
0

Я прочитал следующий XML: http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml

контроллер:

$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);

вид:

var_dump($ECB_rates);

и я получаю следующее:

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

Я не могу понять, почему ставки возвращаются в виде пустого массива.

Источник
u_mulder
8 апреля 2018 в 07:54
0

Потому что @rate и @currency находятся на одном уровне?

linuxoid
8 апреля 2018 в 08:02
0

да. Я следил за многочисленными сообщениями, например. coderhelper.com/questions/15158314/…, вот как они показывают, что вы получаете атрибут того же уровня. Разве это не правильно?

Ответы (1)

avatar
Nigel Ren
8 апреля 2018 в 08:06
0

Документ имеет пространство имен по умолчанию, которое может привести к путанице в выражениях XPath, если оно сделано неправильно. Другая часть заключается в том, что xpath() возвращает массив SimpleXMLElements, который также не помогает в вашем деле.

Следующий код сначала регистрирует пространство имен по умолчанию с префиксом 'def', а затем (я также упростил выражение) использует его в качестве префикса для поиска элемента <Cube> с нужной валютой. Затем он берет первый результат (в любом случае он должен быть только один) и преобразует его в строку, чтобы сделать его более полезным.

$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);

Что дает...

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

Обновление:

Вы можете (если формат XML стабилен) просто использовать доступ к элементам/атрибутам SimpleXML. Проверка наличия валюты в массиве валют после...

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

Это может дать вам элементы в другом порядке, но это может не быть проблемой.

linuxoid
8 апреля 2018 в 08:15
0

Я прочитал xml с simplexml_load_string, так же, как пример на сайте ЕЦБ: ecb.europa.eu/stats/policy_and_exchange_rates/…. Разве simplexml_load_string не заботится о пространстве имен?

linuxoid
8 апреля 2018 в 08:21
0

Следующее отлично работает для перечисления всех узлов: foreach($ECB_XML->Cube->Cube->Cube as $rate) { $ECB_rates[(string)$rate["currency"]] = $rate["rate"]; }. Но мне нужно перечислить только те из моего списка.

Nigel Ren
8 апреля 2018 в 13:53
0

Я добавил еще один пример. Что касается пространства имен - SimpleXML учитывает его, но это не обязательно работает с XPath.