Link to home
Start Free TrialLog in
Avatar of maccaj51
maccaj51Flag for Afghanistan

asked on

I need to update this xml / php script with new features...

This script works brilliantly:

<?php

// A little class for collect data together
//
class SnowData {

     public $title;
     public $description;
     public $giud;
     public $pubDate;

     // Constructor
     //
     function __construct( $t, $d, $g, $p ) {
          $this->title = $t;
          $this->description = $d;
          $this->guid = $g;
          $this->pubDate = $p;
     }

     
     // Pull the base depth using a regex
     //
     function getDepth() {
          preg_match('~^.*Base Depth:\s+([0-9]+)\s+cm\s*$~', $this->description, $matches );
          return $matches[1];
     }
     
}



     // A custom sort based on snow depth
     //
     function snowDepthSort( $a, $b ) {

          $aDepth = $a->getDepth();
          $bDepth = $b->getDepth();

          if ( $aDepth < $bDepth )
               return 1;
          else
               if ( $aDepth > $bDepth )
                    return -1;

          return 0;                    
     }






     

     // Load the XML
     //
     $xml = simplexml_load_file("http://www.onthesnow.co.uk/france/snow.rss");


     // Array to collect the data
     //
     $arr = array();


     // Process the XML
     //
     foreach( $xml->channel->item as $anEntry ) {
          $arr [] = new SnowData(
                                   (string) $anEntry->title,
                                   (string) $anEntry->description,
                                   (string) $anEntry->guid,
                                   (string) $anEntry->pubDate
                                );
     }



     // Sort the array into descending snowdepth
     //
     uasort( $arr, 'snowDepthSort' );


     // Keep only the first 10
     //
     $arr = array_slice( $arr, 0, 10 );



     // Produce a table
     //
     $tab = "<table>\n";

     foreach( $arr as $aSnowObj ) {
          $tab .= "<tr>\n";
          $tab .=    "<td>\n";
          $tab .=        $aSnowObj->title;
          $tab .=    "</td>\n";
          $tab .=    "<td>\n";
          $tab .=        $aSnowObj->getDepth();
          $tab .=    "</td>\n";
          $tab .= "</tr>\n";
         
     }
     
     $tab .= "</table>\n";

     echo $tab;
?>


Produced the following output

La Clusaz               310
Oz-en-Oisans               270
Les Carroz               240
Les 2 Alpes               190
Morzine               180
Valmorel               180
Arêches - Beaufort       170
Peisey Vallandry       160
Courchevel             145
Les Arcs               133

BUT NOW

i need to be able to load multiple feeds....

feed://www.onthesnow.co.uk/austria/soll/snow.rss
feed://www.onthesnow.co.uk/austria/st-anton-am-arlberg/snow.rss
feed://www.onthesnow.co.uk/france/valloire/snow.rss

Then take the country from them and produce this output

Austria   La Clusaz               310 - top result in a different .class in html output
Austria   Oz-en-Oisans               270
Austria   Les Carroz               240
France   Les 2 Alpes               190
France   Morzine               180
France   Valmorel               180
France   Arêches - Beaufort       170
France   Peisey Vallandry       160
France   Courchevel             145
France   Les Arcs               133

Many Thanks
Avatar of Beverley Portlock
Beverley Portlock
Flag of United Kingdom of Great Britain and Northern Ireland image

OK, try the attached. I have done the following

- Extended the class to hold the location and added an extra parameter to the constructor

- Modified the sort function to have a composite field beased on location and snow depth

- Added a new function by moving some code into a function body. This now collects individual RSS feed and adds them to the array which is passed by REFERENCE (so you can get the changes back). The array slicing (limiting to 10 entries) is now in here also.

- Added a "location" cell to the table and stuck a border on it so that I could be sure I had 3 columns (not obvious with the test data)

Unfortunately the feeds you supplied are all for closed resorts so I've used the ones from yesterday for testing
<?php

