diff --git a/feeds.api.php b/feeds.api.php
index e0dfc12..19e7bb8 100644
--- a/feeds.api.php
+++ b/feeds.api.php
@@ -278,6 +278,11 @@ function hook_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
       // configuration form.
       'summary_callback' => 'my_module_summary_callback',
       'form_callback' => 'my_module_form_callback',
+
+      // Specify post-process callback. This runs after all values have been
+      // mapped to the target.
+      // @see feeds_filter_empty_field_items()
+      'post_process' => 'my_module_post_process_callback',
     );
     $targets['my_node_field2'] = array(
       'name' => t('My Second custom node field'),
@@ -303,8 +308,9 @@ function hook_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
  *  Associative array of the mapping settings from the per mapping
  *  configuration form.
  */
-function my_module_set_target($source, $entity, $target, $value, $mapping) {
-  $entity->{$target}[$entity->language][0]['value'] = $value;
+function my_module_set_target($source, $entity, $target, array $values, $mapping) {
+  $entity->{$target}[$entity->language][0]['value'] = reset($values);
+
   if (isset($source->importer->processor->config['input_format'])) {
     $entity->{$target}[$entity->language][0]['format'] =
       $source->importer->processor->config['input_format'];
@@ -312,6 +318,24 @@ function my_module_set_target($source, $entity, $target, $value, $mapping) {
 }
 
 /**
+ * Example post-process callback.
+ *
+ * @param FeedsSource $source
+ *   The feed source.
+ * @param object $entity
+ *   The entity being created or updated.
+ * @param string $target
+ *   The target being mapped.
+ * @param array $target_info
+ *   The target info array.
+ */
+function my_module_post_process_callback(FeedsSource $source, $entity, $target, array $target_info) {
+  foreach ($entity->{$target}['und'] as $delta => $value) {
+    $entity->{$target}['und'][$delta] = drupal_strtolower($value);
+  }
+}
+
+/**
  * Example of the summary_callback specified in
  * hook_feeds_processor_targets_alter().
  *
diff --git a/feeds.module b/feeds.module
index f581d3f..7a115f1 100644
--- a/feeds.module
+++ b/feeds.module
@@ -1249,3 +1249,28 @@ function feeds_api_version() {
   $version = feeds_ctools_plugin_api('feeds', 'plugins');
   return $version['version'];
 }
+
+/**
+ * Filters empty field values.
+ *
+ * This is used as a post-process callback for field targets.
+ *
+ * @param FeedsSource $source
+ *   The feed source.
+ * @param object $entity
+ *   The entity being created or updated.
+ * @param string $target
+ *   The target being mapped.
+ * @param array $target_info
+ *   The target info array.
+ */
+function feeds_filter_empty_field_items(FeedsSource $source, $entity, $target, array $target_info) {
+  $field_name = $target;
+  if (!empty($target_info['real_target'])) {
+    $field_name = $target_info['real_target'];
+  }
+
+  $field = field_info_field($field_name);
+
+  $entity->{$field_name}['und'] = _field_filter_items($field, $entity->{$field_name}['und']);
+}
diff --git a/mappers/date.inc b/mappers/date.inc
index 8ff4cbb..8a75687 100644
--- a/mappers/date.inc
+++ b/mappers/date.inc
@@ -21,6 +21,7 @@ function date_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
         'callback' => 'date_feeds_set_target',
         'description' => t('The start date for the @name field. Also use if mapping both start and end.', array('@name' => $instance['label'])),
         'real_target' => $name,
+        'post_process' => 'feeds_filter_empty_field_items',
       );
       $targets[$name . ':end'] = array(
         'name' => t('@name: End', array('@name' => $instance['label'])),
@@ -33,41 +34,28 @@ function date_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
 }
 
 /**
- * Implements hook_feeds_set_target().
- *
- * @param $node
- *   The target node.
- * @param $field_name
- *   The name of field on the target node to map to.
- * @param $feed_element
- *   The value to be mapped. Should be either a (flexible) date string
- *   or a FeedsDateTimeElement object.
- *
+ * Callback for setting target values.
  */
-function date_feeds_set_target($source, $entity, $target, $feed_element) {
+function date_feeds_set_target($source, $entity, $target, array $values) {
   list($field_name, $sub_field) = explode(':', $target, 2);
 
-  if (!is_array($feed_element)) {
-    $feed_element = array($feed_element);
-  }
-
   $delta = 0;
-  foreach ($feed_element as $f) {
+  foreach ($values as $value) {
 
-    if (!($feed_element instanceof FeedsDateTimeElement)) {
+    if (!($value instanceof FeedsDateTimeElement)) {
 
-      if (empty($f) || !is_numeric($f) && is_string($f) && !date_create($f)) {
-        $f = new FeedsDateTimeElement(NULL, NULL);
+      if (empty($value) || !is_numeric($value) && is_string($value) && !date_create($value)) {
+        $value = new FeedsDateTimeElement(NULL, NULL);
       }
       elseif ($sub_field == 'end') {
-        $f = new FeedsDateTimeElement(NULL, $f);
+        $value = new FeedsDateTimeElement(NULL, $value);
       }
       else {
-        $f = new FeedsDateTimeElement($f, NULL);
+        $value = new FeedsDateTimeElement($value, NULL);
       }
     }
 
-    $f->buildDateField($entity, $field_name, $delta);
+    $value->buildDateField($entity, $field_name, $delta);
     $delta++;
   }
 }
diff --git a/mappers/file.inc b/mappers/file.inc
index aa967b9..65c6be6 100644
--- a/mappers/file.inc
+++ b/mappers/file.inc
@@ -21,6 +21,7 @@ function file_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
         'callback' => 'file_feeds_set_target',
         'description' => t('The URI of the @label field.', array('@label' => $instance['label'])),
         'real_target' => $name,
+        'post_process' => 'feeds_filter_empty_field_items',
       );
 
       if ($info['type'] == 'image') {
@@ -48,57 +49,45 @@ function file_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
  * user has decided to map to and $value contains the value of the feed item
  * element the user has picked as a source.
  */
-function file_feeds_set_target($source, $entity, $target, $value) {
-  if (empty($value)) {
-    return;
-  }
-
-  // Make sure $value is an array of objects of type FeedsEnclosure.
-  if (!is_array($value)) {
-    $value = array($value);
-  }
-
+function file_feeds_set_target($source, $entity, $target, array $values) {
   // Add default of uri for backwards compatibility.
   list($field_name, $sub_field) = explode(':', $target . ':uri');
   $info = field_info_field($field_name);
 
   if ($sub_field == 'uri') {
 
-    foreach ($value as $k => $v) {
+    foreach ($values as $k => $v) {
       if (!($v instanceof FeedsEnclosure)) {
         if (is_string($v)) {
-          $value[$k] = new FeedsEnclosure($v, file_get_mimetype($v));
+          $values[$k] = new FeedsEnclosure($v, file_get_mimetype($v));
         }
         else {
-          unset($value[$k]);
+          // Set the value for FALSE rather than remove it to keep our deltas
+          // correct.
+          $values[$k] = FALSE;
         }
       }
     }
-    if (empty($value)) {
-      return;
-    }
 
-    static $destination;
-    if (!$destination) {
-      $entity_type = $source->importer->processor->entityType();
-      $bundle = $source->importer->processor->bundle();
+    $entity_type = $source->importer->processor->entityType();
+    $bundle = $source->importer->processor->bundle();
 
-      $instance_info = field_info_instance($entity_type, $field_name, $bundle);
+    $instance_info = field_info_instance($entity_type, $field_name, $bundle);
 
-      // Determine file destination.
-      // @todo This needs review and debugging.
-      $data = array();
-      if (!empty($entity->uid)) {
-        $data[$entity_type] = $entity;
-      }
-      $destination = file_field_widget_uri($info, $instance_info, $data);
+    // Determine file destination.
+    // @todo This needs review and debugging.
+    $data = array();
+    if (!empty($entity->uid)) {
+      $data[$entity_type] = $entity;
     }
+
+    $destination = file_field_widget_uri($info, $instance_info, $data);
   }
 
   // Populate entity.
   $field = isset($entity->$field_name) ? $entity->$field_name : array(LANGUAGE_NONE => array());
   $delta = 0;
-  foreach ($value as $v) {
+  foreach ($values as $value) {
     if ($info['cardinality'] == $delta) {
       break;
     }
@@ -110,18 +99,20 @@ function file_feeds_set_target($source, $entity, $target, $value) {
     switch ($sub_field) {
       case 'alt':
       case 'title':
-        $field[LANGUAGE_NONE][$delta][$sub_field] = $v;
+        $field[LANGUAGE_NONE][$delta][$sub_field] = $value;
         break;
 
       case 'uri':
-        try {
-          $file = $v->getFile($destination);
-          $field[LANGUAGE_NONE][$delta] += (array) $file;
-          // @todo: Figure out how to properly populate this field.
-          $field[LANGUAGE_NONE][$delta]['display'] = 1;
-        }
-        catch (Exception $e) {
-          watchdog_exception('Feeds', $e, nl2br(check_plain($e)));
+        if ($value) {
+          try {
+            $file = $value->getFile($destination);
+            $field[LANGUAGE_NONE][$delta] += (array) $file;
+            // @todo: Figure out how to properly populate this field.
+            $field[LANGUAGE_NONE][$delta]['display'] = 1;
+          }
+          catch (Exception $e) {
+            watchdog_exception('Feeds', $e, nl2br(check_plain($e)));
+          }
         }
         break;
     }
diff --git a/mappers/link.inc b/mappers/link.inc
index 45a86f7..6a43644 100644
--- a/mappers/link.inc
+++ b/mappers/link.inc
@@ -20,6 +20,7 @@ function link_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
           'callback' => 'link_feeds_set_target',
           'description' => t('The @label field of the entity.', array('@label' => $instance['label'])),
           'real_target' => $name,
+          'post_process' => 'feeds_filter_empty_field_items',
         );
       }
       if (array_key_exists('title', $info['columns'])) {
@@ -30,6 +31,10 @@ function link_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
           'real_target' => $name,
         );
       }
+      // Only set the post_process for one column.
+      if (!isset($targets[$name . ':url']) && isset($targets[$name . ':title'])) {
+        $targets[$name . ':title']['post_process'] = 'feeds_filter_empty_field_items';
+      }
     }
   }
 }
@@ -41,36 +46,24 @@ function link_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
  * user has decided to map to and $value contains the value of the feed item
  * element the user has picked as a source.
  */
-function link_feeds_set_target($source, $entity, $target, $value) {
-  if (empty($value)) {
-    return;
-  }
-
-  // Handle non-multiple value fields.
-  if (!is_array($value)) {
-    $value = array($value);
-  }
+function link_feeds_set_target($source, $entity, $target, array $values) {
 
   // Iterate over all values.
   list($field_name, $column) = explode(':', $target);
-  $info = field_info_field($field_name);
 
   $field = isset($entity->$field_name) ? $entity->$field_name : array();
   $delta = 0;
 
-  foreach ($value as $v) {
-    if ($info['cardinality'] == $delta) {
-      break;
+  foreach ($values as $value) {
+    if (is_object($value) && ($value instanceof FeedsElement)) {
+      $value = $value->getValue();
     }
 
-    if (is_object($v) && ($v instanceof FeedsElement)) {
-      $v = $v->getValue();
-    }
-
-    if (is_scalar($v)) {
-      $field['und'][$delta][$column] = $v;
-      $delta++;
+    if (is_scalar($value)) {
+      $field['und'][$delta][$column] = $value;
     }
+    $delta++;
   }
+
   $entity->$field_name = $field;
 }
diff --git a/mappers/number.inc b/mappers/number.inc
index b64c4ee..baf548d 100644
--- a/mappers/number.inc
+++ b/mappers/number.inc
@@ -27,6 +27,7 @@ function number_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_n
         'name' => check_plain($instance['label']),
         'callback' => 'number_feeds_set_target',
         'description' => t('The @label field of the entity.', array('@label' => $instance['label'])),
+        'post_process' => 'feeds_filter_empty_field_items',
       );
     }
   }
@@ -37,36 +38,18 @@ function number_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_n
  *
  * Ensure that $value is a numeric to avoid database errors.
  */
-function number_feeds_set_target($source, $entity, $target, $value) {
-
-  // Do not perform the regular empty() check here. 0 is a valid value. That's
-  // really just a performance thing anyway.
-
-  if (!is_array($value)) {
-    $value = array($value);
-  }
-
-  $info = field_info_field($target);
-
+function number_feeds_set_target($source, $entity, $target, array $values) {
   // Iterate over all values.
   $field = isset($entity->$target) ? $entity->$target : array('und' => array());
 
-  // Allow for multiple mappings to the same target.
-  $delta = count($field['und']);
-
-  foreach ($value as $v) {
-
-    if ($info['cardinality'] == $delta) {
-      break;
-    }
+  foreach ($values as $value) {
 
-    if (is_object($v) && ($v instanceof FeedsElement)) {
-      $v = $v->getValue();
+    if (is_object($value) && ($value instanceof FeedsElement)) {
+      $value = $value->getValue();
     }
 
-    if (is_numeric($v)) {
-      $field['und'][$delta]['value'] = $v;
-      $delta++;
+    if (is_numeric($value)) {
+      $field['und'][] = array('value' => $value);
     }
   }
 
diff --git a/mappers/path.inc b/mappers/path.inc
index 47ae0fc..82c149e 100644
--- a/mappers/path.inc
+++ b/mappers/path.inc
@@ -33,14 +33,17 @@ function path_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
  * user has decided to map to and $value contains the value of the feed item
  * element the user has picked as a source.
  */
-function path_feeds_set_target($source, $entity, $target, $value, $mapping) {
-  if (empty($value)) {
-    $value = '';
-  }
+function path_feeds_set_target($source, $entity, $target, array $values, $mapping) {
+
+  $alias = FALSE;
 
-  // Path alias cannot be multi-valued, so use the first value.
-  if (is_array($value)) {
-    $value = $value[0];
+  // Path alias cannot be multi-valued, so use the first non-empty value.
+  foreach ($values as $value) {
+    $value = ltrim(trim($value), '/');
+    if (strlen($value)) {
+      $alias = $value;
+      break;
+    }
   }
 
   $entity->path = array();
@@ -58,15 +61,11 @@ function path_feeds_set_target($source, $entity, $target, $value, $mapping) {
     }
   }
 
-  $entity->path['pathauto'] = FALSE;
-  // Allow pathauto to set the path alias if the option is set, and this value
-  // is empty.
-  if (!empty($mapping['pathauto_override']) && !$value) {
-    $entity->path['pathauto'] = TRUE;
-  }
-  else {
-    $entity->path['alias'] = ltrim($value, '/');
-  }
+  // Allow pathauto to set the path alias if the option is set, and the value is
+  // empty.
+  $entity->path['pathauto'] = !empty($mapping['pathauto_override']) && $alias === FALSE;
+
+  $entity->path['alias'] = (string) $alias;
 }
 
 /**
diff --git a/mappers/profile.inc b/mappers/profile.inc
index 0dd62de..00fdf3a 100644
--- a/mappers/profile.inc
+++ b/mappers/profile.inc
@@ -30,6 +30,6 @@ function profile_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_
 /**
  * Set the user profile target after import.
  */
-function profile_feeds_set_target($source, $entity, $target, $value, $mapping) {
-  $entity->$target = $value;
+function profile_feeds_set_target($source, $entity, $target, array $values, $mapping) {
+  $entity->$target = reset($values);
 }
diff --git a/mappers/taxonomy.inc b/mappers/taxonomy.inc
index 02ac54e..1bcc584 100644
--- a/mappers/taxonomy.inc
+++ b/mappers/taxonomy.inc
@@ -67,6 +67,7 @@ function taxonomy_feeds_processor_targets_alter(&$targets, $entity_type, $bundle
         'description' => t('The @label field of the entity.', array('@label' => $instance['label'])),
         'summary_callback' => 'taxonomy_feeds_summary_callback',
         'form_callback' => 'taxonomy_feeds_form_callback',
+        'post_process' => 'feeds_filter_empty_field_items',
       );
     }
   }
@@ -77,17 +78,7 @@ function taxonomy_feeds_processor_targets_alter(&$targets, $entity_type, $bundle
  *
  * @todo Do not create new terms for non-autotag fields.
  */
-function taxonomy_feeds_set_target($source, $entity, $target, $terms, $mapping = array()) {
-
-  // Allow mapping the string '0' to a term name.
-  if (empty($terms) && $terms != 0) {
-    return;
-  }
-
-  // Handle non-multiple values.
-  if (!is_array($terms)) {
-    $terms = array($terms);
-  }
+function taxonomy_feeds_set_target($source, $entity, $target, array $terms, $mapping = array()) {
 
   // Add in default values.
   $mapping += array(
@@ -123,7 +114,6 @@ function taxonomy_feeds_set_target($source, $entity, $target, $terms, $mapping =
 
   // Iterate over all values.
   foreach ($terms as $term) {
-
     if ($info['cardinality'] == $delta) {
       break;
     }
@@ -171,7 +161,7 @@ function taxonomy_feeds_set_target($source, $entity, $target, $terms, $mapping =
     }
 
     if ($tid && isset($cache['allowed_values'][$target][$tid])) {
-      $field['und'][$delta]['tid'] = $tid;
+      $field['und'][] = array('tid' => $tid);
       $delta++;
     }
   }
diff --git a/mappers/text.inc b/mappers/text.inc
index 48447d7..874c2a1 100644
--- a/mappers/text.inc
+++ b/mappers/text.inc
@@ -25,6 +25,7 @@ function text_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
         'name' => check_plain($instance['label']),
         'callback' => 'text_feeds_set_target',
         'description' => t('The @label field of the entity.', array('@label' => $instance['label'])),
+        'post_process' => 'feeds_filter_empty_field_items',
       );
     }
   }
@@ -33,45 +34,27 @@ function text_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_nam
 /**
  * Callback for mapping text fields.
  */
-function text_feeds_set_target($source, $entity, $target, $value) {
-  if (empty($value)) {
-    return;
-  }
-
-  if (!is_array($value)) {
-    $value = array($value);
-  }
+function text_feeds_set_target($source, $entity, $target, array $values) {
 
   if (isset($source->importer->processor->config['input_format'])) {
     $format = $source->importer->processor->config['input_format'];
   }
 
-  $info = field_info_field($target);
-
   // Iterate over all values.
   $field = isset($entity->$target) ? $entity->$target : array('und' => array());
 
-  // Allow for multiple mappings to the same target.
-  $delta = count($field['und']);
-
-  foreach ($value as $v) {
+  foreach ($values as $value) {
 
-    if ($info['cardinality'] == $delta) {
-      break;
+    if (is_object($value) && ($value instanceof FeedsElement)) {
+      $value = $value->getValue();
     }
 
-    if (is_object($v) && ($v instanceof FeedsElement)) {
-      $v = $v->getValue();
-    }
-
-    if (is_scalar($v)) {
-      $field['und'][$delta]['value'] = $v;
-
+    if (is_scalar($value)) {
+      $value = array('value' => (string) $value);
       if (isset($format)) {
-        $field['und'][$delta]['format'] = $format;
+        $value['format'] = $format;
       }
-
-      $delta++;
+      $field['und'][] = $value;
     }
   }
 
diff --git a/plugins/FeedsProcessor.inc b/plugins/FeedsProcessor.inc
index c2b0af5..83d85d7 100755
--- a/plugins/FeedsProcessor.inc
+++ b/plugins/FeedsProcessor.inc
@@ -506,12 +506,30 @@ abstract class FeedsProcessor extends FeedsPlugin {
           isset($targets[$this->id][$mapping['target']]['callback']) &&
           function_exists($targets[$this->id][$mapping['target']]['callback'])) {
         $callback = $targets[$this->id][$mapping['target']]['callback'];
+
+        // All target callbacks expect an array.
+        if (!is_array($value)) {
+          $value = array($value);
+        }
         $callback($source, $target_item, $mapping['target'], $value, $mapping);
       }
       else {
         $this->setTargetElement($source, $target_item, $mapping['target'], $value, $mapping);
       }
     }
+
+    foreach ($this->config['mappings'] as $mapping) {
+      $target = $mapping['target'];
+      if (isset($targets[$this->id][$target]) &&
+          is_array($targets[$this->id][$target]) &&
+          isset($targets[$this->id][$target]['post_process']) &&
+          function_exists($targets[$this->id][$target]['post_process'])) {
+
+        $callback = $targets[$this->id][$target]['post_process'];
+        $callback($source, $target_item, $target, $targets[$this->id][$target]);
+      }
+    }
+
     return $target_item;
   }
 
diff --git a/tests/feeds/nodes_multiple_body.csv b/tests/feeds/nodes_multiple_body.csv
new file mode 100644
index 0000000..4029f90
--- /dev/null
+++ b/tests/feeds/nodes_multiple_body.csv
@@ -0,0 +1,4 @@
+Title,Body,Body2,Body3
+"Ut wisi enim ad minim veniam",, Body text 2,"Body 3"
+"Duis autem vel eum iriure dolor",, Body text 2,"Body 3"
+"Nam liber tempor",, Body text 2,"Body 3"
diff --git a/tests/feeds_mapper_field.test b/tests/feeds_mapper_field.test
index 2506a29..5e004c9 100644
--- a/tests/feeds_mapper_field.test
+++ b/tests/feeds_mapper_field.test
@@ -87,4 +87,49 @@ class FeedsMapperFieldTestCase extends FeedsMapperTestCase {
     $this->assertNodeFieldValue('gamma', '1.20');
     $this->assertNodeFieldValue('delta', '5.62951');
   }
+
+  /**
+   * Tests post_process callbacks.
+   *
+   * @see  feeds_filter_empty_field_items()
+   */
+  public function testFilterEmptyValues() {
+    // Create and configure importer.
+    $this->createImporterConfiguration('Content CSV', 'csv');
+    $this->setSettings('csv', NULL, array('content_type' => '', 'import_period' => FEEDS_SCHEDULE_NEVER));
+    $this->setPlugin('csv', 'FeedsFileFetcher');
+    $this->setPlugin('csv', 'FeedsCSVParser');
+    $this->setSettings('csv', 'FeedsNodeProcessor', array('bundle' => 'article'));
+
+    // Map multiple values to the same field. The first value is empty, and the
+    // third should be removed since cardinality = 1.
+    $this->addMappings('csv', array(
+      0 => array(
+        'source' => 'title',
+        'target' => 'title',
+      ),
+      1 => array(
+        'source' => 'body',
+        'target' => 'body',
+      ),
+      2 => array(
+        'source' => 'body2',
+        'target' => 'body',
+      ),
+      3 => array(
+        'source' => 'body3',
+        'target' => 'body',
+      ),
+    ));
+
+    // Import CSV file.
+    $this->importFile('csv', $this->absolutePath() . '/tests/feeds/nodes_multiple_body.csv');
+    $this->assertText(t('Created 3 nodes.'));
+    foreach (range(1, 3) as $nid) {
+      $this->drupalGet("node/$nid");
+      $this->assertText('Body text 2');
+      $this->assertNoText('Body 3');
+    }
+  }
+
 }
