diff --git a/libtaskotron.spec b/libtaskotron.spec
--- a/libtaskotron.spec
+++ b/libtaskotron.spec
@@ -31,6 +31,7 @@
 Requires:       python-progressbar >= 2.3
 Requires:       python-requests >= 2.7.0
 Requires:       python-setuptools
+Requires:       python2-xunitparser >= 1.3.3
 Requires:       PyYAML >= 3.11
 Requires:       resultsdb_api >= 1.2.1
 BuildRequires:  pytest >= 2.7.3
diff --git a/libtaskotron/directives/xunit_directive.py b/libtaskotron/directives/xunit_directive.py
new file mode 100644
--- /dev/null
+++ b/libtaskotron/directives/xunit_directive.py
@@ -0,0 +1,111 @@
+# -*- coding: utf-8 -*-
+# Copyright 2009-2014, Red Hat, Inc.
+# License: GPL-2.0+ <http://spdx.org/licenses/GPL-2.0+>
+# See the LICENSE file for more details on Licensing
+
+from __future__ import absolute_import
+
+import xunitparser
+
+from libtaskotron.directives import BaseDirective
+from libtaskotron.exceptions import TaskotronDirectiveError
+from libtaskotron.check import CheckDetail, export_YAML
+
+DOCUMENTATION = """
+module: xunit_directive
+short_description: parse XML xUnit file
+description: |
+  Parse test ouput in XML xUnit format and generate ResultYAML for further use (i.e. in resultsdb)
+parameters:
+  file:
+    required: true
+    description: xml file to be parsed, relative path is to the task formula file
+    type: str
+  agregation:
+    required: false
+    description: type of result agregation, ``none`` means no agregation will be use and all
+      testcases will be reporter as separate results. ``allpass`` will agregate testcases into
+      one results with outcome ``PASSED`` if all testcases passed otherwise ``FAILED`` outcome is
+      set.
+      If not provided ``allpass`` is default value.
+    type: str
+returns: |
+  Returns output of the check in the ResultYAML format directly usable in
+  :ref:`resultsdb directive <resultsdb_directive>`
+
+raises: |
+  * :class:`.TaskotronDirectiveError`: if ``file`` was not provided or agregation
+    was set to unknown type.
+
+"""
+
+EXAMPLES = """
+This example parses XML file located in ``artifactsdir`` generates ResultYAML with no agregation
+and exports it to variable which is finally passed to ``resultsdb``::
+
+  - name: parse test output
+    xunit:
+        file: ${artifactsdir}/output.xml
+        agregation: none
+    export: test_output
+
+  - name: report results to resultsdb
+    resultsdb:
+        results: ${test_output}
+"""
+
+agregations = ['none', 'allpass']
+
+directive_class = 'XunitDirective'
+
+
+class XunitDirective(BaseDirective):
+    def process(self, params, arg_data):
+        try:
+            artifact = params['file']
+        except KeyError:
+            raise TaskotronDirectiveError('No file provided.')
+
+        agregation = params.get('agregation', 'allpass')
+
+        if not arg_data['item'] or not arg_data['type']:
+            raise TaskotronDirectiveError('Item and its type has to be provided.')
+
+        if agregation not in agregations:
+            raise TaskotronDirectiveError('Agregation must be one of %s.' % ', '.join(agregations))
+
+        with open(artifact) as xmlfile:
+            testsuite, testresult = xunitparser.parse(xmlfile)
+
+        if agregation == 'none':
+            details = []
+            for tc in testsuite:
+                outcome = 'PASSED' if tc.good else 'FAILED'
+                details.append(CheckDetail(item=arg_data['item'],
+                                           checkname="%s.%s" % (arg_data['checkname'],
+                                                                tc.methodname),
+                                           report_type=arg_data['type'],
+                                           outcome=outcome))
+
+            return export_YAML(details)
+        elif agregation == 'allpass':
+            summary = "%d PASSED, %d FAILED"
+            passed = 0
+            failed = 0
+            final_outcome = 'PASSED'
+            for tc in testsuite:
+                if tc.good:
+                    passed += 1
+                else:
+                    failed += 1
+                    final_outcome = 'FAILED'
+
+            summary = summary % (passed, failed)
+            return export_YAML(CheckDetail(item=arg_data['item'],
+                                           note=summary,
+                                           report_type=arg_data['type'],
+                                           outcome=final_outcome,
+                                           artifact=artifact))
+
+        else:
+            assert False, "This should never happen"
diff --git a/libtaskotron/main.py b/libtaskotron/main.py
--- a/libtaskotron/main.py
+++ b/libtaskotron/main.py
@@ -19,7 +19,7 @@
 
 
 # The list of accepted item types on the command line (--type option)