ini_set('display_errors',1); error_reporting(E_ALL);


// A little class for collect data together
//
class SnowData {

     public $location;
     public $title;
     public $description;
     public $giud;
     public $pubDate;

     // Constructor
     //
     function __construct( $l, $t, $d, $g, $p ) {
          $this->location = $l;
          $this->title = $t;
          $this->description = $d;
          $this->guid = $g;
          $this->pubDate = $p;
     }

     
     // Pull the base depth using a regex
     //
     function getDepth() {
          preg_match('~^.*Base Depth:\s+([0-9]+)\s+cm\s*$~', $this->description, $matches );
          return $matches[1];
     }
     
}




     function collectRSS( $location, $feedUrl, & $arr ) {
     
          // Load the XML
          //
          $xml = simplexml_load_file( $feedUrl );

          $wrkArr = array();

          // Process the XML
          //
          foreach( $xml->channel->item as $anEntry ) {
               $wrkArr [] = new SnowData(
                                        $location,
                                        (string) $anEntry->title,
                                        (string) $anEntry->description,
                                        (string) $anEntry->guid,
                                        (string) $anEntry->pubDate
                                   );
          }


          // Keep only the first 10
          //
          $wrkArr = array_slice( $wrkArr, 0, 10 );

          $arr = array_merge( $arr, $wrkArr );    

     }


     
     

     // A custom sort based on snow depth
     //
     function snowDepthSort( $a, $b ) {

          $aDepth = sprintf("%s%07d", $a->location, $a->getDepth() );
          $bDepth = sprintf("%s%07d", $b->location, $b->getDepth() );

          if ( $aDepth < $bDepth )
               return 1;
          else
               if ( $aDepth > $bDepth )
                    return -1;

          return 0;                    
     }






     

     // Array to collect the data
     //
     $arr = array();


     // Collect all the data
     //


     collectRSS( "Austria other", "http://www.onthesnow.co.uk/austria/snow.rss", $arr );
     collectRSS( "France other", "http://www.onthesnow.co.uk/france/snow.rss",  $arr );
     
     collectRSS( "Austria", "http://www.onthesnow.co.uk/austria/soll/snow.rss",  $arr );
     collectRSS( "Austria", "http://www.onthesnow.co.uk/austria/st-anton-am-arlberg/snow.rss", $arr );
     collectRSS( "France", "http://www.onthesnow.co.uk/france/valloire/snow.rss",  $arr );



     // Sort the array into descending snowdepth
     //
     uasort( $arr, 'snowDepthSort' );



     // Produce a table
     //
     $tab = "<table border='1'>\n";

     foreach( $arr as $aSnowObj ) {
          $tab .= "<tr>\n";
          $tab .=    "<td>\n";
          $tab .=        $aSnowObj->location;
          $tab .=    "</td>\n";
          $tab .=    "<td>\n";
          $tab .=        $aSnowObj->title;
          $tab .=    "</td>\n";
          $tab .=    "<td>\n";
          $tab .=        $aSnowObj->getDepth();
          $tab .=    "</td>\n";
          $tab .= "</tr>\n";
          
     }
     
     $tab .= "</table>\n";

     echo $tab;

?>

Open in new window

