Выход из отсортированного массива с SimpleXML, xsort и xpath в PHP

Решив цепочку других проблем с этим проектом анализа XML (благодаря прекрасному пользователю SO), я теперь застрял в следующем препятствии. Я загружаю SimpleXML в массив, сортируя его, а затем повторяю его на странице с группировкой данных.

Я могу отображать заголовки своих групп, отсортированные правильно, однако, когда я пытаюсь добавить данные подгруппы (для которых требуется, чтобы xpath соответствовал атрибутам родительской группе), мой вывод – это только первый заголовок группы. Не уверен, что это то, как я смешиваю результаты массива с xpath или нет, но, надеюсь, кто-то здесь может сразу выявить проблему.

Вот мой XML:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE besteplist SYSTEM "example.dtd"> <besteplist> <yearlist> <year yid="y1"> <yearname>1995, Season 3</yearname> </year> <year yid="y2"> <yearname>1996, Season 4</yearname> </year> <year yid="y3"> <yearname>1997, Season 5</yearname> </year> <year yid="y4"> <yearname>1994, Season 2</yearname> </year> <year yid="y5"> <yearname>1993, Season 1</yearname> </year> </yearlist> <eplist> <ep yearid="y1" eid="e1"> <eptitle>The Third Episode</eptitle> <eptnumber>3</eptnumber> </ep> <ep yearid="y2" eid="e2"> <eptitle>Bla bla bla</eptitle> <eptnumber>21</eptnumber> </ep> <ep yearid="y2" eid="e3"> <eptitle>Rar rar rar</eptitle> <eptnumber>39</eptnumber> </ep> <ep yearid="y2" eid="e4"> <eptitle>Tra la la</eptitle> <eptnumber>45</eptnumber> </ep> <ep yearid="y3" eid="e5"> <eptitle>Donkey</eptitle> <eptnumber>126</eptnumber> </ep> <ep yearid="y1" eid="e6"> <eptitle>SHOULD APPPEAR AS FIRST ONCE SORTED</eptitle> <eptnumber>1</eptnumber> </ep> </eplist> </besteplist> 

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

Вот мой PHP-код:

 <?php $xml=simplexml_load_file("example.xml") or die("Error: Cannot create object"); function xsort(&$sorted_year, $child_name, $order=SORT_ASC) { $sort_proxy = array(); foreach ($sorted_year as $k => $node) { $sort_proxy[$k] = (string) $node->$child_name; } array_multisort($sort_proxy, $order, $sorted_year); } $sorted_year = $xml->xpath('/besteplist/yearlist/year'); xsort($sorted_year, 'yearname', SORT_ASC); $sorted_ep = $xml->xpath('/besteplist/eplist/ep'); xsort($sorted_ep, 'eptnumber', SORT_ASC); foreach ($sorted_year as $season) { echo "SEASON: " . $season->yearname . "<br>"; foreach ($sorted_ep->xpath("//ep[@yearid='$season[yid]']") as $episode) { echo "EPISODE TITLE: " . $episode->eptitle . PHP_EOL . "<br>"; echo "EPISODE NUMBER: " . $episode->eptnumber . PHP_EOL . "<br>"; echo PHP_EOL . "<br>"; } } ?> 

Это мой вывод перед любой сортировкой:

 SEASON: 1995, Season 3 EPISODE TITLE: The Third Episode EPISODE NUMBER: 3 EPISODE TITLE: SHOULD APPPEAR AS FIRST ONCE SORTED EPISODE NUMBER: 1 SEASON: 1996, Season 4 EPISODE TITLE: Bla bla bla EPISODE NUMBER: 21 EPISODE TITLE: Rar rar rar EPISODE NUMBER: 39 EPISODE TITLE: Tra la la EPISODE NUMBER: 45 SEASON: 1997, Season 5 EPISODE TITLE: Donkey EPISODE NUMBER: 126 SEASON: 1994, Season 2 SEASON: 1993, Season 1 

