2

This is an excerpt from the xml feed I'm accessing:

xml feed

And here's my current code:

$file = file_get_contents('feed.xml');
$file = preg_replace('/(<role[^>]+>)([^<]+)/si', '$1', $file);
$xml = new SimpleXMLElement($file);

$search_term = preg_replace('/[,.\/\\\(\)\[\]\{\}`~!@#\$%\^&*;:\'"\-_<>]*/is', '', $_GET['work']);

$productions = $xml->xpath('//production');
?>

<table width="300px" cellspacing="5px" cellpadding="5px" border="1px" >
<tr>
<th>year</th>
<th>company</th>
</tr>

<?php
foreach($productions as $prod) {

    $prod_attrs = $prod->attributes();
    $prod_date = $prod_attrs->startdate;

    echo "<tr><td>", $prod_date, "</td><td>", html_encode($prod_attrs->company), "</td></tr>";


    }               
?>

</table>

This is the output: table

My question is, how do I get the table to sort in descending numerical order (i.e. most recent year first)? I've searched here and tried to understand the sort() function (e.g. this answer), but it's a bit beyond me still and I can't figure out how to get that to work here.


UPDATE

I'm playing around with @Chris Goddard's answer below..

This is the code I've got, but it doesn't seem to have done the trick:

<?php


    function html_encode($var){

    $var = html_entity_decode($var, ENT_QUOTES, 'UTF-8');
    $var = htmlentities($var, ENT_QUOTES, 'UTF-8');
    return $var;
}


$file = file_get_contents('feed.xml');
$file = preg_replace('/(<role[^>]+>)([^<]+)/si', '$1', $file);
$xml = simplexml_load_string($file);
$json = json_encode($xml); 
$array = json_decode($json,TRUE); 


$search_term = preg_replace('/[,.\/\\\(\)\[\]\{\}`~!@#\$%\^&*;:\'"\-_<>]*/is', '', $_GET['work']);


$works = $xml->xpath('//work');

foreach($works as $work) {
$Productions = $work->xpath('./production');

$Sorter = array();

foreach ($Productions as $prod) {

$prod_attrs = $prod->attributes();
    $Sorter[$key] = $prod_attrs->startdate;
array_multisort($Sorter, SORT_DESC, $Productions);
  }
}
echo "<pre>".print_r($works, true)."</pre>";
?>

What am I doing wrong?

Community
  • 1
  • 1
Findo
  • 87
  • 1
  • 3
  • 8

3 Answers3

1

array_multisort will do the trick

you put an array in the first one (which has the keys of each element, and the sorting value, the direction then the big array)

Edit

$Productions = json_decode(json_encode((array) simplexml_load_string($file)), 1);
$Sorter = array();

foreach ($Productions as $Key => $prod)
    $Sorter[$Key] = $prod->attributes->startdate;
array_multisort($Sorter, SORT_DESC, $Productions);

