Сортировать объект (SimpleXMLElement) php

Я пытаюсь найти способ отсортировать свой массив из SimpleXMLElement. Я хотел бы отсортировать по времени начала, которое я могу получить из event_start_dt. Я также хотел бы сортировать по идентификатору комнаты как отдельный процесс. В настоящее время массив упорядочен по объекту (SimpleXMLElement) #. Вот var_dump($array):

    object(SimpleXMLElement)#275 (1) { 
["reservation"]=> array(3) 
    { 
    [0]=> object(SimpleXMLElement)#287 (28) { 
        ["reservation_id"]=> string(7) "8644894" 
        ["event_start_dt"]=> string(25) "2013-12-02T12:00:00-08:00" 
        ["event_end_dt"]=> string(25) "2013-12-02T13:00:00-08:00" 
        ["event_id"]=> string(6) "314147" 
        ["event_name"]=> string(24) "Practice" 
        ["room_id"]=> string(3) "202"
    }
    [1]=> object(SimpleXMLElement)#288 (28) { 
        ["reservation_id"]=> string(7) "8595185" 
        ["event_start_dt"]=> string(25) "2013-12-02T08:00:00-08:00" 
        ["event_end_dt"]=> string(25) "2013-12-02T09:00:00-08:00" 
        ["event_id"]=> string(6) "314005"
        ["event_name"]=> string(24) "Meeting" 
        ["room_id"]=> string(3) "207"
    }
    [2]=> object(SimpleXMLElement)#289 (28) { 
        ["reservation_id"]=> string(7) "8718654" 
        ["event_start_dt"]=> string(25) "2013-12-02T10:00:00-08:00" 
        ["event_end_dt"]=> string(25) "2013-12-02T11:00:00-08:00" 
        ["event_id"]=> string(6) "315811" 
        ["event_name"]=> string(20) "Maintenance" 
        ["room_id"]=> string(3) "202"
    }
} }

Я пробовал usort и asort, но не работал ни с одним из методов.

метод usort:

function sortByTime($a, $b){
    $a = strtotime($array->event_start_dt);
    $b = strtotime($array->event_start_dt);
        if ($a==$b) return 0;
        return ($a < $b) ?-1 : 1;
        }

        usort($arrTimes, 'sortByTime');

        var_dump($arrTimes);

Попытка кода ниже дает мне предупреждение: usort() ожидает, что параметр 1 будет массивом, заданным объектом.

foreach ($rez->reservation as $value){ 
    $var1 = $value->space_reservation->space_name;
    $var2 = substr($value->event_start_dt,11,5);
}
sort_obj_arr($value,$var1,SORT_DESC);

echo "<pre>SORTED ";
print_r($value);
echo "</pre>";

function sort_obj_arr(& $arr, $sort_field, $sort_direction)
{
    $sort_func = function($obj_1, $obj_2) use ($sort_field, &$sort_direction)
    {
        if ($sort_direction == SORT_ASC) {
            return strnatcasecmp($obj_1->$sort_field, $obj_2->$sort_field);
        } else {
            return strnatcasecmp($obj_2->$sort_field, $obj_1->$sort_field);
        }
    };
    usort($arr, $sort_func);

}

У меня есть массив из моего контроллера, но не могу заставить работать usort: я получаю либо: usort() ожидает, что параметр 1 будет массивом, заданным объектом или нулевым.

$array = array($this->data);
print_r($array);

array(1) { 
[0]=> object(SimpleXMLElement)#280 (1) { ["reservation"]=> array(3) { 
        [0]=> object(SimpleXMLElement)#287 (28) { 
            ["reservation_id"]=> string(7) "8644894" 
            ["event_start_dt"]=> string(25) "2013-12-02T12:00:00-08:00" 
            ["event_end_dt"]=> string(25) "2013-12-02T13:00:00-08:00" 
            ["event_id"]=> string(6) "314147" 
            ["event_name"]=> string(24) "Practice" 
            ["room_id"]=> string(3) "202"
        }
        [1]=> object(SimpleXMLElement)#288 (28) { 
            ["reservation_id"]=> string(7) "8595185" 
            ["event_start_dt"]=> string(25) "2013-12-02T08:00:00-08:00" 
            ["event_end_dt"]=> string(25) "2013-12-02T09:00:00-08:00" 
            ["event_id"]=> string(6) "314005"
            ["event_name"]=> string(24) "Meeting" 
            ["room_id"]=> string(3) "207"
        }
        [2]=> object(SimpleXMLElement)#289 (28) { 
            ["reservation_id"]=> string(7) "8718654" 
            ["event_start_dt"]=> string(25) "2013-12-02T10:00:00-08:00" 
            ["event_end_dt"]=> string(25) "2013-12-02T11:00:00-08:00" 
            ["event_id"]=> string(6) "315811" 
            ["event_name"]=> string(20) "Maintenance" 
            ["room_id"]=> string(3) "202"
        }
    } }