Вот как это ДОЛЖНО появиться:

 SEASON: 1993, Season 1 SEASON: 1994, Season 2 SEASON: 1995, Season 3 EPISODE TITLE: SHOULD APPPEAR AS FIRST ONCE SORTED EPISODE NUMBER: 1 EPISODE TITLE: The Third Episode EPISODE NUMBER: 3 SEASON: 1996, Season 4 EPISODE TITLE: Bla bla bla EPISODE NUMBER: 21 EPISODE TITLE: Rar rar rar EPISODE NUMBER: 39 EPISODE TITLE: Tra la la EPISODE NUMBER: 45 SEASON: 1997, Season 5 EPISODE TITLE: Donkey EPISODE NUMBER: 126 

Большое спасибо заранее, если вы можете обнаружить проблему или предложить улучшения. Очевидно, что это примеры / примеры данных, основанные на одной и той же структуре.

Сэм

ОБНОВИТЬ

Все еще не удалось получить это совершенно правильно и не смог определить, в какой точке я ошибаюсь. Наилучшая догадка – это xpath в инструкции foreach, но я недостаточно хорошо знаком с этим типом кода, чтобы его можно было определить.

Я отключил xsort для sort_obj_arr, поскольку я предполагаю, что это несколько лучшая функция. К сожалению, я получаю то же самое, что и раньше. Вот мой обновленный код:

 <?php $xml=simplexml_load_file("example.xml") or die("Error: Cannot create object"); 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); } $sorted_year = $xml->xpath('/besteplist/yearlist/year'); $field1 = 'yearname'; $direction1 = SORT_ASC; sort_obj_arr($sorted_year, $field1, $direction1); $sorted_ep = $xml->xpath('/besteplist/eplist/ep'); $field2 = 'eptnumber'; $direction2 = SORT_ASC; sort_obj_arr($sorted_ep, $field2, $direction2); foreach ($sorted_year as $season) { echo "SEASON: " . $season->yearname . "<br>"; foreach ($sorted_ep->xpath("//ep[@yearid='$season[yid]']") as $episode) { echo "EPISODE TITLE: " . $episode->eptitle . PHP_EOL . "<br>"; echo "EPISODE NUMBER: " . $episode->eptnumber . PHP_EOL . "<br>"; echo PHP_EOL . "<br>"; } } ?> 

Ваш код

 foreach ($sorted_ep->xpath("//ep[@yearid='$season[yid]']") as $episode) 

выдает ошибку

 Fatal error: Call to a member function xpath() on a non-object (...) 

потому что $sorted_ep – это массив, а не SimpleXml SimpleXml.

Нет смысла получать отсортированный список всех <ep> в вашем XML. Вам нужно выбрать эпизоды в течение определенного года , а затем отсортировать их:

 foreach ($sorted_year as $season) { echo "SEASON: " . $season->yearname . "<br><br>"; // first select episodes from a certain year $episodes = $xml->xpath("//ep[@yearid='$season[yid]']"); // then sort those sort_obj_arr($episodes, "eptnumber", SORT_ASC); // now iterate and echo foreach ($episodes as $episode) { echo " EPISODE TITLE: " . $episode->eptitle . "<br>"; echo " EPISODE NUMBER: " . $episode->eptnumber . "<br><br>"; } } на foreach ($sorted_year as $season) { echo "SEASON: " . $season->yearname . "<br><br>"; // first select episodes from a certain year $episodes = $xml->xpath("//ep[@yearid='$season[yid]']"); // then sort those sort_obj_arr($episodes, "eptnumber", SORT_ASC); // now iterate and echo foreach ($episodes as $episode) { echo " EPISODE TITLE: " . $episode->eptitle . "<br>"; echo " EPISODE NUMBER: " . $episode->eptnumber . "<br><br>"; } } на foreach ($sorted_year as $season) { echo "SEASON: " . $season->yearname . "<br><br>"; // first select episodes from a certain year $episodes = $xml->xpath("//ep[@yearid='$season[yid]']"); // then sort those sort_obj_arr($episodes, "eptnumber", SORT_ASC); // now iterate and echo foreach ($episodes as $episode) { echo " EPISODE TITLE: " . $episode->eptitle . "<br>"; echo " EPISODE NUMBER: " . $episode->eptnumber . "<br><br>"; } } 

см. в действии: https://eval.in/468571