PHP简单XML反转

4
有没有办法在simpleXML中加载的xml中反向循环?比如我有以下xml:
$string ="<items>
    <item>1</item>
    <item>2</item>
    <item>3</item> 
</items>";

$xml = simplexml_load_string($string);

有没有办法将 $xml 反转,这样当我使用 foreach 时就可以得到第三个项目?
6个回答

9

假设OP只是一个初学者,只关心解决方案,我建议使用xpath()获取元素,然后使用array_reverse()来反转它们的顺序:

$items = array_reverse($xml->xpath('item'));

注意:XPath中的“item”将抓取当前元素下的所有直接子元素<item/>

6
$items = $xml->item;
for ($i = count($items) - 1; $i >= 0; $i--)
{
    echo (string) $items[$i].", ";
}

是的,SimpleXMLIterator 实现了 Countable 接口,所以 count 部分应该可以工作。然而,它和它继承的任何类/接口都没有继承 ArrayAccess,所以 $items[$i] 不应该起作用。但我尝试了一下,它确实可以工作。得爱上不正确的实现(因为唯一的方式它能工作就是如果 $it instanceof ArrayAccess 返回 true,但它并没有(我已经检查过))... 为未记录的功能点数加一... - ircmaxell
我并不是说上面的代码不能工作。我只是在说它使用了未记录的(如果你想深究的话,还实现不当的)功能。这是一个 PHP 的问题,而不是提供的代码的问题... - ircmaxell
@ircmaxell 这并非未记录的事情。SimpleXmlElement有一个count方法,并且可以通过数组符号访问SimpleXmlElement在例子中已经展示了。只是SimpleXmlElement没有实现您期望的接口。 - Gordon

1

使用simplexml:

<?php
$string ="<items>
    <item>1</item>
    <item>2</item>
    <item>3</item>
</items>";

$xml = simplexml_load_string($string);

$length = count($xml->item);
for($i = $length; $i; --$i) {
    echo $xml->item[$i-1];
}

输出:

321

另一个例子:

这有点啰嗦,如果你真的想要,它使用更强大的{{link1:DomDocument}}而不是SimpleXml ;)

<?php
$string ="<items>
    <item>1</item>
    <item>2</item>
    <item>3</item>
</items>";

$oXml = DomDocument::loadXml($string);

$oItems = $oXml->firstChild->childNodes;
$lastItemIndex = $oItems->length;

$oItem = $oItems->item($lastItemIndex-1);
do {
    echo $oItem->nodeValue;
} while($oItem = $oItem->previousSibling);

输出:

3
2
1

1

这对我来说很好用:

$string = "<items>
<item>1</item>
<item>2</item>
<item>3</item>
</items>";
$xml = simplexml_load_string($string); 
$reverseArray = (array) $xml;
$reverseArray = array_reverse($reverseArray["item"]);
print_r($reverseArray);

输出:

Array
(
    [0] => 3
    [1] => 2
    [2] => 1
)

0

由于PHP中的迭代器没有previous方法,所以简短的答案是不行。您可以将它们读入数组,然后反转数组,但这不会直接向后迭代。

一个选项是创建一个ReverseIterator,其中您包装一个常规迭代器,然后向后遍历它。但这可能会有问题,因为您不知道迭代器是否有结束(您可以在SPL中看到一些没有的示例)。

所以不行,您唯一的选择是像这样做:

$nodes = array();
foreach ($xml AS $node) {
    array_unshift($nodes, $node);
}

我不确定在使用 foreach 时,SimpleXmlElement 是否默认使用 SimpleXmlIteratorsimplexml_load_file 的默认类是 SimpleXmlElement,它是一个 Class [ <internal:SimpleXML> <iterateable> class SimpleXMLElement implements Traversable ] - Gordon
它确实如此。$xml->item本身就是SimpleXmlIterator的一个实例(至少在我的5.3.3安装中是这样的)... - ircmaxell
在我的5.3.3安装中,var_dump($xml->item);返回SimpleXmlElement。虽然我很擅长阅读C代码,但我认为SimpleXmlElement基本上是一个HashTable on Steroids,并且迭代器已经内置其中。 - Gordon
1
我刚刚再次检查,现在它也报告了 SimleXMLElement。我不确定为什么我之前得到的是一个迭代器,但有些事情告诉我,在引擎盖下面有一些黑暗的巫术正在进行... - ircmaxell

-1

$xml->item 是一个数组。使用数组排序函数。

rsort($xml->item);
print_r($xml->item);

编辑:好的,没有其他方法可以做到这一点。你必须先创建一个数组。

$myArray = array_reverse((array)$xml->item, true);
print_r($myArray);

(不再测试)


无法工作,因为$xml->item不是一个数组,而是一个迭代器(确切地说是SimpleXMLIterator)。你无法对迭代器进行排序。 - ircmaxell
不是的。它是一个对象。这就是为什么你会得到一个警告:rsort()期望参数1是数组。 - Gordon
rsort 不会翻转数组,它会按照字母顺序相反的方式对数组进行排序。可以使用 array_reverse 来实现翻转数组。 - Sjoerd
先创建一个数组,然后对其进行排序或反转。 - Anpher
@Anpher 不行,也不会起作用。该数组只包含一个元素,而不是全部三个。 - Gordon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接