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?

3 Answers 3

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.

1
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) { ...
5
  • 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) Commented Oct 13, 2011 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 :) Commented Oct 13, 2011 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) { ... Commented Oct 13, 2011 at 21:07
  • @ChrisGoddard you should edit that code into your answer, rather than leaving it as a comment. Commented Oct 13, 2011 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. Commented Oct 18, 2011 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;
}
4
  • 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 <review> and <translation> 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. Commented Oct 14, 2011 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. Commented Oct 14, 2011 at 17:31
  • Arg... always something! I just realised it's only showing the first <review> - 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 <work name=""> to the array. Commented Oct 16, 2011 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. Commented Oct 17, 2011 at 16:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.