Запрос на print_r:

SimpleXMLElement Object
(
    [reservation] => Array(3)
        (
            [0] => SimpleXMLElement Object
                (
                    [reservation_id] => 8604174
                    [event_start_dt] => 2013-12-31T06:00:00-08:00
                    [event_end_dt] => 2013-12-31T08:00:00-08:00
                    [event_id] => 314147
                    [event_name] => Practice
                    [room_id] => 202
                 )
         [1] => SimpleXMLElement Object
                (
                    [reservation_id] => 8604177
                    [event_start_dt] => 2013-12-31T05:00:00-08:00
                    [event_end_dt] => 2013-12-31T06:00:00-08:00
                    [event_id] => 314150
                    [event_name] => Meeting
                    [room_id] => 216
                 )
         [2] => SimpleXMLElement Object
                (
                    [reservation_id] => 8604189
                    [event_start_dt] => 2013-12-31T10:00:00-08:00
                    [event_end_dt] => 2013-12-31T11:00:00-08:00
                    [event_id] => 314150
                    [event_name] => Maintenance
                    [room_id] => 220
                 )
)
)

$arrTimes = xml2array($array->reservation);

var_dump($arrTimes)

array(5) { 
["reservation_id"]=> string(7) "8604175" 
["event_start_dt"]=> string(25) "2014-01-02T06:00:00-08:00" 
["event_end_dt"]=> string(25) "2014-01-02T08:00:00-08:00" 
["event_id"]=> string(6) "314147" 
["event_name"]=> string(24) "Practice" 
}

person sloga    schedule 02.12.2013    source источник
comment
usort() должен работать с отдельным массивом, что именно вы пробовали?   -  person ThW    schedule 03.12.2013
comment
Главное помнить, что SimpleXMLElement — это не массив, а объект (и var_dump вводит в заблуждение). Его нельзя отсортировать напрямую, поскольку он представляет реальную структуру XML-файла, а не просто копию его данных.   -  person IMSoP    schedule 03.12.2013
comment
Я добавил один из методов usort, которые пробовал. Я не могу получить данные с помощью $array['reservation'][$i]['event_start_dt'], но могу получить их с помощью $array-›event_start_dt.   -  person sloga    schedule 04.12.2013
comment
см. принятый ответ в этом сообщении: stackoverflow.com/questions/15604459/   -  person michi    schedule 04.12.2013
comment
@michi Я получаю сообщение об ошибке в этой строке кода: $sort_func = function($obj_1, $obj_2) use ($sort_field, $sort_direction)   -  person sloga    schedule 05.12.2013
comment
@michi также получает ошибку usort() ожидает, что параметр 1 будет массивом, задано значение NULL. $arr равно NULL. Мои данные указаны выше, поэтому я не отформатировал их в xml, например ‹?xml version=1.0 encoding=UTF-8?› ‹root›‹reservation›‹/reservation›‹/root›‹/xml› на данный момент, все, с чем я могу работать, это массив $ выше   -  person sloga    schedule 05.12.2013
comment
возможный дубликат Reference: все основные способы сортировки массивы и данные в PHP   -  person Ja͢ck    schedule 06.12.2013
comment
@sloga: извините, я не видел, чтобы у вас был массив, а не XML.   -  person michi    schedule 08.12.2013
comment
все еще нужно отсортировать мой массив, используя event_start_dt вместо reservation_id. Пробовал usort, но $a и $b всегда равны.   -  person sloga    schedule 18.12.2013
comment
дайте мне ваш результат print_r вместо var_dump   -  person Padmanathan J    schedule 31.12.2013
comment
@NathanSrivi отредактировал мой вопрос, включив в него print_r, или я могу вставить его в чат/электронную почту для вас. Спасибо.   -  person sloga    schedule 31.12.2013