You can lose the ini_set(.... line just after the <?php tag - left over from my tests
Avatar of maccaj51

ASKER

Thats seems to work brilliantly... do u have a solution to the other part... with regards to add a different css class to the top row?
NOt sure if it will work in all browsers, but try changing the table code to

     // Produce a table
     //
     $tab = "<table border='1'>\n";

     $topRowClass = " class='topRow'";
     foreach( $arr as $index => $aSnowObj ) {

          $tab .= "<tr$topRowClass>\n";
          $tab .=    "<td>\n";
          $tab .=        $aSnowObj->location;
          $tab .=    "</td>\n";
          $tab .=    "<td>\n";
          $tab .=        $aSnowObj->title;
          $tab .=    "</td>\n";
          $tab .=    "<td>\n";
          $tab .=        $aSnowObj->getDepth();
          $tab .=    "</td>\n";
          $tab .= "</tr>\n";

          $topRowClass = "";
     }
 

and then add this to your style sheet

.topRow { font-weight: bold; }
just comes up blank...

is there a way to run the script twice...

i.e run it once and output a table with first result - and class it .topresult

and then run the script again excluding the top result??

Thanks for all your help your scripts are so clear!
Put this at the top after the <?php tag like so

<?php

ini_set('display_errors',1); error_reporting(E_ALL & ~E_NOTICE);

and run it again. Do you get any error messages

If you want to use .topresult rather than .topRow then change this

$topRowClass = " class='topRow'";

to this

$topRowClass = " class='topresult'";

I got it to work... it was me being an idiot haha!

but it doesnt seem to put in descending numerical order anymore....?
It is in descending order within *location*. If you want it in just descending order regardless of location then use the earlier sort routine. I think I misunderstood your requirements.

A little "bug" is that I am only keeping the first 10 results for each location rather than the BEST 10 results, so if it is to be the best 10 results REGARDLESS of location then use this code for collectRSS


     function collectRSS( $location, $feedUrl, & $arr ) {
     
          // Load the XML
          //
          $xml = simplexml_load_file( $feedUrl );

          // Process the XML
          //
          foreach( $xml->channel->item as $anEntry ) {
               $arr [] = new SnowData(
                                        $location,
                                        (string) $anEntry->title,
                                        (string) $anEntry->description,
                                        (string) $anEntry->guid,
                                        (string) $anEntry->pubDate
                                   );
          }


     }



Use the previous sort comparison



     // A custom sort based on snow depth
     //
     function snowDepthSort( $a, $b ) {

          $aDepth = $a->getDepth();
          $bDepth = $b->getDepth();

          if ( $aDepth < $bDepth )
               return 1;
          else
               if ( $aDepth > $bDepth )
                    return -1;

          return 0;                    
     }






and put the array slice back after the sort


     // Sort the array into descending snowdepth
     //
     uasort( $arr, 'snowDepthSort' );
     $arr = array_slice( $arr, 0, 10);


Sorry for the confusion....
     
ASKER CERTIFIED SOLUTION
Avatar of Beverley Portlock
Beverley Portlock
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ABSOLUTE HERO! This is guy is the best.... complete solution... easy to understand!!!!!!
Thanks for the praise! Better than points!!

;-)

Actually, I've been mulling this question over in my mind as I've been chatting with other experts here in the PHP forum. I would like to use it as a basis for an article using PHP classes as a data grouping andhandling mechanism. Would you mind if I used the code as a basis? I'd include an aknowledgment to yourself "maccaj51" and a link  to the original question.
By all means! the website it will be used on is <a href="http://www.snow2moro.com>Skiing & Snowboarding News</a> !! we're relaunching soon!! we may need your help in the future... and ive got no issues with any accreditation that you require!!
By all means! the website it will be used on is <a href="http://www.snow2moro.com">Skiing & Snowboarding News</a> !! we're relaunching soon!! we may need your help in the future... and ive got no issues with any accreditation that you require!!
I'm not sure the EE guidelines will let me link to a live site, but I would like to link to this article and the previous one as examples of how an OO class can simply the extension of a programming task involving data collection and selection.

Never fancied skiing myself.... I prefer my fun to have wings on it. http://www.youtube.com/watch?v=0uobI0cF3UI (not me in there I should point out)
BTW - I forgot to say "thanks" for letting me use the code. I'll post an update on here when I push the article up.
maccaj51 - I have converted this question into an article which you can read at

https://www.experts-exchange.com/articles/Web_Development/Web_Languages-Standards/PHP/Using-PHP-classes-to-group-data-in-memory.html

Thanks again for an interesting problem and for allowing me to use it.