diff --git a/migrate.info b/migrate.info
index 6648be9..460d2b9 100644
--- a/migrate.info
+++ b/migrate.info
@@ -38,6 +38,7 @@ files[] = plugins/sources/sql.inc
 files[] = plugins/sources/sqlmap.inc
 files[] = plugins/sources/mssql.inc
 files[] = plugins/sources/oracle.inc
+files[] = plugins/sources/spreadsheet.inc
 files[] = plugins/sources/xml.inc
 files[] = tests/import/options.test
 files[] = tests/plugins/destinations/comment.test
diff --git a/plugins/sources/spreadsheet.inc b/plugins/sources/spreadsheet.inc
new file mode 100644
index 0000000..136a45b
--- /dev/null
+++ b/plugins/sources/spreadsheet.inc
@@ -0,0 +1,235 @@
+<?php

+

+/**

+ * @file

+ * Define a MigrateSource for importing from spreadsheet files.

+ *

+ * Requires the PHPExcel library to be installed.

+ * - Download PHPExcel at http://phpexcel.codeplex.com/.

+ * - Extract the archive to a temporary folder.

+ * - Ensure the hosting environment fulfills the requirements found in

+ *   install.txt.

+ * - Copy the contents of the Classes folder to an appropriate location

+ *   (sites/all/libraries/PHPExcel).

+ */

+

+/**

+ * Implements MigrateSource, to handle imports from XLS files.

+ */

+class MigrateSourceSpreadsheet extends MigrateSource {

+  /**

+   * PHPExcel object for storing the workbook data.

+   *

+   * @var PHPExcel

+   */

+  protected $workbook;

+

+  /**

+   * PHPExcel object for storing the worksheet data.

+   *

+   * @var PHPExcel_Worksheet

+   */

+  protected $worksheet;

+

+  /**

+   * The name of the worksheet that will be processed.

+   *

+   * @var string

+   */

+  protected $sheetName;

+

+  /**

+   * Number of rows in the worksheet that is being processed.

+   *

+   * @var integer

+   */

+  protected $rows = 0;

+

+  /**

+   * Number of columns in the worksheet that is being processed.

+   *

+   * @var integer

+   */

+  protected $cols = 0;

+

+  /**

+   * List of available source fields.

+   *

+   * @var array

+   */

+  protected $fields = array();

+

+  /**

+   * The current row number in the XLS file.

+   *

+   * @var integer

+   */

+  protected $rowNumber;

+

+  /**

+   * The columns to be read from Excel

+   */

+  protected $columns;

+

+  /**

+   * Simple initialization.

+   *

+   * @param string $path

+   *   The path to the source file.

+   * @param string $sheet_name

+   *   The name of the sheet to be processed.

+   * @param array $options

+   *   Options applied to this source.

+   */

+  public function __construct($path, $sheet_name, $columns = array(), array $options = array()) {

+    parent::__construct($options);

+    $this->file = $path;

+    $this->sheetName = $sheet_name;

+    $this->columns = $columns;

+

+    // Load the workbook.

+    if ($this->load()) {

+      // Get the dimensions of the worksheet.

+      $this->rows = $this->worksheet->getHighestDataRow();

+      $this->cols = PHPExcel_Cell::columnIndexFromString($this->worksheet->getHighestDataColumn());

+

+      // Map field names to their column index.

+      for ($col = 0; $col < $this->cols; ++$col) {

+        $this->fields[$col] = trim($this->worksheet->getCellByColumnAndRow($col, 1)->getValue());

+      }

+

+      $this->unload();

+    }

+  }

+

+  /**

+   * Loads the workbook.

+   *

+   * @return bool

+   *   Returns true if the workbook was successfully loaded, otherwise false.

+   */

+  public function load() {

+    // Check that the file exists.

+    if (!file_exists($this->file)) {

+      Migration::displayMessage(t('The file !filename does not exist.', array('!filename' => $this->file)));

+      return FALSE;

+    }

+

+    if (module_exists('libraries') && module_exists('phpexcel')) {

+      $library = libraries_load('PHPExcel');

+      if (empty($library['loaded'])) {

+        Migration::displayMessage(t('The PHPExcel library could not be found.'));

+        return FALSE;

+      }

+    }

+    else {

+      Migration::displayMessage(t('The Libraries API module is not enabled.'));

+      return FALSE;

+    }

+

+    // Load the workbook.

+    try {

+      // Identify the type of the input file.

+      $type = PHPExcel_IOFactory::identify($this->file);

+      // Create a new Reader of the file type.

+      $reader = PHPExcel_IOFactory::createReader($type);

+      // Advise the Reader that we only want to load cell data.

+      $reader->setReadDataOnly(TRUE);

+      // Advise the Reader of which worksheet we want to load.

+      $reader->setLoadSheetsOnly($this->sheetName);

+      // Load the source file.

+      $this->workbook = $reader->load($this->file);

+      $this->worksheet = $this->workbook->getSheet();

+    }

+    catch (Exception $e) {

+      Migration::displayMessage(t('Error loading file: %message', array('%message' => $e->getMessage())));

+      return FALSE;

+    }

+

+    return TRUE;

+  }

+

+  /**

+   * Unloads the workbook.

+   */

+  public function unload() {

+    $this->workbook->disconnectWorksheets();

+    unset($this->workbook);

+  }

+

+  /**

+   * Returns a string representing the source query.

+   *

+   * @return string

+   */

+  public function __toString() {

+    return $this->file;

+  }

+

+  /**

+   * Returns a list of fields available to be mapped from the source query.

+   *

+   * @return array

+   *   Keys: machine names of the fields (to be passed to addFieldMapping).

+   *   Values: Human-friendly descriptions of the fields.

+   */

+  public function fields() {

+    $fields = array();

+

+    foreach ($this->fields as $name) {

+      $fields[$name] = $name;

+    }

+

+    return $fields;

+  }

+

+  /**

+   * Returns a count of all available source records.

+   */

+  public function computeCount() {

+    // Subtract 1 for the header.

+    return $this->rows - 1;

+  }

+

+  /**

+   * Implements MigrateSource::performRewind().

+   *

+   * @return void

+   */

+  public function performRewind() {

+    // Initialize the workbook if it isn't already.

+    if (!isset($this->workbook)) {

+      $this->load();

+    }

+

+    $this->rowNumber = 1;

+  }

+

+  /**

+   * Implements MigrateSource::getNextRow().

+   *

+   * @return null|object

+   */

+  public function getNextRow() {

+    migrate_instrument_start('MigrateSourceSpreadsheet::next');

+    ++$this->rowNumber;

+

+    if ($this->rowNumber <= $this->rows) {

+      $row_values = array();

+      for ($col = 0; $col < $this->cols; ++$col) {

+        if (in_array($this->fields[$col], $this->columns) || empty($this->columns)) {

+          $row_values[$this->fields[$col]] = trim($this->worksheet->getCellByColumnAndRow($col, $this->rowNumber)->getValue());

+         }

+      }

+

+      return (object) $row_values;

+    }

+    else {

+      // EOF, close the workbook.

+      $this->unload();

+

+      migrate_instrument_stop('MigrateSourceSpreadsheet::next');

+      return NULL;

+    }

+  }

+}

