diff --git a/plugins/views_data_export_plugin_style_export_xml.inc b/plugins/views_data_export_plugin_style_export_xml.inc
index 8e6d790..2e96b4f 100644
--- a/plugins/views_data_export_plugin_style_export_xml.inc
+++ b/plugins/views_data_export_plugin_style_export_xml.inc
@@ -12,6 +12,26 @@
 class views_data_export_plugin_style_export_xml extends views_data_export_plugin_style_export {
 
   /**
+   * Initialize a style plugin.
+   */
+  function init(&$view, &$display, $options = NULL) {
+    // View is not set in option_definition(), so we fill defaults here if
+    // options are empty.
+    if (empty($options['root_node']) || empty($options['item_node'])) {
+      $base_object_name = rtrim($view->base_table, 's');
+
+      if (empty($options['root_node'])) {
+        $options['root_node'] = $base_object_name . 's';
+      }
+      if (empty($options['item_node'])) {
+        $options['item_node'] = $base_object_name;
+      }
+    }
+
+    parent::init($view, $display, $options);
+  }
+
+  /**
    * Set options fields and default values.
    *
    * @return
@@ -28,6 +48,14 @@ class views_data_export_plugin_style_export_xml extends views_data_export_plugin
       'default' => 'dash',
       'translatable' => FALSE,
     );
+    $options['root_node'] = array(
+      'default' => '',
+      'translatable' => FALSE,
+    );
+    $options['item_node'] = array(
+      'default' => '',
+      'translatable' => FALSE,
+    );
 
     return $options;
   }
@@ -66,5 +94,17 @@ class views_data_export_plugin_style_export_xml extends views_data_export_plugin
         'edit-style-options-transform' => array(TRUE),
       ),
     );
+    $form['root_node'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Root node'),
+      '#default_value' => $this->options['root_node'],
+      '#description' => t('The XML tag for the root node.'),
+    );
+    $form['item_node'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Item node'),
+      '#default_value' => $this->options['item_node'],
+      '#description' => t('The XML tag for an item node.'),
+    );
   }
 }
diff --git a/theme/views_data_export.theme.inc b/theme/views_data_export.theme.inc
index bc69cbd..30c0477 100644
--- a/theme/views_data_export.theme.inc
+++ b/theme/views_data_export.theme.inc
@@ -350,24 +350,14 @@ function template_preprocess_views_data_export_msoffice_header(&$vars) {
  * Preprocess xml output template.
  */
 function template_preprocess_views_data_export_xml_header(&$vars) {
-  // Compute the root XML node, using the base table, and appending an 's' if needed.
-  $root_node = $vars['view']->base_table;
-  if (rtrim($root_node, 's') == $root_node) {
-    $root_node .= 's';
-  }
-  $vars['root_node'] = _views_data_export_xml_tag_clean($root_node);
+  $vars['root_node'] = _views_data_export_xml_tag_clean($vars['options']['root_node']);
 }
 
 /**
  * Preprocess xml output template.
  */
 function template_preprocess_views_data_export_xml_footer(&$vars) {
-  // Compute the root XML node, using the base table, and appending an 's' if needed.
-  $root_node = $vars['view']->base_table;
-  if (rtrim($root_node, 's') == $root_node) {
-    $root_node .= 's';
-  }
-  $vars['root_node'] = _views_data_export_xml_tag_clean($root_node);
+  $vars['root_node'] = _views_data_export_xml_tag_clean($vars['options']['root_node']);
 }
 
 /**
@@ -379,8 +369,7 @@ function template_preprocess_views_data_export_xml_body(&$vars) {
   $vars['hide_empty_support'] = TRUE;
   _views_data_export_body_shared_preprocess($vars);
 
-  // Compute the tag name based on the views base table, minus any trailing 's'.
-  $vars['item_node'] = _views_data_export_xml_tag_clean(rtrim($vars['view']->base_table, 's'));
+  $vars['item_node'] = _views_data_export_xml_tag_clean($vars['options']['item_node']);
 
   foreach ($vars['themed_rows'] as $num => $row) {
     foreach ($row as $field => $content) {
