Having solved a chain of other issues with this XML parsing project (thanks to a lovely SO user), I'm now stuck at the next hurdle. I'm loading SimpleXML into an array, sorting it and then echoing it into the page with grouping for the data.
I can get my group headings to display, sorted correctly, however when I try to add the sub-group data (which requires xpath to match attributes to the parent group), my output is just the first group heading. Not sure if it's the way I'm mixing array results with xpath or not but hopefully somebody here can spot the issue straight away.
Here is my 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>
I am looking to sort the group headers by yearname in ascending order and the subgroup results by eptnumber in ascending order.
Here is my PHP code so far:
<?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>";
}
}
?>
This is my output before any sorting:
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
This is how it SHOULD appear:
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
Many thanks in advance if you can spot the problem or suggest improvements. Obviously this is sample/example data based on the same structure.
Sam
UPDATE
Still haven't managed to get this quite right and unable to spot which point I'm going wrong at. Best guess would be the xpath within the foreach statement, but I'm not familiar enough with this type of code to be able to spot it.
I've switched out xsort for sort_obj_arr as I assume it's a somewhat better function. Unfortunately I'm getting the exact same results as before. Here's my updated code:
<?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>";
}
}
?>