SimpleXMLIterator & FilterIterator combined

June 3, 2008 – 10:55 pm
  1. < ?php
  2. /*
  3.     Goal:
  4.       * Take a GPX (which is XML) file
  5.       * Extract interesting records from it
  6.       * Calculate the arithmetic average of latitudes and longitutes
  7.      
  8.     I won't tell you why exactly I needed this, just that it is part of a game
  9.     called geocaching
  10.  
  11.     —
  12.    
  13.     Class is called collector, because I am _collecting_ only the records
  14.     I'm interested in
  15.  
  16.     Example record:
  17.         <wpt lat="59.4658317566" lon="24.8649997711">
  18.             <name>< ![CDATA[Gtehnokratt]]></name>
  19.             <url>< ![CDATA[http://www.geopeitus.ee/?p=350&c=2]]></url>
  20.        
  21.    
  22.     Actually there is more data, but I'm only interested in lat and lon attributes
  23.     and name and url elements.
  24.  
  25.     Records do not have any id-s, only the url has the unique identifier at the end.
  26. */
  27.  
  28. class Collector extends FilterIterator
  29. {
  30.     /**
  31.      * I only care about records with id's that are listed here
  32.      */
  33.     private $ids = array(187, 513, 537, 542, 544, 563, 605, 715, 717, 748);
  34.  
  35.     /**
  36.      * Set up the FilterIterator by passing our SimpleXMLIterator to it
  37.      */
  38.     public function __construct(Iterator $it) {
  39.         parent::__construct($it);
  40.     }
  41.  
  42.     /**
  43.      * Part of FilterIterator implementation, called for each record,
  44.      * responsible for the decision whether the current element is needed
  45.      * or not
  46.      */
  47.     public function accept() {
  48.         $id = $this->get_id_from_url($this->current()->url);
  49.         if (in_array($id,$this->ids)) {
  50.             return true;
  51.         }
  52.         return false;
  53.     }
  54.      /**
  55.      * Extracts record ID from string
  56.      */
  57.     private function get_id_from_url($url)
  58.     {
  59.         // http://www.geopeitus.ee/?p=350&c=514
  60.         preg_match('/&c=(\d+)$/',$url,$matches);
  61.         return $matches[1];
  62.     }
  63. }
  64.  
  65. /*
  66.     SimpleXMLIterator is one of the standard SPL iterators, which makes it possible
  67.     to use other standard iterators when parsing XML
  68.  
  69.     Second argument of simplexml_load_file is a class name and as result the XML
  70.     in-memory representation becomes instance of that class. Seems awkward, but
  71.     really useful
  72. */
  73. $it = simplexml_load_file('geopeitusee.gpx','SimpleXMLIterator');
  74.  
  75. $lat_sum = $lon_sum = $count = 0.0;
  76.  
  77. // so, all the data goes in, but only the elements I'm interested in, come out
  78. foreach(new Collector($it) as $element) {
  79.     // access subnodes with $element->name
  80.     // access attributes with array notation
  81.     printf("taking %s, lat=%f, lon = %f\n", $element->name,$element['lat'],$element['lon']);
  82.  
  83.     // typecasting is needed to get correct results from SimpleXML, otherwise you would
  84.     // get integers
  85.     $lat_sum += (float)$element['lat'];
  86.     $lon_sum += (float)$element['lon'];
  87.     $count++;
  88. }
  89.  
  90. // finally do the math
  91. printf("Average: cnt=%d lat=%s, lon=%s\n", $count, ($lat_sum / $count), $lon_sum / $count);

Post a Comment