-_ITEM_TYPES = ["bodhi_id", "koji_build", "koji_tag", "compose"]
+_ITEM_TYPES = ["bodhi_id", "koji_build", "koji_tag", "compose", "docker_image"]
 
 
 def get_argparser():
diff --git a/requirements.txt b/requirements.txt
--- a/requirements.txt
+++ b/requirements.txt
@@ -24,3 +24,4 @@
 PyYAML == 3.11
 resultsdb_api == 1.2.1
 Sphinx == 1.2.3
+xunitparser == 1.3.3
diff --git a/testing/test_xunit_directive.py b/testing/test_xunit_directive.py
new file mode 100644
--- /dev/null
+++ b/testing/test_xunit_directive.py
@@ -0,0 +1,137 @@
+# -*- coding: utf-8 -*-
+# Copyright 2009-2014, Red Hat, Inc.
+# License: GPL-2.0+ <http://spdx.org/licenses/GPL-2.0+>
+# See the LICENSE file for more details on Licensing
+
+from libtaskotron.directives import xunit_directive
+from libtaskotron.exceptions import TaskotronDirectiveError
+from libtaskotron.check import import_YAML
+
+import mock
+import pytest
+import xunitparser
+import io
+
+OUTPUT = 'Kilo kabanosu naprudko'
+
+XML = """<?xml version="1.0"?>
+<testsuite errors="0" failures="0" name="pytest" skips="0" tests="3" time="17.131">
+<testcase classname="test.TestClass" file="test.py" line="30" name="test1" time="2.76759004593">
+<system-out></system-out></testcase>
+<testcase classname="test.TestClass" file="test.py" line="34" name="test2" time="2.67303919792">
+<system-out></system-out></testcase>
+<testcase classname="test.TestClass" file="test.py" line="52" name="test3" time="11.6780951023">
+<system-out></system-out></testcase></testsuite>"""
+
+
+class TestCheckParams(object):
+    def test_file_present(self, monkeypatch):
+        test_params = {'file': 'json.xml'}
+        test_arg_data = {'item': 'starobrno', 'type': 'skopek'}
+
+        test_directive = xunit_directive.XunitDirective()
+
+        stub_parse = mock.MagicMock(return_value=([], True))
+        monkeypatch.setattr(xunitparser, 'parse', stub_parse)
+
+        with mock.patch('__builtin__.open', mock.mock_open(), create=True):
+            with mock.patch('libtaskotron.directives.xunit_directive.export_YAML',
+                            mock.MagicMock(return_value=OUTPUT)):
+                output = test_directive.process(test_params, test_arg_data)
+
+        assert output == OUTPUT
+
+    def test_file_not_present(self, monkeypatch):
+        test_params = {'fila': 'json.xml'}
+        test_arg_data = {'item': 'starobrno', 'type': 'skopek'}
+        test_directive = xunit_directive.XunitDirective()
+
+        stub_parse = mock.MagicMock(return_value=([], True))
+        monkeypatch.setattr(xunitparser, 'parse', stub_parse)
+
+        with mock.patch('__builtin__.open', mock.mock_open(), create=True):
+            with pytest.raises(TaskotronDirectiveError):
+                test_directive.process(test_params, test_arg_data)
+
+    def test_item_not_present(self, monkeypatch):
+        test_params = {'file': 'json.xml'}
+        test_arg_data = {'item': None, 'type': 'skopek'}
+        test_directive = xunit_directive.XunitDirective()
+
+        stub_parse = mock.MagicMock(return_value=([], True))
+        monkeypatch.setattr(xunitparser, 'parse', stub_parse)
+
+        with mock.patch('__builtin__.open', mock.mock_open(), create=True):
+            with pytest.raises(TaskotronDirectiveError):
+                test_directive.process(test_params, test_arg_data)
+
+    def test_type_not_present(self, monkeypatch):
+        test_params = {'file': 'json.xml'}
+        test_arg_data = {'item': 'starobrno', 'type': None}
+        test_directive = xunit_directive.XunitDirective()
+
+        stub_parse = mock.MagicMock(return_value=([], True))
+        monkeypatch.setattr(xunitparser, 'parse', stub_parse)
+
+        with mock.patch('__builtin__.open', mock.mock_open(), create=True):
+            with pytest.raises(TaskotronDirectiveError):
+                test_directive.process(test_params, test_arg_data)
+
+    def test_file_does_not_exist(self, monkeypatch):
+        test_params = {'file': 'json.xml'}
+        test_arg_data = {'item': 'starobrno', 'type': 'skopek'}
+        test_directive = xunit_directive.XunitDirective()
+
+        stub_parse = mock.MagicMock(return_value=([], True))
+        monkeypatch.setattr(xunitparser, 'parse', stub_parse)
+
+        with pytest.raises(IOError):
+            test_directive.process(test_params, test_arg_data)
+
+    def test_agregation_unknown(self, monkeypatch):
+        test_params = {'file': 'json.xml', 'agregation': 'allfail'}
+        test_arg_data = {'item': 'starobrno', 'type': 'skopek'}
+        test_directive = xunit_directive.XunitDirective()
+
+        stub_parse = mock.MagicMock(return_value=([], True))
+        monkeypatch.setattr(xunitparser, 'parse', stub_parse)
+
+        with pytest.raises(TaskotronDirectiveError):
+            test_directive.process(test_params, test_arg_data)
+
+    def test_agregation_none(self, monkeypatch):
+        test_params = {'file': 'json.xml', 'agregation': 'none'}
+        test_arg_data = {'item': 'starobrno', 'type': 'skopek', 'checkname': 'ochutnavka'}
+        test_directive = xunit_directive.XunitDirective()
+
+        # https://bugzilla.redhat.com/show_bug.cgi?id=1244145#c18
+        # with mock.patch('__builtin__.open', mock.mock_open(read_data=XML), create=True):
+        with mock.patch('__builtin__.open', mock.MagicMock(return_value=io.BytesIO(XML)),
+                        create=True):
+            output = test_directive.process(test_params, test_arg_data)
+
+        assert len(import_YAML(output)) == 3
+
+    def test_agregation_allpass(self, monkeypatch):
+        test_params = {'file': 'json.xml', 'agregation': 'allpass'}
+        test_arg_data = {'item': 'starobrno', 'type': 'skopek'}
+        test_directive = xunit_directive.XunitDirective()
+
+        # ditto
+        with mock.patch('__builtin__.open', mock.MagicMock(return_value=io.BytesIO(XML)),
+                        create=True):
+            output = test_directive.process(test_params, test_arg_data)
+
+        assert len(import_YAML(output)) == 1
+
+    def test_agregation_allpass_default(self, monkeypatch):
+        test_params = {'file': 'json.xml'}
+        test_arg_data = {'item': 'starobrno', 'type': 'skopek'}
+        test_directive = xunit_directive.XunitDirective()
+
+        # ditto
+        with mock.patch('__builtin__.open', mock.MagicMock(return_value=io.BytesIO(XML)),
+                        create=True):
+            output = test_directive.process(test_params, test_arg_data)
+
+        assert len(import_YAML(output)) == 1

