Вывод из отсортированного массива с помощью SimpleXML, xsort и xpath в PHP

1

Решив цепочку других проблем с этим проектом анализа 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>";
    }
}

?>
  • 0
    Я предполагаю, что мой xpath, ссылающийся на массив, как-то неверен, но я не очень хорошо знаком с кодом, чтобы иметь возможность обнаруживать ошибки, так как я вроде как выдумываю это. Обновили мой вопрос.
  • 0
    время научиться отлаживать ваш код. Ваше предположение совершенно верно, вы получаете сообщения об ошибках? см. eval.in/468492 . Вы сортируете ep слишком рано, вам нужно отсортировать их после выбора соответствующих.
Показать ещё 2 комментария
Теги:
arrays
xpath
sorting

1 ответ

1
Лучший ответ

Ваш код

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 -object.

Нет смысла получать отсортированный список всех <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>"; 
    }
}

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

  • 0
    Я знаю, что мы не должны благодарить людей в этих комментариях, но я чувствую грубость, не показывая мою благодарность. Просто хочу сказать спасибо за вашу прекрасную помощь! :)
  • 0
    Спасибо, я рад, что могу поделиться.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню