Search code examples
phpxmlxpathsimplexml

PHP / XML - distinct values & nested loops


I'm in the process of upgrading an old asp Movie theater site to php. It needs to pull its movie schedule data from an xml feed.

This is schedule.xml:

<showtimes>
  <movie>
    <name>BROOKLYN</name>
    <movieId>BR30015</movieId>
    <showtime>
      <date>01082016</date>
      <time>1700</time>
      <soldout>0</soldout>
      <linkref>29779</linkref>
    </showtime>
    <showtime>
      <date>01082016</date>
      <time>1930</time>
      <soldout>0</soldout>
      <linkref>29780</linkref>
    </showtime>
    <showtime>
      <date>01092016</date>
      <time>1700</time>
      <soldout>0</soldout>
      <linkref>29797</linkref>
    </showtime>
    <showtime>
      <date>01092016</date>
      <time>1930</time>
      <soldout>0</soldout>
      <linkref>29796</linkref>
    </showtime>
    <showtime>
      <date>01102016</date>
      <time>1700</time>
      <soldout>0</soldout>
      <linkref>29822</linkref>
    </showtime>
    <showtime>
      <date>01102016</date>
      <time>1930</time>
      <soldout>0</soldout>
      <linkref>29823</linkref>
    </showtime>
  </movie>
  <movie>
    <name>THE HATEFUL EIGHT</name>
    <movieId>HA18700</movieId>
    <showtime>
      <date>01072016</date>
      <time>1630</time>
      <soldout>0</soldout>
      <linkref>29399</linkref>
    </showtime>
    <showtime>
      <date>01072016</date>
      <time>2000</time>
      <soldout>1</soldout>
      <linkref>29400</linkref>
    </showtime>
    <showtime>
      <date>01082016</date>
      <time>1800</time>
      <soldout>0</soldout>
      <linkref>29770</linkref>
    </showtime>
    <showtime>
      <date>01082016</date>
      <time>2130</time>
      <soldout>0</soldout>
      <linkref>29771</linkref>
    </showtime>
    <showtime>
      <date>01082016</date>
      <time>2330</time>
      <soldout>0</soldout>
      <linkref>29799</linkref>
    </showtime>
    <showtime>
      <date>01092016</date>
      <time>1800</time>
      <soldout>0</soldout>
      <linkref>29808</linkref>
    </showtime>
    <showtime>
      <date>01092016</date>
      <time>2130</time>
      <soldout>0</soldout>
      <linkref>29807</linkref>
    </showtime>
  </movie>
</showtimes>

The idea is that there will be a showtimes section in the movie detail page where the user can click on a date / time and be taken directly to the online bookings site for that showing.

The movie is pulled from the xml via movieId tag. Each movie is shown around 3-5 times a day for at least a week.

If a user selects the Movie THE HATEFUL EIGHT, I need the output to be displayed like this:

01072016 - 1630, 2000, 
01082016 - 1800, 2130, 2330
01092016 - 1800, 2130

I've looked high and low for a solution, and I seem to be going round in circles.

Any help would be greatly appreciated.

Cheers

Nico


Solution

  • This should do the trick :)

    <?php
    
    $xml = "<showtimes>
      <movie>
        <name>BROOKLYN</name>
        <movieId>BR30015</movieId>
        <showtime>
          <date>01082016</date>
          <time>1700</time>
          <soldout>0</soldout>
          <linkref>29779</linkref>
        </showtime>
        <showtime>
          <date>01082016</date>
          <time>1930</time>
          <soldout>0</soldout>
          <linkref>29780</linkref>
        </showtime>
        <showtime>
          <date>01092016</date>
          <time>1700</time>
          <soldout>0</soldout>
          <linkref>29797</linkref>
        </showtime>
        <showtime>
          <date>01092016</date>
          <time>1930</time>
          <soldout>0</soldout>
          <linkref>29796</linkref>
        </showtime>
        <showtime>
          <date>01102016</date>
          <time>1700</time>
          <soldout>0</soldout>
          <linkref>29822</linkref>
        </showtime>
        <showtime>
          <date>01102016</date>
          <time>1930</time>
          <soldout>0</soldout>
          <linkref>29823</linkref>
        </showtime>
      </movie>
      <movie>
        <name>THE HATEFUL EIGHT</name>
        <movieId>HA18700</movieId>
        <showtime>
          <date>01072016</date>
          <time>1630</time>
          <soldout>0</soldout>
          <linkref>29399</linkref>
        </showtime>
        <showtime>
          <date>01072016</date>
          <time>2000</time>
          <soldout>1</soldout>
          <linkref>29400</linkref>
        </showtime>
        <showtime>
          <date>01082016</date>
          <time>1800</time>
          <soldout>0</soldout>
          <linkref>29770</linkref>
        </showtime>
        <showtime>
          <date>01082016</date>
          <time>2130</time>
          <soldout>0</soldout>
          <linkref>29771</linkref>
        </showtime>
        <showtime>
          <date>01082016</date>
          <time>2330</time>
          <soldout>0</soldout>
          <linkref>29799</linkref>
        </showtime>
        <showtime>
          <date>01092016</date>
          <time>1800</time>
          <soldout>0</soldout>
          <linkref>29808</linkref>
        </showtime>
        <showtime>
          <date>01092016</date>
          <time>2130</time>
          <soldout>0</soldout>
          <linkref>29807</linkref>
        </showtime>
      </movie>
    </showtimes>";
    
    function getMovieNode($name, $xmlString) {
      $movies = simplexml_load_string($xmlString);
      foreach ($movies as $movie) {
        if ($movie->name == $name) return $movie;
      }
      throw new Exception('Movie not found');
    }
    
    function convertNodes($nodes) {
      $times = [];
      foreach ($nodes as $time) {
        array_push($times, $time);
      }
      return $times;
    }
    
    function getSchedule($name, $xmlString) {
      $movie = getMovieNode($name, $xmlString);
      return array_reduce(convertNodes($movie->showtime), function($acc, $curr) {
        $acc[reset($curr->date)][] = reset($curr->time);
        return $acc;
      }, []);
    }
    
    foreach (getSchedule('THE HATEFUL EIGHT', $xml) as $date => $times) {
      print $date;
      print ' - ';
      $last = array_pop($times);
      foreach ($times as $time) {
        print $time;
        print ', ';
      }
      print $last . "\n";
    }