Ответы (4)


Прежде чем вы сможете отсортировать данные, вам нужно создать массив, содержащий в качестве значений отдельные элементы, которые вы хотите отсортировать. Из ваших выходных данных отладки это несколько узлов <reservation> во входном XML, которые являются дочерними элементами элемента, представленного $array/$this->data в этих образцах (не имеет значения, является ли это корнем документа или нет, SimpleXML не имеет объекта Document ).

Ваши выходные данные print_r и var_dump показывают, что в настоящее время у вас нет такого массива, а есть только объект SimpleXML:

  • Ваш первый пример показывает, что var_dump($array) дает вывод, начинающийся с object(SimpleXMLElement)#275 (1) { — игнорируйте слово array дальше, это просто то, как var_dump отображает внутреннюю часть объекта.
  • Позже у вас есть print_r($array);, начинающееся с array(1) {, но это только потому, что вы обернули реальные данные в одноэлементный массив в строке выше ($array = array($this->data);), и этот один элемент ($array[0]) отображается как object(SimpleXMLElement)#280 (1) { ....

Обратите внимание, что нет необходимости идти дальше и преобразовывать все внутренние объекты SimpleXML в массивы — вам просто нужен сортируемый список, содержащий интересующие вас элементы. Лично я бы использовал простой и явный цикл foreach для максимальной читаемости кода. , хотя есть и более "умные" решения.

Когда у вас есть сортируемый список, вам нужна функция обратного вызова для usort, которая сравнивает два его параметра. Предпринятая вами попытка верна, но относится к несуществующей (в этой функции) переменной $array; значения, которые вам нужно сравнить, являются аргументами функции, которые вы назвали $a и $b — в частности, вы хотите сравнить strtotime($a->event_start_dt) с strtotime($b->event_start_dt).

Вы также можете сделать функцию намного проще, потому что она следует распространенному заблуждению, что возвращаемое значение обратного вызова должно быть -1, 0 или 1. На самом деле это может быть любое целое число, и имеет значение только его знак — возврат -42 будет иметь тот же эффект, что и возврат -999, а именно размещение элемента $a перед $b в результирующем массиве.

Я не могу легко привести проверенный пример, потому что вы не предоставили базовый XML для воспроизведения вашего ввода (например, echo $this->data->asXML();), но основной подход, который я бы выбрал, будет следующим:

// Start with an empty array, and add all the items we're interested in to it
$sortable_array = array();
// Loop over all <reservation> children of the SimpleXML object $this->data
// See http://php.net/manual/en/simplexml.examples-basic.php
foreach ( $this->data->reservation as $reservation_node )
{
    // Add the individual node to our array
    $sortable_array[] = $reservation_node;
}

// Now let's sort out the callback function for the sorting
// This could also be an anonymous function passed directly to usort
function sort_callback_event_start($a, $b)
{
    // $a and $b are both items in our $sortable_array, and therefore
    // <reservation> nodes which we expect to each have a child
    // called <event_start_dt>

    // If we convert both dates to Unix timestamps, we have two integers 
    // to compare, and a simple subtraction gives the desired result
    // of <0, 0, or >0 as documented at http://php.net/usort

    return
        strtotime((string)$a->event_start_dt)
        -
        strtotime((string)$b->event_start_dt);
}

// Now, we have everything we need to do the actual sorting
usort($sortable_array, 'sort_callback_event_start');
// $sortable_array is now sorted as desired! :D

// Note that the items within it are still SimpleXML objects, 
// so you still need to access their properties to do something useful
// e.g. some HTML output with the names listed in order of their start date:
echo '<ol>';
foreach ( $sortable_array as $reservation_node )
{
    echo '<li>', (string)$reservation_node->event_name, '</li>';
}
echo '</ol>';
person IMSoP    schedule 03.01.2014

Используйте array_multisort

            foreach ($rez->reservation as $value)
            { 
                     $dateTime[] = $value->event_start_dt;
            }

           array_multisort($dateTime,SORT_ASC,SORT_STRING,$rez->reservation);   
           echo "<pre>";
           print_r($rez->reservation);

Проверь это. это мой код

<?php
        $myarray=array(
                    0 => array
                        (
                            'dateTime' => '2013-12-02T10:00:00-08:00',
                            'chanl1' => '20.10',
                            'chanl2' => '45.4',
                            'chanl3' => '',
                        ),

                    1 => array
                        (
                            'dateTime' => '2013-12-02T11:00:00-08:00',
                            'chanl1' => '20.11',
                            'chanl2' => '45.4',
                            'chanl3' => '',
                        ),
                  2 => array
                        (
                            'dateTime' => '2013-12-02T12:00:00-08:00',
                            'chanl1' => '20.12',
                            'chanl2' => '33.8',
                            'chanl3' => '',
                        ),

                    3 => array
                        (
                            'dateTime' => '2013-12-02T09:00:00-08:00',
                            'chanl1' => '20.9',
                            'chanl2' => '33.9',
                            'chanl3' => ''
                        ));

            foreach($myarray as $c=>$key) {
                    $dateTime[] = $key['dateTime'];                      
            }           


        array_multisort($dateTime,SORT_ASC,SORT_STRING,$myarray);   
        echo "<pre>";
        print_r($myarray);
        ?>

Выход:

Array
(
    [0] => Array
        (
            [dateTime] => 2013-12-02T09:00:00-08:00
            [chanl1] => 20.9
            [chanl2] => 33.9
            [chanl3] => 
        )

    [1] => Array
        (
            [dateTime] => 2013-12-02T10:00:00-08:00
            [chanl1] => 20.10
            [chanl2] => 45.4
            [chanl3] => 
        )

    [2] => Array
        (
            [dateTime] => 2013-12-02T11:00:00-08:00
            [chanl1] => 20.11
            [chanl2] => 45.4
            [chanl3] => 
        )

    [3] => Array
        (
            [dateTime] => 2013-12-02T12:00:00-08:00
            [chanl1] => 20.12
            [chanl2] => 33.8
            [chanl3] => 
        )

)

FIDDLE

person Padmanathan J    schedule 02.01.2014
comment
получить ошибку при применении этого метода. Ожидается, что аргумент №4 будет массивом или флагом сортировки в этой строке: array_multisort($dateTime,SORT_ASC,SORT_STRING,$rez-›reservation); - person sloga; 03.01.2014
comment
@sloga Ваша бронь массивная или нет?? я имею в виду $rez-›бронирование - person Padmanathan J; 03.01.2014

Я бы просто превратил его в массив, используя эту функцию (пример функции из php.net). Но обратите внимание, что это не сортирует XML, а сортирует новый массив

/**
* function xml2array
*
* This function is part of the PHP manual.
*
* The PHP manual text and comments are covered by the Creative Commons 
* Attribution 3.0 License, copyright (c) the PHP Documentation Group
*
* @author  k dot antczak at livedata dot pl
* @date    2011-04-22 06:08 UTC
* @link    http://www.php.net/manual/en/ref.simplexml.php#103617
* @license http://www.php.net/license/index.php#doc-lic
* @license http://creativecommons.org/licenses/by/3.0/
* @license CC-BY-3.0 <http://spdx.org/licenses/CC-BY-3.0>
*/
function xml2array ( $xmlObject, $out = array () )
{
  foreach ( (array) $xmlObject as $index => $node )
    $out[$index] = ( is_object ( $node ) ) ? xml2array ( $node ) : $node;

   return $out;
 }

и передайте ему XMLObject

$arrTimes = xml2array(YourSimpleXMLElement);

а затем используйте исходную функцию usort для нового массива

 function sortByTime($a, $b){
    $a = strtotime($a['event_start_dt']);
    $b = strtotime($b['event_start_dt']);
    if ($a==$b) 
       return 0;
    return ($a < $b) ? -1 : 1;
 }

Ну наконец то

usort($arrTimes, 'sortByTime');
person josephtikva1    schedule 31.12.2013
comment
Я не совсем понимаю это... Я получаю неопределенный индекс для $a = strtotime($a['event_start_dt']); $b = strtotime($b['event_start_dt']); при изменении на $a=strtotime($arrTimes['event_start_dt']); $b = strtotime($arrTimes['event_start_dt']); Я получаю неопределенную переменную. У меня есть $arrTimes = xml2array($array-›reservation); над функцией sortByTime. - person sloga; 03.01.2014

Вы должны преобразовать frist в xml в массив, используя json encode decode

$xml_array = json_decode(json_encode((массив)$xml), ИСТИНА);

вы получите список массивов .... чем вы можете извиниться по дате, используя функцию strtotime.

person Ravi D    schedule 03.01.2014