Index: plugins/FeedsNodeProcessor.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feeds/plugins/FeedsNodeProcessor.inc,v
retrieving revision 1.15
diff -u -p -r1.15 FeedsNodeProcessor.inc
--- plugins/FeedsNodeProcessor.inc	18 Nov 2009 16:53:48 -0000	1.15
+++ plugins/FeedsNodeProcessor.inc	18 Nov 2009 17:26:48 -0000
@@ -17,36 +17,56 @@ class FeedsNodeProcessor extends FeedsPr
   public function process(FeedsParserResult $parserResult, FeedsSource $source) {
 
     // Count number of created and updated nodes.
-    $created  = $updated = 0;
+    $created = $updated = 0;
 
     foreach ($parserResult->value['items'] as $item) {
       // If the target item does not exist OR if update_existing is enabled,
       // map and save.
       if (!($nid = $this->existingItemId($item, $source)) || $this->config['update_existing']) {
-
-        // Map item to a node.
-        $node = $this->map($item);
-
-        // Add some default information.
-        $node->feeds_node_item->id = $this->id;
-        $node->feeds_node_item->imported = FEEDS_REQUEST_TIME;
-        $node->feeds_node_item->feed_nid = $source->feed_nid;
-
+        $hash = $this->hash($item);
+        $node = new stdClass();
+        
         // If updating populate nid and vid avoiding an expensive node_load().
         if (!empty($nid)) {
+          if ($hash == $this->getHash($nid)) {
+            // No change, nothing to do.
+            continue;
+          }
           $node->nid = $nid;
           $node->vid = db_result(db_query('SELECT vid FROM {node} WHERE nid = %d', $nid));
-        }
-
-        // Save the node.
-        node_save($node);
-
-        if ($nid) {
           $updated++;
         }
         else {
           $created++;
         }
+        
+        $node->type = $this->config['content_type'];
+        $node->feeds_node_item = new stdClass();
+        $node->feeds_node_item->hash = $hash;
+         
+        // Prepare node object.
+        static $included;
+        if (!$included) {
+          module_load_include('inc', 'node', 'node.pages');
+          $included = TRUE;
+        }
+        node_object_prepare($target_node);
+        $node->log = 'Created/updated by FeedsNodeProcessor';
+        
+        // Execute mappings from $item to $node.
+        $this->map($item, $node);
+        
+        // Add some default information.
+        $node->feeds_node_item->id = $this->id;
+        $node->feeds_node_item->imported = FEEDS_REQUEST_TIME;
+        $node->feeds_node_item->feed_nid = $source->feed_nid;
+        
+        // Assign an aggregated node always to anonymous.
+        // @todo: change to feed node uid to keep in line with feedapi?
+        $node->uid = 0;
+
+        // Save the node.
+        node_save($node);
       }
     }
 
@@ -108,22 +128,7 @@ class FeedsNodeProcessor extends FeedsPr
   /**
    * Execute mapping on an item.
    */
-  protected function map($source_item) {
-    // Prepare node object.
-    static $included;
-    if (!$included) {
-      module_load_include('inc', 'node', 'node.pages');
-      $included = TRUE;
-    }
-    $target_node = new stdClass();
-    $target_node->type = $this->config['content_type'];
-    $target_node->feeds_node_item = new stdClass();
-    node_object_prepare($target_node);
-    // Assign an aggregated node always to anonymous.
-    // @todo: change to feed node uid to keep in line with feedapi.
-    $target_node->uid = 0;
-    $target_node->log = 'Created/updated by FeedsNodeProcessor';
-
+  protected function map($source_item, $target_node) {
     // Load all mappers. parent::map() might invoke their callbacks.
     self::loadMappers();
 
@@ -316,6 +321,29 @@ class FeedsNodeProcessor extends FeedsPr
     }
     $loaded = TRUE;
   }
+  
+  /**
+   * Create MD5 hash of $item array.
+   * @return Always returns a hash, even with empty, NULL, FALSE:
+   *  Empty arrays return 40cd750bba9870f18aada2478b24840a
+   *  Empty/NULL/FALSE strings return d41d8cd98f00b204e9800998ecf8427e
+   */
+   protected function hash($item) {
+    return hash('md5', serialize($item));
+  }
+  
+  /**
+   * Retrieve MD5 hash of $nid from DB.
+   * @return Empty string if no item is found, hash otherwise.
+   */
+  protected function getHash($nid) {
+    $hash = db_result(db_query('SELECT hash FROM {feeds_node_item} WHERE nid = %d', $nid));
+    if ($hash) {
+      // Return with the hash.
+      return $hash;
+    }
+    return '';
+  }
 }
 
 /**
@@ -343,4 +371,4 @@ function _feeds_node_delete($nid) {
   }
   watchdog('content', '@type: deleted %title.', array('@type' => $node->type, '%title' => $node->title));
   drupal_set_message(t('@type %title has been deleted.', array('@type' => node_get_types('name', $node), '%title' => $node->title)));
-}
\ No newline at end of file
+}
