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