diff --git a/tests/testing_html/sample.html b/tests/testing_html/sample.html
new file mode 100644
index 0000000..9fadd13
--- /dev/null
+++ b/tests/testing_html/sample.html
@@ -0,0 +1,6 @@
+<p>one paragraph with special characters: äöüľščťžýáíéäňú©«®™»</p>
+<p>one paragraph with a <br />break line</p>
+<p>one paragraph with html entities: &amp;&lt;&gt;</p>
+<p>and here we have some link <a href="http://example.com">break line</a></p>
+<p>one paragraph with an <img src="not-existing.gif" alt="not existing image" title="not existing image" />image</p>
+<p>hello <span class="green">world</span> this is <span class="red">simple html</span></p><div>nested 1<div>nested 2<div>nested 3</div></div></div>
diff --git a/tests/tmgmt_test.info b/tests/tmgmt_test.info
index b6ec301..471a8ec 100644
--- a/tests/tmgmt_test.info
+++ b/tests/tmgmt_test.info
@@ -4,5 +4,6 @@ core = 7.x
 hidden = TRUE
 dependencies[] = tmgmt
 files[] = tmgmt_test.plugin.source.inc
+files[] = tmgmt_test.plugin.html_source.inc
 files[] = tmgmt_test.plugin.translator.inc
 files[] = tmgmt_test.ui.translator.inc
diff --git a/tests/tmgmt_test.module b/tests/tmgmt_test.module
index 82abbba..d67c23a 100644
--- a/tests/tmgmt_test.module
+++ b/tests/tmgmt_test.module
@@ -32,6 +32,11 @@ function tmgmt_test_tmgmt_source_plugin_info() {
       'description' => t('Simple source for testing purposes.'),
       'plugin controller class' => 'TMGMTTestSourcePluginController',
     ),
+    'test_html_source' => array(
+      'label' => t('Test html source'),
+      'description' => t('HTML source for testing purposes.'),
+      'plugin controller class' => 'TMGMTTestHTMLSourcePluginController',
+    ),
   );
 }
 
@@ -51,3 +56,15 @@ function tmgmt_test_tmgmt_source_suggestions(array $items, TMGMTJob $job) {
   }
   return $suggestions;
 }
