Index: mappers/content.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feeds/mappers/content.inc,v
retrieving revision 1.4
diff -u -r1.4 content.inc
--- mappers/content.inc	29 Mar 2010 02:55:50 -0000	1.4
+++ mappers/content.inc	29 Mar 2010 10:23:26 -0000
@@ -39,7 +39,7 @@
  */
 function content_feeds_set_target($node, $target, $value) {
 
-  $field = isset($node->$target) ? $node->$target : array();
+  $field = array();
 
   // Handle multiple value fields.
   if (is_array($value)) {
Index: mappers/filefield.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feeds/mappers/filefield.inc,v
retrieving revision 1.4
diff -u -r1.4 filefield.inc
--- mappers/filefield.inc	29 Mar 2010 02:55:50 -0000	1.4
+++ mappers/filefield.inc	29 Mar 2010 10:23:35 -0000
@@ -58,7 +58,7 @@
   }
 
   // Map enclosures.
-  $items = isset($node->$field_name) ? $node->$field_name : array();
+  $items = array();
   foreach ($enclosures as $enclosure) {
     if ($file = $enclosure->getFile()) {
       $field = content_fields($field_name, $node->type);
Index: mappers/taxonomy.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feeds/mappers/taxonomy.inc,v
retrieving revision 1.1
diff -u -r1.1 taxonomy.inc
--- mappers/taxonomy.inc	5 Dec 2009 01:38:27 -0000	1.1
+++ mappers/taxonomy.inc	29 Mar 2010 10:26:01 -0000
@@ -50,6 +50,15 @@
   $vocab_id = (int) str_replace('taxonomy:', '', $key);
   $vocab = taxonomy_vocabulary_load($vocab_id);
 
+  if (isset($node->taxonomy)) {
+    // Remove target vocabulary terms from node before adding new ones
+    foreach ($node->taxonomy as $term) {
+      if ($term->vid == $vocab->vid) {
+        unset($node->taxonomy[$term->tid]);
+      }
+    }
+  }
+
   // Cast a given single string to an array so we can use it.
   if (!is_array($terms)) {
     $terms = array($terms);
Index: plugins/FeedsNodeProcessor.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feeds/plugins/FeedsNodeProcessor.inc,v
retrieving revision 1.25
diff -u -r1.25 FeedsNodeProcessor.inc
--- plugins/FeedsNodeProcessor.inc	30 Mar 2010 20:06:36 -0000	1.25
+++ plugins/FeedsNodeProcessor.inc	2 Apr 2010 06:50:38 -0000
@@ -9,6 +9,11 @@
 // Create or delete FEEDS_NODE_BATCH_SIZE at a time.
 define('FEEDS_NODE_BATCH_SIZE', 50);
 
+// Updating mode for existing nodes
+define('FEEDS_NODE_SKIP_EXISTING', 0);
+define('FEEDS_NODE_REPLACE_EXISTING', 1);
+define('FEEDS_NODE_UPDATE_EXISTING', 2);
+
 /**
  * Creates nodes from feed items.
  */
@@ -25,7 +30,7 @@
     while ($item = $batch->shiftItem()) {
 
       // Create/update if item does not exist or update existing is enabled.
-      if (!($nid = $this->existingItemId($item, $source)) || $this->config['update_existing']) {
+      if (!($nid = $this->existingItemId($item, $source)) || ($this->config['update_existing'] != FEEDS_NODE_SKIP_EXISTING)) {
 
         $node = new stdClass();
         $hash = $this->hash($item);
@@ -38,10 +43,17 @@
             continue;
           }
 
-          // If updating populate nid and vid avoiding an expensive node_load().
-          $node->nid = $nid;
-          $node->vid = db_result(db_query("SELECT vid FROM {node} WHERE nid = %d", $nid));
-          $batch->updated++;
+          if ($this->config['update_existing'] == FEEDS_NODE_REPLACE_EXISTING) {
+            // Replace existing item nodes
+            $node->nid = $nid;
+            $node->vid = db_result(db_query("SELECT vid FROM {node} WHERE nid = %d", $nid));
+            $batch->replaced++;
+          }
+          else {
+            // Update existing item nodes (slower than replacing them)
+            $node = node_load($nid, NULL, TRUE);
+            $batch->updated++;
+          }
         }
         else {
           $batch->created++;
@@ -75,20 +87,28 @@
 
       $processed++;
       if ($processed >= variable_get('feeds_node_batch_size', FEEDS_NODE_BATCH_SIZE)) {
-        return (1.0 / ($batch->total + 1)) * ($batch->updated + $batch->created); // Add + 1 to make sure that result is not 1.0 = finished.
+        return (1.0 / ($batch->total + 1)) * ($batch->created + $batch->replaced + $batch->updated); // Add + 1 to make sure that result is not 1.0 = finished.
       }
     }
 
     // Set messages.
+    $messages = array();
     if ($batch->created) {
-      drupal_set_message(t('Created !number !type nodes.', array('!number' => $batch->created, '!type' => node_get_types('name', $this->config['content_type']))));
+      $messages[] = format_plural($batch->created, 'Created one @type node.', 'Created @count @type nodes.', array('@type' => node_get_types('name', $this->config['content_type'])));
     }
-    elseif ($batch->updated) {
-      drupal_set_message(t('Updated !number !type nodes.', array('!number' => $batch->updated, '!type' => node_get_types('name', $this->config['content_type']))));
+    if ($batch->replaced) {
+      $messages[] = format_plural($batch->replaced, 'Replaced one @type node.', 'Replaced @count @type nodes.', array('@type' => node_get_types('name', $this->config['content_type'])));
     }
-    else {
-      drupal_set_message(t('There is no new content.'));
+    if ($batch->updated) {
+      $messages[] = format_plural($batch->updated, 'Updated one @type node.', 'Updated @count @type nodes.', array('@type' => node_get_types('name', $this->config['content_type'])));
     }
+    if (!count($messages)) {
+      $messages[] = t('There is no new content.');
+    }
+    foreach ($messages as $message) {
+      drupal_set_message($message);
+    }
+    watchdog('feeds', 'File %file processed: %msg', array('%file' => $batch->getFilePath(), '%msg' => implode(' ', $messages)));
 
     return FEEDS_BATCH_COMPLETE;
   }
@@ -163,7 +183,7 @@
     $type = isset($types['story']) ? 'story' : key($types);
     return array(
       'content_type' => $type,
-      'update_existing' => 0,
+      'update_existing' => FEEDS_NODE_SKIP_EXISTING,
       'expire' => FEEDS_EXPIRE_NEVER,
       'mappings' => array(),
     );
@@ -183,9 +203,14 @@
       '#default_value' => $this->config['content_type'],
     );
     $form['update_existing'] = array(
-      '#type' => 'checkbox',
+      '#type' => 'radios',
       '#title' => t('Update existing items'),
-      '#description' => t('Check if existing items should be updated from the feed.'),
+      '#description' => t('Choose how existing items should be updated from the feed.'),
+      '#options' => array(
+        FEEDS_NODE_SKIP_EXISTING => 'Do not update existing item nodes',
+        FEEDS_NODE_REPLACE_EXISTING => 'Replace existing item nodes',
+        FEEDS_NODE_UPDATE_EXISTING => 'Update existing item nodes (slower than replacing them)',
+      ),
       '#default_value' => $this->config['update_existing'],
     );
     $period = drupal_map_assoc(array(FEEDS_EXPIRE_NEVER, 3600, 10800, 21600, 43200, 86400, 259200, 604800, 604800 * 4, 604800 * 12, 604800 * 24, 31536000), 'feeds_format_expire');