foreach ($Productions as $prod) { ...
topherg
  • 4,203
  • 4
  • 37
  • 72
  • sorry, a real beginner here.. would you mind explaining that a little more for me, please? (I can't really change the xml file btw.. well I could, but it would defeat the purpose of using this particular one) – Findo Oct 13 '11 at 21:00
  • create a new array called Sorter, then you do a foreach ($products as $key => $product) on the XML array (do a search for XML2Array and you should get a few results). In the foreach, you do something like Sorter[$Key] = and then the value you want to have it sorted by, in this case the year. Then finally, do array_multisort(Sorter, SORT_DESC, $Products); then a final foreach around $Products and its all sorted. Hope that helps dude :) – topherg Oct 13 '11 at 21:04
  • here's some code: $Productions = json_decode(json_encode((array) simplexml_load_string($file)), 1); $Sorter = array(); foreach ($Productions as $Key => $prod) $Sorter[$Key] = $prod->attributes->startdate; array_multisort($Sorter, SORT_DESC, $Productions); foreach ($Productions as $prod) { ... – topherg Oct 13 '11 at 21:07
  • @ChrisGoddard you should edit that code into your answer, rather than leaving it as a comment. – ben Oct 13 '11 at 21:19
  • @ChrisGoddard - I've edited my question with an update of how I tried (and failed) to implement your suggestion.. any thoughts? Thanks. – Findo Oct 18 '11 at 20:24
1

you can place the values in an array, then use usort to sort by a user defined function.

And notice that the elements are cast to string when they are set in the array. Comparing them as the XML objects they are isn't what you want.

A little explanation:

First I'm placing the XML data into an array, just because the data is easier to work with that way.

Then, I sort the array based on my custom function date_sort. Looking at the documentation for usort you see:

The comparison function must return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.

So, because you want to sort by date desc, if the dates are equal then the sort order is also equal(return 0), if the date is later it should be earlier in the list (return -1), and if the date is greater it should be later in the list (return 1)

Then you just traverse through the array printing as you go.

If you want to use additional data, just place it in the array in the first loop.

$production_array = array();
foreach($productions as $prod) {

    $prod_attrs = $prod->attributes();
    $prod_date = $prod_attrs->startdate;
    $production_array[] = array(
        'date'=>(string) $prod_date,
        'company'=>(string) $prod_attrs->company,
        'review_en'=>(string) $prod->review['quote'],
        'review_de'=>(string) $prod->review->translation
    );
}
usort($production_array, 'date_sort');

foreach($production_array as $production) {
    echo "<tr><td>", $production['date'], "</td><td>", html_encode($production['company']), "</td><td>",$production['review_en'], "</td></tr>";
}

function date_sort($a, $b) {
    if($a['date'] == $b['date']) return 0;
    return $a['date'] > $b['date'] ? -1 : 1;
}
ben
  • 1,946
  • 2
  • 18
  • 26
  • Thanks! That did the trick (still trying to understand what you've done to be fair). Can I go one more step...? I tried then to loop through and pull out the and data (ultimately I want to display a list of reviews with most recent first) but couldn't get that work.. I also tried putting it into the array, but as I mentioned, still not sure how that works.. any ideas how I might use what you've already shown me and pull out that other data? Thanks. – Findo Oct 14 '11 at 14:42
  • @Findo I've edited my answer to show you how to add review/translation to the array. And added a little explanation of what I did. Let me know if it's still not clear. – ben Oct 14 '11 at 17:31
  • Arg... always something! I just realised it's only showing the first - some of the entries have multiple reviews. Will they need to be in an array to? I've been playing around and can't seem to figure it out.. I also couldn't figure out how to add to the array. – Findo Oct 16 '11 at 16:46
  • I would suggest posting another question asking for some help working with XML and arrays. Or better yet, search for already answered questions, and apply them to your scenario. – ben Oct 17 '11 at 16:27
1

I dont understand half of that code (what's all the regex for?), but to achieve desired sorted table you can simply do:

$profile = simplexml_load_file('http://andrewfinden.com/test/feed.xml');
$productions = $profile->xpath(
    '/profile/repertoire/composer/work/role/production'
);

to load the XML and get the list of all productions as they appear in the XML. To sort them you can use a custom sort:

usort($productions, function($a, $b) {
    return $b['startdate'] - $a['startdate'];
});

which will compare the startdates of the simplexml elements and sort them in descending order. And then it's only a matter of just iterating the productions:

<table>
    <thead>
        <tr>
            <th>Year</th>
            <th>Company</th>
        </tr>
    </thead>
    <tbody>
    <?php foreach ($productions as $production): ?>
        <tr>
            <td><?php echo htmlspecialchars($production['startdate'])?></td>
            <td><?php echo htmlspecialchars($production['company'])?></td>
        </tr>
    <?php endforeach; ?>
    </tbody>
</table>

See demo

Also see this demo for your additional requests in chat, e.g. limit productions to those with a review and sorting works by production startdate.

Community
  • 1
  • 1
Gordon
  • 312,688
  • 75
  • 539
  • 559
  • 1
    Great - thank-you. You've given me the tools to finally show exactly what I wanted: http://andrewfinden.com/test/array_test.php :) – Findo Oct 19 '11 at 14:00