+
+/**
+ * Implements hook_tmgmt_fle_text_processor_plugin_info().
+ */
+function tmgmt_test_tmgmt_file_text_processor_plugin_info() {
+  return array(
+    'test' => array(
+      'label' => t('Test'),
+      'plugin controller class' => 'TMGMTTestTextProcessor',
+    ),
+  );
+}
diff --git a/tests/tmgmt_test.plugin.html_source.inc b/tests/tmgmt_test.plugin.html_source.inc
new file mode 100644
index 0000000..eed0b1b
--- /dev/null
+++ b/tests/tmgmt_test.plugin.html_source.inc
@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * @file
+ * Contains the test source plugin with html.
+ */
+
+class TMGMTTestHTMLSourcePluginController extends TMGMTTestSourcePluginController {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getData(TMGMTJobItem $job_item) {
+    return array(
+      'dummy' => array(
+        'deep_nesting' => array(
+          '#text' => file_get_contents(drupal_get_path('module', 'tmgmt') . '/tests/testing_html/sample.html'),
+          '#label' => 'Label for job item with type ' . $job_item->item_type . ' and id ' . $job_item->item_id . '.',
+        ),
+      ),
+    );
+  }
+}
diff --git a/translators/file/tmgmt_file.api.php b/translators/file/tmgmt_file.api.php
index 211a011..283790d 100644
--- a/translators/file/tmgmt_file.api.php
+++ b/translators/file/tmgmt_file.api.php
@@ -32,6 +32,22 @@ function hook_tmgmt_file_format_plugin_info() {
 }
 
 /**
+ * Provide information about available text processors.
+ *
+ * @return array
+ *   An array of available text processor definitions. The key is the text
+ *   processor name.
+ */
+function hook_tmgmt_file_text_processor_plugin_info() {
+  return array(
+    'mask_html_for_xliff' => array(
+      'label' => t('Escape HTML'),
+      'processor class' => 'TMGMTFileXLIFFMaskHTMLProcessor',
+    ),
+  );
+}
+
+/**
  * Alter file format plugins provided by other modules.
  *
  * @see hook_tmgmt_file_format_plugin_info()
diff --git a/translators/file/tmgmt_file.format.xliff.inc b/translators/file/tmgmt_file.format.xliff.inc
index 4c80665..e085a35 100644
--- a/translators/file/tmgmt_file.format.xliff.inc
+++ b/translators/file/tmgmt_file.format.xliff.inc
@@ -2,6 +2,46 @@
 
 /**
  * Export to XLIFF format.
+ *
+ * The XLIFF processor follows this specification:
+ * @link http://docs.oasis-open.org/xliff/v1.2/xliff-profile-html/xliff-profile-html-1.2-cd02.html
+ *
+ * The purpose of this class is to mask or process HTML elements in the source
+ * and target elements so that translation tools are able to understand which
+ * content needs to be translated and ignored.
+ *
+ * On the other hand we need to properly unmask the XLIFF markup back to HTML on
+ * the translation import. So the process is bidirectional and prior to running
+ * the unmasking process we try to validate the integrity in the
+ * validateJobTranslationUponImport() method. Currently the integrity check
+ * involves only a counter of XLIFF elements that have been created during
+ * source processing and has to mach number of XLIFF elements being imported
+ * with the translation.
+ *
+ * To process the content DOMDocument object is used due to its ability to
+ * read broken HTML. This also implies that if broken HTML is in the source
+ * content the translation content will be fixed into the extend of DOMDocument
+ * abilities.
+ *
+ * Following is implemented:
+ * - All pair tags get escaped using <bpt><ept> markup.
+ * - <br> tags are marked with <x ctype="lb">.
+ * - <img> tags are marked with <ph ctype="image"> tags. The title and alt
+ *   attributes should have been extracted into <sub> elements, however are not
+ *   as Trados studio triggers a fatal error in case there are two <sub>
+ *   elements at the same level.
+ *
+ * Not implemented:
+ * - Attributes of <img> element are written only as attributes of <ph> element
+ *   instead of using x-html: prefix. This results in conflict with own <ph>
+ *   element's attributes such as "id". The reason why x-html prefix has not
+ *   been used is that Trados studio triggered fatal error on xml validation.
+ * - Translatable attributes like title and alt.
+ *   @link http://docs.oasis-open.org/xliff/v1.2/xliff-profile-html/xliff-profile-html-1.2-cd02.html#elem_img
+ * - Forms - this is big part
+ *   @link http://docs.oasis-open.org/xliff/v1.2/xliff-profile-html/xliff-profile-html-1.2-cd02.html#HTMLForms
+ * - <pre> elements
+ *   @link http://docs.oasis-open.org/xliff/v1.2/xliff-profile-html/xliff-profile-html-1.2-cd02.html#Elem_preformatted
  */
 class TMGMTFileformatXLIFF extends XMLWriter implements TMGMTFileFormatInterface {
 
@@ -12,6 +52,9 @@ class TMGMTFileformatXLIFF extends XMLWriter implements TMGMTFileFormatInterface
    */
   protected $job;
 
+  protected $importedXML;
+  protected $importedTransUnits;
+
   /**
    * Adds a job item to the xml export.
    *
@@ -44,17 +87,21 @@ class TMGMTFileformatXLIFF extends XMLWriter implements TMGMTFileFormatInterface
    */
   protected function addTransUnit($key, $element) {
 
+    $key_array = tmgmt_ensure_keys_array($key);
+
     $this->startElement('trans-unit');
     $this->writeAttribute('id', $key);
     $this->writeAttribute('resname', $key);
 
     $this->startElement('source');
     $this->writeAttribute('xml:lang', $this->job->getTranslator()->mapToRemoteLanguage($this->job->source_language));
-    $this->text($element['#text']);
+    $this->writeRaw($this->processForExport($element['#text'], $key_array[0]));
     $this->endElement();
     $this->startElement('target');
     $this->writeAttribute('xml:lang', $this->job->getTranslator()->mapToRemoteLanguage($this->job->target_language));
-    $this->text($element['#text']);
+    // @todo - temporary solution, it will be changed in the [#2006786]
+    $target = (!empty($element['#translation']['#text']) ? $element['#translation']['#text'] : $element['#text']);
+    $this->writeRaw($this->processForExport($target, $key_array[0]));
     $this->endElement();
     if (isset($element['#label'])) {
       $this->writeElement('note', $element['#label']);
@@ -124,39 +171,20 @@ class TMGMTFileformatXLIFF extends XMLWriter implements TMGMTFileFormatInterface
    * {@inheritdoc}
    */
   public function import($imported_file) {
-    // It is not possible to load the file directly with simplexml as it gets
-    // url encoded due to the temporary://. This is a PHP bug, see
-    // https://bugs.php.net/bug.php?id=61469
-    $xml_string = file_get_contents($imported_file);
-    $xml = simplexml_load_string($xml_string);
-
-    // Register the xliff namespace, required for xpath.
-    $xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:1.2');
-
-    $data = array();
-    foreach ($xml->xpath('//xliff:trans-unit') as $unit) {
-      $data[(string) $unit['id']]['#text'] = (string) $unit->target;
-    }
-    return tmgmt_unflatten_data($data);
+    $this->getImportedXML($imported_file);
+    return tmgmt_unflatten_data($this->getImportedTargets());
   }
 
   /**
-   * {@inheritdoc}
+   * Validates imported XLIFF file.
+   *
+   * Checks:
+   * - Job ID.
+   * - Target ans source languages
+   * - Content integrity by
    */
   public function validateImport($imported_file) {
-    // It is not possible to load the file directly with simplexml as it gets
-    // url encoded due to the temporary://. This is a PHP bug, see
-    // https://bugs.php.net/bug.php?id=61469
-    $xml_string = file_get_contents($imported_file);
-    $xml = simplexml_load_string($xml_string);
-
-    if (!$xml) {
-      return FALSE;
-    }
-
-    // Register the xliff namespace, required for xpath.
-    $xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:1.2');
-
+    $xml = $this->getImportedXML($imported_file);
     // Check if our phase information is there.
     $phase = $xml->xpath("//xliff:phase[@phase-name='extraction']");
     if ($phase) {
@@ -181,8 +209,331 @@ class TMGMTFileformatXLIFF extends XMLWriter implements TMGMTFileFormatInterface
       return FALSE;
     }
 
+    $targets = $this->getImportedTargets();
+
+    if (empty($targets)) {
+      return FALSE;
+    }
+
+    $reader = new XMLReader();
+    $elements_counts = $job->getSetting('elements_counts');
+
+    foreach ($targets as $id => $target) {
+      $count = 0;
+      $reader->XML('<translation>' . $target['#text'] . '</translation>');
+      while ($reader->read()) {
+        if (in_array($reader->name, array('translation', '#text'))) {
+          continue;
+        }
+        $count++;
+      }
+
+      $keys_array = tmgmt_ensure_keys_array($id);
+      $tjiid = array_shift($keys_array);
+      if (!isset($elements_counts[$tjiid]) || $elements_counts[$tjiid] != $count) {
+        return FALSE;
+      }
+    }
+
     // Validation successful.
     return $job;
   }
 
+  protected function getImportedXML($imported_file) {
+    if (empty($this->importedXML)) {
+      // It is not possible to load the file directly with simplexml as it gets
+      // url encoded due to the temporary://. This is a PHP bug, see
+      // https://bugs.php.net/bug.php?id=61469
+      $xml_string = file_get_contents($imported_file);
+      $this->importedXML = simplexml_load_string($xml_string);
+      // Register the XLIFF namespace, required for xpath.
+      $this->importedXML->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:1.2');
+    }
+
+    return $this->importedXML;
+  }
+
+  protected function getImportedTargets() {
+    if (empty($this->importedXML)) {
+      return FALSE;
+    }
+
+    if (empty($this->importedTransUnits)) {
+      $reader = new XMLReader();
+      foreach ($this->importedXML->xpath('//xliff:trans-unit') as $unit) {
+        $reader->XML($unit->target->asXML());
+        $reader->read();
+        $this->importedTransUnits[(string) $unit['id']]['#text'] = $this->processForImport($reader->readInnerXML());
+      }
+    }
+
+    return $this->importedTransUnits;
+  }
+
+  /**
+   * Processes trans-unit/target to rebuild back the HTML.
+   *
+   * @param string $translation
+   *   Job data array.
+   *
+   * @return string
+   */
+  protected function processForImport($translation) {
+    $reader = new XMLReader();
+    $reader->XML('<translation>' . $translation . '</translation>');
+    $text = '';
+
+    while ($reader->read()) {
+      // If the current element is text append it to the result text.
+      if ($reader->name == '#text' || $reader->name == '#cdata-section') {
+        $text .= $reader->value;
+      }
+      elseif ($reader->name == 'x') {
+        if ($reader->getAttribute('ctype') == 'lb') {
+          $text .= '<br />';
+        }
+      }
+      elseif ($reader->name == 'ph') {
+        if ($reader->getAttribute('ctype') == 'image') {
+          $text .= '<img';
+          while ($reader->moveToNextAttribute()) {
+            // @todo - we have to use x-html: prefixes for attributes.
+            if ($reader->name != 'ctype' && $reader->name != 'id') {
+              $text .= " {$reader->name}=\"{$reader->value}\"";
+            }
+          }
+          $text .= ' />';
+        }
+      }
+    }
+    return $text;
+  }
+
+  /**
+   * Helper function to process the source text.
+   *
+   * @param string $source
+   *   Job data array.
+   * @param int $tjiid
+   *   Job item ID.
+   *
+   * @return string
+   */
+  protected function processForExport($source, $tjiid) {
+    // The reason why we use DOMDocument object here and not just XMLReader
+    // is the DOMDocument's ability to deal with broken HTML.
+    $dom = new DOMDocument();
+    // We need to append the head with encoding so that special characters
+    // are read correctly.
+    $dom->loadHTML("<html><head><meta http-equiv='Content-type' content='text/html; charset=UTF-8' /></head><body>" . $source . '</body></html>');
+
+    $iterator = new RecursiveIteratorIterator(
+      new RecursiveDOMIterator($dom),
+      RecursiveIteratorIterator::SELF_FIRST);
+
+    $writer = new XMLWriter();
+    $writer->openMemory();
+    $writer->startDocument('1.0', 'UTF-8');
+    $writer->startElement('wrapper');
+
+    $tray = array();
+    $non_pair_tags = array('br', 'img');
+    $elements_count = 0;
+
+    /** @var DOMElement $node */
+    foreach ($iterator as $node) {
+
+      if (in_array($node->nodeName, array('html', 'body', 'head', 'meta'))) {
+        continue;
+      }
+
+      if ($node->nodeType === XML_ELEMENT_NODE) {
+        // Increment the elements count and compose element id.
+        $elements_count++;
+        $id = 'tjiid' . $tjiid . '-' . $elements_count;
+
+        $is_pair_tag = !in_array($node->nodeName, $non_pair_tags);
+
+        if ($is_pair_tag) {
+          $this->writeBPT($writer, $node, $id);
+        }
+        elseif ($node->nodeName == 'img') {
+          $this->writeIMG($writer, $node, $id);
+        }
+        elseif ($node->nodeName == 'br') {
+          $this->writeBR($writer, $node, $id);
+        }
+
+        // Add to tray new element info.
+        $tray[$id] = array(
+          'name' => $node->nodeName,
+          'id' => $id,
+          'value' => $node->nodeValue,
+          'built_text' => '',
+          'is_pair_tag' => $is_pair_tag,
+        );
+
+      }
+      // The current node is a text.
+      elseif ($node->nodeName == '#text') {
+        // Add the node value to the text output.
+        $writer->writeCdata($this->toEntities($node->nodeValue));
+        foreach ($tray as &$info) {
+          $info['built_text'] .= $node->nodeValue;
+        }
+      }
+
+      // Reverse so that pair tags are closed in the expected order.
+      $reversed_tray = array_reverse($tray);
+      foreach ($reversed_tray as $_info) {
+        // If the build_text equals to the node value and it is not a pair tag
+        // add the end pair tag markup.
+        if ($_info['value'] == $_info['built_text'] && $_info['is_pair_tag']) {
+          // Count also for the closing elements.
+          $elements_count++;
+          $this->writeEPT($writer, $_info['name'], $_info['id']);
+          // When the end pair tag has been written unset the element info
+          // from the tray.
+          unset($tray[$_info['id']]);
+        }
+      }
+    }
+
+    // Set the elements count for the current item into job settings.
+    $this->job->settings['elements_counts'][$tjiid] = $elements_count;
+    $this->job->save();
+
+    $writer->endElement();
+    // Load the output with XMLReader so that we can easily get the inner xml.
+    $reader = new XMLReader();
+    $reader->XML($writer->outputMemory());
+    $reader->read();
+    return $reader->readInnerXML();
+  }
+
+  /**
+   * Writes br tag.
+   *
+   * @param XMLWriter $writer
+   *   Writer that writes the output.
+   * @param DOMElement $node
+   *   Current node.
+   * @param $id
+   *   Current node id.
+   */
+  protected function writeBR(XMLWriter $writer, DOMElement $node, $id) {
+    $writer->startElement('x');
+    $writer->writeAttribute('id', $id);
+    $writer->writeAttribute('ctype', 'lb');
+    $writer->endElement();
+  }
+
+  /**
+   * Writes beginning pair tag.
+   *
+   * @param XMLWriter $writer
+   *   Writer that writes the output.
+   * @param DOMElement $node
+   *   Current node.
+   * @param $id
+   *   Current node id.
+   */
+  protected function writeBPT(XMLWriter $writer, DOMElement $node, $id) {
+    $beginning_tag = '<' . $node->nodeName;
+    if ($node->hasAttributes()) {
+      $attributes = array();
+      /** @var DOMAttr $attribute */
+      foreach ($node->attributes as $attribute) {
+        $attributes[] = $attribute->name . '="' . $attribute->value . '"';
+      }
+
+      $beginning_tag .= ' '. implode(' ', $attributes);
+    }
+    $beginning_tag .= '>';
+    $writer->startElement('bpt');
+    $writer->writeAttribute('id', $id);
+    $writer->text($beginning_tag);
+    $writer->endElement();
+  }
+
+  /**
+   * Writes ending pair tag.
+   *
+   * @param XMLWriter $writer
+   *   Writer that writes the output.
+   * @param string $name
+   *   Ending tag name.
+   * @param $id
+   *   Current node id.
+   */
+  protected function writeEPT(XMLWriter $writer, $name, $id) {
+    $writer->startElement('ept');
+    $writer->writeAttribute('id', $id);
+    $writer->text('</' . $name . '>');
+    $writer->endElement();
+  }
+
+  /**
+   * Writes img tag.
+   *
+   * Note that alt and title attributes are not written as sub elements as
+   * Trados studio is not able to deal with two sub elements at one level.
+   *
+   * @param XMLWriter $writer
+   *   Writer that writes the output.
+   * @param DOMElement $node
+   *   Current node.
+   * @param $id
+   *   Current node id.
+   */
+  protected function writeIMG(XMLWriter $writer, DOMElement $node, $id) {
+    $writer->startElement('ph');
+    $writer->writeAttribute('id', $id);
+    $writer->writeAttribute('ctype', 'image');
+    foreach ($node->attributes as $attribute) {
+      // @todo - uncomment when issue with Trados/sub elements fixed.
+      /*
+      if (in_array($attribute->name, array('title', 'alt'))) {
+        continue;
+      }
+      */
+      $writer->writeAttribute($attribute->name, $attribute->value);
+    }
+    /*
+    if ($alt_attribute = $node->getAttribute('alt')) {
+      $writer->startElement('sub');
+      $writer->writeAttribute('id', $id . '-img-alt');
+      $writer->writeAttribute('ctype', 'x-img-alt');
+      $writer->text($alt_attribute);
+      $writer->endElement();
+      $this->elementsCount++;
+    }
+    if ($title_attribute = $node->getAttribute('title')) {
+      $writer->startElement('sub');
+      $writer->writeAttribute('id', $id . '-img-title');
+      $writer->writeAttribute('ctype', 'x-img-title');
+      $writer->text($title_attribute);
+      $writer->endElement();
+      $this->elementsCount++;
+    }
+    */
+    $writer->endElement();
+  }
+
+  /**
+   * Convert critical characters to HTML entities.
+   *
+   * DOMDocument will convert HTML entities to its actual characters. This can
+   * lead into situation when not allowed characters will appear in the content.
+   *
+   * @param string $string
+   *   String to escape.
+   *
+   * @return string
+   *   Escaped string.
+   */
+  protected function toEntities($string) {
+    return str_replace(array('&', '>', '<'), array('&amp;', '&gt;', '&lt;'), $string);
+  }
+
 }
diff --git a/translators/file/tmgmt_file.info b/translators/file/tmgmt_file.info
index 6331f00..786d890 100644
--- a/translators/file/tmgmt_file.info
+++ b/translators/file/tmgmt_file.info
@@ -9,4 +9,5 @@ files[] = tmgmt_file.ui.inc
 files[] = tmgmt_file.format.interface.inc
 files[] = tmgmt_file.format.xliff.inc
 files[] = tmgmt_file.format.html.inc
+files[] = tmgmt_file.recursive_iterator.inc
 files[] = tmgmt_file.test
diff --git a/translators/file/tmgmt_file.module b/translators/file/tmgmt_file.module
index a3b6a29..fdadb5c 100644
--- a/translators/file/tmgmt_file.module
+++ b/translators/file/tmgmt_file.module
@@ -56,7 +56,7 @@ function tmgmt_file_import_form_submit($form, &$form_state) {
         try {
           // Validation successful, start import.
           $job->addTranslatedData($controller->import($file->uri));
-          $job->addMessage('Sucessfully imported file.');
+          $job->addMessage('Successfully imported file.');
         } catch (Exception $e) {
           $job->addMessage('File import failed with the following message: @message', array('@message' => $e->getMessage()), 'error');
         }
@@ -80,7 +80,7 @@ function tmgmt_file_import_form_submit($form, &$form_state) {
  * @param $plugin
  *   (Optional) Name of a plugin/extension.
  *
- * @return
+ * @return array
  *   If a plugin name is provided, information about that plugin, an array of
  *   plugin information otherwise. The information of each plugin consists of
  *   the label and plugin controller class, keyed by the plugin name which is
@@ -100,6 +100,9 @@ function tmgmt_file_format_plugin_labels() {
 /**
  * Returns the file format plugin controller.
  *
+ * @param $plugin
+ *   (Optional) Name of a plugin/extension.
+ *
  * @return TMGMTFileFormatInterface
  *   Either a specific file format plugin controller instance or an array of
  *   available controllers.
diff --git a/translators/file/tmgmt_file.recursive_iterator.inc b/translators/file/tmgmt_file.recursive_iterator.inc
new file mode 100644
index 0000000..36f2f83
--- /dev/null
+++ b/translators/file/tmgmt_file.recursive_iterator.inc
@@ -0,0 +1,99 @@
+<?php
+/**
+ * @file
+ * Contains RecursiveDOMIterator.
+ */
+
+/**
+ * Class used to iterate through DOMDocument.
+ */
+class RecursiveDOMIterator implements RecursiveIterator {
+  /**
+   * Current position in DOMNodeList.
+   *
+   * @var int
+   */
+  protected $position;
+
+  /**
+   * The DOMNodeList with all children to iterate over.
+   *
+   * @var DOMNodeList
+   */
+  protected $nodeList;
+
+  /**
+   * Constructor.
+   *
+   * @param DOMNode $domNode
+   *   DOMNode to iterate over.
+   */
+  public function __construct(DOMNode $domNode) {
+    $this->position = 0;
+    $this->nodeList = $domNode->childNodes;
+  }
+
+  /**
+   * Returns the current DOMNode.
+   *
+   * @return DOMNode
+   *   Current DOMNode object.
+   */
+  public function current() {
+    return $this->nodeList->item($this->position);
+  }
+
+  /**
+   * Returns an iterator for the current iterator entry.
+   *
+   * @return RecursiveDOMIterator
+   *   Iterator with children elements.
+   */
+  public function getChildren() {
+    return new self($this->current());
+  }
+
+  /**
+   * Checks if current element has children.
+   *
+   * @return bool
+   *   Has children.
+   */
+  public function hasChildren() {
+    return $this->current()->hasChildNodes();
+  }
+
+  /**
+   * Returns the current position.
+   *
+   * @return int
+   *   Current position
+   */
+  public function key() {
+    return $this->position;
+  }
+
+  /**
+   * Moves the current position to the next element.
+   */
+  public function next() {
+    $this->position++;
+  }
+
+  /**
+   * Rewind the Iterator to the first element.
+   */
+  public function rewind() {
+    $this->position = 0;
+  }
+
+  /**
+   * Checks if current position is valid.
+   *
+   * @return bool
+   *   Is valid.
+   */
+  public function valid() {
+    return $this->position < $this->nodeList->length;
+  }
+}
diff --git a/translators/file/tmgmt_file.test b/translators/file/tmgmt_file.test
index 15a6f47..814693d 100644
--- a/translators/file/tmgmt_file.test
+++ b/translators/file/tmgmt_file.test
@@ -25,6 +25,143 @@ class TMGMTFileTestCase extends TMGMTBaseTestCase {
   }
 
   /**
+   * Test the content processing for XLIFF export and import.
+   */
+  function testXLIFFTextProcessing() {
+    $translator = $this->createTranslator();
+    $translator->plugin = 'file';
+    $translator->settings = array(
+      'export_format' => 'xlf',
+    );
+    $translator->save();
+
+    // Create the reader instance, it will be used through the tests.
+    $reader = new XMLReader();
+    $xliff_elements = array('bpt', 'ept', 'ph', 'x', '#text', '#cdata-section', 'content');
+
+    // ==== First test the whole cycle ==== //
+    $job = $this->createJob();
+    $job->translator = $translator->name;
+    $job->addItem('test_html_source', 'test', '1');
+
+    // Requesting translation will mask the html.
+    $job->requestTranslation();
+    $content = $this->getTransUnitsContent($job);
+    // Test that the exported trans unit contains only xliff elements.
+    $reader->XML('<content>' . $content[0]['source'] . '</content>');
+    while ($reader->read()) {
+      if (!in_array($reader->name, $xliff_elements)) {
+        $this->fail(t('The source contains unexpected element %element', array('%element' => $reader->name)));
+      }
+    }
+    $reader->XML('<content>' . $content[0]['target'] . '</content>');
+    while ($reader->read()) {
+      if (!in_array($reader->name, $xliff_elements)) {
+        $this->fail(t('The target contains unexpected element %element', array('%element' => $reader->name)));
+      }
+    }
+
+    // Import the file, make sure all the html has been revealed and no xliff
+    // elements are present in the job translation.
+    $messages = $job->getMessages();
+    $message = reset($messages);
+    $download_url = $message->variables['!link'];
+    $xml = simplexml_load_file($download_url);
+    $translated_file = 'public://tmgmt_file/translated.xlf';
+    $xml->asXML($translated_file);
+    $uri = $job->uri();
+    $edit = array(
+      'files[file]' => $translated_file,
+    );
+    $this->drupalPost($uri['path'] . '/manage', $edit, t('Import'));
+    // Reset caches and reload job.
+    entity_get_controller('tmgmt_job')->resetCache();
+    entity_get_controller('tmgmt_job_item')->resetCache();
+    $job = tmgmt_job_load($job->tjid);
+
+    // Do the comparison of the translation text and the source. I must be the
+    // same as there was change done to the translation.
+    $item_data = $job->getData(array(1, 'dummy', 'deep_nesting'));
+    $source_text = trim(file_get_contents(drupal_get_path('module', 'tmgmt') . '/tests/testing_html/sample.html'));
+    $this->assertEqual(trim($item_data[1]['#text']), trim($source_text));
+    $job_items = $job->getItems();
+    /** @var TMGMTJobItem $job_item */
+    $job_item = array_shift($job_items);
+    // Job item must be in review.
+    $this->assertTrue($job_item->isNeedsReview());
+
+    // ==== Test integrity check ==== //
+    $job = $this->createJob();
+    $job->translator = $translator->name;
+    $job->addItem('test_html_source', 'test', '1');
+    $job->requestTranslation();
+
+    $messages = $job->getMessages();
+    $message = reset($messages);
+    // Get the xml content and remove the element representing <br />. This will
+    // result in different element counts in the source and target and should
+    // trigger an error and not import the translation.
+    $content = str_replace('<x id="tjiid2-4" ctype="lb"/>', '', file_get_contents($message->variables['!link']));
+    $xml = simplexml_load_string($content);
+    $translated_file = 'public://tmgmt_file/translated.xlf';
+    $xml->asXML($translated_file);
+    $uri = $job->uri();
+    $edit = array(
+      'files[file]' => $translated_file,
+    );
+    $this->drupalPost($uri['path'] . '/manage', $edit, t('Import'));
+    entity_get_controller('tmgmt_job')->resetCache();
+    entity_get_controller('tmgmt_job_item')->resetCache();
+    $job = tmgmt_job_load($job->tjid);
+
+    $integrity_check_failed = FALSE;
+    /** @var TMGMTMessage $message */
+    foreach ($job->getMessages() as $message) {
+      if ($message->getMessage() == t('Failed to validate file, import aborted.')) {
+        $integrity_check_failed = TRUE;
+      }
+    }
+    // We must have the message that integrity check failed.
+    $this->assertTrue($integrity_check_failed);
+
+    $job_items = $job->getItems();
+    /** @var TMGMTJobItem $job_item */
+    $job_item = array_shift($job_items);
+    // Job item must be in active state => translation not imported.
+    $this->assertTrue($job_item->isActive());
+  }
+
+  /**
+   * Gets trans-unit content from the XLIFF file that has been exported for the
+   * given job as last.
+   */
+  protected function getTransUnitsContent(TMGMTJob $job) {
+    $messages = $job->getMessages();
+    $message = reset($messages);
+    $download_url = $message->variables['!link'];
+    $xml_string = file_get_contents($download_url);
+    $xml = simplexml_load_string($xml_string);
+
+    // Register the xliff namespace, required for xpath.
+    $xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:1.2');
+
+    $reader = new XMLReader();
+    $data = array();
+    $i = 0;
+    foreach ($xml->xpath('//xliff:trans-unit') as $unit) {
+      $reader->XML($unit->source->asXML());
+      $reader->read();
+      $data[$i]['source'] = $reader->readInnerXML();
+      $reader->XML($unit->target->asXML());
+      $reader->read();
+      $data[$i]['target'] = $reader->readInnerXML();
+      $i++;
+    }
+
+    return $data;
+  }
+
+  /**
    * Tests export and import for the HTML format.
    */
   function testHTML() {
@@ -64,7 +201,7 @@ class TMGMTFileTestCase extends TMGMTBaseTestCase {
   }
 
   /**
-   * Tests import and export for the xliff format.
+   * Tests import and export for the XLIFF format.
    */
   function testXLIFF() {
     $translator = $this->createTranslator();
@@ -118,6 +255,10 @@ class TMGMTFileTestCase extends TMGMTBaseTestCase {
     $wrong_xml = clone $xml;
     $second_job = $this->createJob();
     $second_job->translator = $translator->name;
+    // We need to add the elements count value into settings, otherwise the
+    // validation will fail on integrity check.
+    $second_job->settings['elements_counts'][1] = 0;
+    $second_job->settings['elements_counts'][2] = 0;
     $second_job->save();
     $wrong_xml->file->header->{'phase-group'}->phase['job-id'] = $second_job->tjid;
     $wrong_file = 'public://tmgmt_file/wrong_file.xlf';
