问题
How would I get the last item (or any specific item for that matter) in a simplexml object? Assume you don't know how many nodes there will be.
ex.
<?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>
And I want to grab the last <obj></obj>
chunk (or even just part of it).
回答1:
Use XPath's last()
function, which solves this very problem:
<?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);
?>
Here it looks for the last inner <obj>
, and therein for the <int>
with the name of "energy_in_kwh"
.
Watch out for the namespace registration. (All your elements are part of the "http://obix.org/ns/schema/1.0"
namespace, the XPath query must reflect that.
EDIT: Note that [last()]
is equivalent to [position() = last()]
.
回答2:
There is a XPath expression that'll do exactly what you want:
$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);
For example /bookstore/book[last()]
will select the last book element that is the child of the bookstore element.
回答3:
Quickest way to access nodes in XML, for a programmer, is XPath. Take a look at the xpath methods and xpath itself.
回答4:
You can start with this.. You'll be able to dig it out.. I don't like that they used the same tag name at 2 levels.. I try to avoid duplicate tag names.
<?php
$s = simplexml_load_file('in.xml');
$s->registerXPathNamespace('obix', 'http://obix.org/ns/schema/1.0');
$items = $s->xpath('//obix:list');
?>
回答5:
I think SimpleXML loads the whole XML anyway and (if I remember correctly) you can use the SimpleXML nodes as if they were arrays, so you could just use array functions to get the last node. It's a while since I used PHP but you should be able to get the length and then get the item at length-1...
Edit:
You can of course use XPath too, I thought I should mention that too but I wasn't sure if last()
worked in the SimpleXML XPath implementation.
I'm not sure wich is fastest, using array indexes or XPath, I would guess that array indexes were faster but you should try both in a loop a few thousand times getting the time before and after the loop to check.
But as allways in CS: what you choose depends on many things.
Is it time critical or used very often: then find the fastest solution.
If you will need more complicated queries and speed isn't an issue: then use whatever is easiest to implement and gives the power you need (XPath is good for complex tree navigation, array indexing is good for quick random access in list-type datastructures; XML can be used for both.)
回答6:
As it was already mentioned, you can use array notation and functions.
<?php
$xml = simplexml_load_file('HistoryRecord.xml');
$lastObj = $xml->list->obj[$xml->list->obj->count()-1];
or
$lastObj = $xml->list->obj[count($xml->list->obj)-1];
You can also use end()
to get the last element but only if you always have more than one <obj>, otherwise it will return different result.
来源:https://stackoverflow.com/questions/295112/php-simplexml-how-to-get-the-last-item