Как мне получить последний элемент (или любой конкретный элемент в этом отношении) в объекте simplexml? Предположим, вы не знаете, сколько узлов будет.
бывший.
<?xml version = "1.0" encoding = "UTF-8"?>
<?xml-stylesheet type = "text/xsl" href = "/xsl.xml"?>
<obj
href = "http://xml.foo.com/"
display = "com.foo.bar"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns = "http://obix.org/ns/schema/1.0"
>
<list name = "data" of = "HistoryRecord">
<obj>
<abstime name = "timestamp" val = "1876-11-10T00:00:00-08:00"></abstime>
<int name = "energy_in_kwh" val = "1234"></int>
<int name = "energy_out_kwh" val = "123456"></int>
</obj>
<obj>
<abstime name = "timestamp" val = "1876-11-10T00:15:00-08:00"></abstime>
<int name = "energy_in_kwh" val = "1335"></int>
<int name = "energy_out_kwh" val = "443321"></int>
</obj>
</list>
<int name = "count" val = "2"></int>
</obj>
И я хочу захватить последний кусок <obj></obj> (или даже его часть).






Я думаю, SimpleXML все равно загружает весь XML и (если я правильно помню) вы можете использовать узлы SimpleXML, как если бы они были массивами, поэтому вы могли бы просто использовать функции массива для получения последнего узла. Прошло некоторое время с тех пор, как я использовал PHP, но вы должны иметь возможность получить длину, а затем получить элемент длиной-1 ...
Редактировать:
Конечно, вы также можете использовать XPath, я подумал, что должен упомянуть и об этом, но я не был уверен, работает ли last() в реализации SimpleXML XPath.
Я не уверен, что быстрее всего, используя индексы массива или XPath, я бы предположил, что индексы массива были быстрее, но вы должны попробовать оба в цикле несколько тысяч раз, получая время до и после цикла для проверки.
Но, как всегда в CS: то, что вы выберете, зависит от многих вещей.
Это критично по времени или используется очень часто: тогда найдите самое быстрое решение.
Если вам понадобятся более сложные запросы и скорость не является проблемой: тогда используйте то, что проще всего реализовать и дает необходимую мощность (XPath хорош для сложной навигации по дереву, индексация массивов хороша для быстрого произвольного доступа в структурах данных типа списков ; XML можно использовать для обоих.)
Самый быстрый способ доступа к узлам в XML для программиста - это XPath. Взгляните на методы xpath и сам xpath.
Вы можете начать с этого .. Вы сможете выкопать это .. Мне не нравится, что они использовали одно и то же имя тега на двух уровнях .. Я стараюсь избегать дублирования имен тегов.
<?php
$s = simplexml_load_file('in.xml');
$s->registerXPathNamespace('obix', 'http://obix.org/ns/schema/1.0');
$items = $s->xpath('//obix:list');
?>
Используйте функцию XPath last(), которая решает именно эту проблему:
<?php
$xml = simplexml_load_file('HistoryRecord.xml');
$xml->registerXPathNamespace('o', 'http://obix.org/ns/schema/1.0');
$xpath = "/o:obj/o:list/o:obj[last()]/o:int[@name = 'energy_in_kwh']";
$last_kwh = $xml->xpath($xpath);
?>
Здесь он ищет последний внутренний <obj>, а в нем - <int> с именем "energy_in_kwh".
Следите за регистрацией пространства имен. (Все ваши элементы являются частью пространства имен "http://obix.org/ns/schema/1.0", запрос XPath должен это отражать.
Обновлено: Обратите внимание, что [last()] эквивалентен [position() = last()].
Вероятно, потому что отсутствует регистрация пространства имен. Не заметил, потому что в вопросе он за кадром.
Есть выражение XPath, которое сделает именно то, что вы хотите:
$xml='<?xml version = "1.0" encoding = "UTF-8"?>
<?xml-stylesheet type = "text/xsl" href = "/xsl.xml"?>
<obj href = "http://xml.foo.com/" display = "com.foo.bar" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns = "http://obix.org/ns/schema/1.0" >
<list name = "data" of = "HistoryRecord">
<obj>
<abstime name = "timestamp" val = "1876-11-10T00:00:00-08:00"></abstime>
<int name = "energy_in_kwh" val = "1234"></int>
<int name = "energy_out_kwh" val = "123456"></int>
</obj>
<obj>
<abstime name = "timestamp" val = "1876-11-10T00:15:00-08:00"></abstime>
<int name = "energy_in_kwh" val = "1335"></int>
<int name = "energy_out_kwh" val = "443321"></int>
</obj>
</list>
<int name = "count" val = "2"></int>
</obj>';
$x=simplexml_load_string($xml);
$x->registerXPathNamespace('obix', 'http://obix.org/ns/schema/1.0');
$objects=$x->xpath('/obix:obj/obix:list/obix:obj[last()]');
print_r($objects);
Например, /bookstore/book[last()] выберет последний элемент book, который является дочерним элементом элемента bookstore.
Забыл префикс пространства имен в выражении XPath ... Извините!
Как уже упоминалось, вы можете использовать нотацию и функции массива.
<?php
$xml = simplexml_load_file('HistoryRecord.xml');
$lastObj = $xml->list->obj[$xml->list->obj->count()-1];
или же
$lastObj = $xml->list->obj[count($xml->list->obj)-1];
Вы также можете использовать end() для получения последнего элемента, но только если у вас всегда более одного <obj>, иначе он вернет другой результат.
Вы тестировали этот код? Я просто запустил его, но ничего не вышло. $ last_kwh вернет ложь;