diff --git a/lwr/tools/validator.py b/lwr/tools/validator.py
new file mode 100644
index 0000000000000000000000000000000000000000..0c949cebcb8cacf61591995fd0a463a42481e88d
--- /dev/null
+++ b/lwr/tools/validator.py
@@ -0,0 +1,59 @@
+from xml.etree.ElementTree import fromstring
+from re import escape, compile
+
+from os.path import join
+
+
+class ExpressionValidator(object):
+
+    def __init__(self, xml_el):
+        if type(xml_el) == str:
+            xml_el = fromstring(xml_el)
+        self.xml_el = xml_el
+
+    def validate(self, job_directory, string):
+        regex = "^%s$" % self._expression_to_regex(job_directory, self.xml_el)
+        return compile(regex).match(string) is not None
+
+    def _expression_to_regex(self, job_directory, element):
+        return r"\s+".join([self._element_to_regex(child, job_directory) for child in list(element)])
+
+    def _element_to_regex(self, element, job_directory):
+        tag = element.tag
+        method_name = "_%s_to_regex" % tag
+        try:
+            method = getattr(self, method_name)
+        except NameError:
+            raise NameError("Unknown XML validation tag [%s]" % tag)
+        return method(element, job_directory)
+
+    def _literal_to_regex(self, element, job_directory):
+        return escape(self.__value_or_text(element))
+
+    def _parameter_to_regex(self, element, job_directory):
+        parameter_name = element.get('name')
+        value_regex = self._expression_to_regex(job_directory, element)
+        return r"%s(?:=|\s+)%s" % (parameter_name, value_regex)
+
+    def _integer_to_regex(self, element, job_directory):
+        return r"\d+"
+
+    def _float_to_regex(self, element, job_directory):
+        # http://stackoverflow.com/a/9392612
+        return r"[-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?"
+
+    def _tool_wrapper_to_regex(self, element, job_directory):
+        wrapper_name = self.__value_or_text(element, "name")
+        path = join(job_directory.path, "tool_files", wrapper_name)
+        return escape(path)
+
+    def _configfile_to_regex(self, element, job_directory):
+        wrapper_name = self.__value_or_text(element, "name")
+        path = join(job_directory.path, "configs", wrapper_name)
+        return escape(path)
+
+    def __value_or_text(self, element, attribute="value"):
+        value = element.get(attribute, None)
+        if value is None:
+            value = element.text
+        return value
diff --git a/test/test_utils.py b/test/test_utils.py
index ebfeba7ff2d5f899054ed9e1138015dfe0ec9952..51909ea1eb8bd1e197aef26ad928073477c952a1 100644
--- a/test/test_utils.py
+++ b/test/test_utils.py
@@ -3,6 +3,19 @@ from lwr.tools import ToolBox
 from os import pardir
 from os.path import join, dirname
 
+from unittest import TestCase
+from tempfile import mkdtemp
+from shutil import rmtree
+
+
+class TempDirectoryTestCase(TestCase):
+
+    def setUp(self):
+        self.temp_directory = mkdtemp()
+
+    def tearDown(self):
+        rmtree(self.temp_directory)
+
 
 def get_test_toolbox():
     toolbox_path = join(dirname(__file__), pardir, "test_data", "test_shed_toolbox.xml")
diff --git a/test/validator_test.py b/test/validator_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..422bb850af50cc6465b4637624a7d72e9796e74e
--- /dev/null
+++ b/test/validator_test.py
@@ -0,0 +1,102 @@
+from test_utils import TempDirectoryTestCase
+
+from lwr.util import JobDirectory
+from lwr.tools.validator import ExpressionValidator
+
+from os.path import join
+
+
+class ValidatorTest(TempDirectoryTestCase):
+
+    def test_literal(self):
+        xml = """
+        <expression>
+            <literal value="tophat2" />
+        </expression>"""
+        self.__assertValid(xml, "tophat2")
+        self.__assertInvalid(xml, "bowtie")
+
+    def test_two_literals(self):
+        xml = """
+        <expression>
+            <literal value="python" />
+            <literal value="setup.py" />
+        </expression>"""
+        self.__assertValid(xml, "python setup.py")
+        self.__assertInvalid(xml, "pythonsetup.py")
+
+    def test_parameter(self):
+        xml = """
+        <expression>
+            <literal value="tophat2" />
+            <parameter name="--mate-std-dev">
+                <literal value="4" />
+            </parameter>
+        </expression>"""
+        self.__assertValid(xml, "tophat2 --mate-std-dev 4")
+        self.__assertValid(xml, "tophat2 --mate-std-dev=4")
+        self.__assertInvalid(xml, "tophat2 --mate-std-dev=5")
+
+    def test_integer(self):
+        xml = """
+        <expression>
+            <literal value="tophat2" />
+            <parameter name="--mate-std-dev">
+                <integer />
+            </parameter>
+        </expression>"""
+        self.__assertValid(xml, "tophat2 --mate-std-dev 4")
+        self.__assertValid(xml, "tophat2 --mate-std-dev=4")
+        self.__assertInvalid(xml, "tophat2 --mate-std-dev=5.0")
+
+    def test_float(self):
+        xml = """
+        <expression>
+            <literal value="tophat2" />
+            <parameter name="--mate-std-dev">
+                <float />
+            </parameter>
+        </expression>"""
+        self.__assertValid(xml, "tophat2 --mate-std-dev 4")
+        self.__assertValid(xml, "tophat2 --mate-std-dev=4")
+        self.__assertValid(xml, "tophat2 --mate-std-dev=5.0")
+        self.__assertValid(xml, "tophat2 --mate-std-dev=4e10")
+        self.__assertValid(xml, "tophat2 --mate-std-dev=-1.0e10")
+        self.__assertValid(xml, "tophat2 --mate-std-dev=-.0e10")
+        self.__assertInvalid(xml, "tophat2 --mate-std-dev=cat")
+
+    def test_tool_wrapper(self):
+        xml = """
+        <expression>
+            <tool_wrapper name="tool1_wrapper.py" />
+        </expression>
+        """
+        self.__assertValid(xml, "%s" % join(self.temp_directory, '1', 'tool_files', 'tool1_wrapper.py'))
+        self.__assertInvalid(xml, "tool1_wrapper.py")
+
+    def test_config_file(self):
+        xml = """
+        <expression>
+            <literal value="tophat2" />
+            <configfile name="top_opts" />
+        </expression>
+        """
+        self.__assertValid(xml, "tophat2 %s" % join(self.temp_directory, '1', 'configs', 'top_opts'))
+        self.__assertInvalid(xml, "tophat2 ../%s" % join(self.temp_directory, '1', 'configs', 'top_opts'))
+        self.__assertInvalid(xml, "tophat2 %s" % join(self.temp_directory, '1', 'configs', 'top_optsX'))
+
+    def __validator(self, xml):
+        return ExpressionValidator(xml)
+
+    @property
+    def job_directory(self):
+        return JobDirectory(self.temp_directory, '1')
+
+    def __is_valid(self, xml, contents):
+        return self.__validator(xml).validate(self.job_directory, contents)
+
+    def __assertValid(self, xml, contents):
+        self.assertTrue(self.__is_valid(xml, contents), "%s did not validate against %s" % (contents, xml))
+
+    def __assertInvalid(self, xml, contents):
+        self.assertFalse(self.__is_valid(xml, contents), "%s falsely validated against %s" % (contents, xml))