diff --git a/migrate_example_advanced/config/install/migrate_plus.migration.weather_soap.yml b/migrate_example_advanced/config/install/migrate_plus.migration.weather_soap.yml
new file mode 100755
index 0000000..5f88af2
--- /dev/null
+++ b/migrate_example_advanced/config/install/migrate_plus.migration.weather_soap.yml
@@ -0,0 +1,35 @@
+# This migration demonstrates importing from SOAP/WSDL.
+id: weather_soap
+label: SOAP service providing weather.
+migration_group: wine
+source:
+  # We use the SOAP parser source plugin.
+  plugin: url
+  data_fetcher_plugin: http # Ignored - SoapClient does the fetching.
+  data_parser_plugin: soap
+  # URL of a WSDL endpoint.
+  urls: http://www.webservicex.net/globalweather.asmx?WSDL
+  # The function to call on the service, and the parameters to pass.
+  function: GetCitiesByCountry
+  parameters:
+    CountryName: Spain
+  item_selector: /NewDataSet/Table
+  fields:
+    -
+      name: Country
+      label: Country
+      selector: Country
+    -
+      name: City
+      label: City
+      selector: City
+  ids:
+    City:
+      type: string
+process:
+  vid:
+    plugin: default_value
+    default_value: migrate_example_wine_varieties
+  name: City
+destination:
+  plugin: entity:taxonomy_term
diff --git a/src/Plugin/migrate_plus/data_parser/Soap.php b/src/Plugin/migrate_plus/data_parser/Soap.php
new file mode 100755
index 0000000..fb26113
--- /dev/null
+++ b/src/Plugin/migrate_plus/data_parser/Soap.php
@@ -0,0 +1,87 @@
+<?php
+
+namespace Drupal\migrate_plus\Plugin\migrate_plus\data_parser;
+
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\migrate_plus\DataParserPluginBase;
+
+/**
+ * Obtain SOAP data for migration.
+ *
+ * @DataParser(
+ *   id = "soap",
+ *   title = @Translation("SOAP")
+ * )
+ */
+class Soap extends DataParserPluginBase implements ContainerFactoryPluginInterface {
+
+  /**
+   * Iterator over the SOAP data.
+   *
+   * @var \Iterator
+   */
+  protected $iterator;
+
+  /**
+   * Method to call on the SOAP service.
+   *
+   * @var string
+   */
+  protected $function;
+
+  /**
+   * Parameters to pass to the SOAP service function.
+   * @var array
+   */
+  protected $parameters;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+    $this->function = $configuration['function'];
+    $this->parameters = $configuration['parameters'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function openSourceUrl($url) {
+    // @todo Add error handling each step of the way.
+    $client = new \SoapClient($url);
+    // Determine the response property name.
+    foreach ($client->__getFunctions() as $function_signature) {
+      $response_type = strtok($function_signature, ' ');
+      $function_name = strtok('(');
+      if (strcasecmp($function_name, $this->function) === 0) {
+        foreach ($client->__getTypes() as $type_info) {
+          if (preg_match('|struct (.*?) {\s*string (.*?);|is', $type_info, $matches)) {
+            if ($matches[1] == $response_type) {
+              $response_property = $matches[2];
+            }
+          }
+        }
+        break;
+      }
+    }
+    $response = $client->{$this->function}($this->parameters);
+    $xml = simplexml_load_string($response->{$response_property});
+    $this->iterator = new \ArrayIterator($xml->xpath($this->itemSelector));
+    return TRUE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function fetchNextRow() {
+    $current = $this->iterator->current();
+    if ($current) {
+      foreach ($this->fieldSelectors() as $field_name => $selector) {
+        $this->currentItem[$field_name] = $current->$selector;
+      }
+      $this->iterator->next();
+    }
+  }
+
+}
