diff --git a/README.md b/README.md
index b962730ad56b62437e1014b7013585930517c73f..95e106bd84d2068ae9332915ba11dbc712f61485 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ REST service for the validation of ```xml``` against a XML Schema (```xsd```).
 > cd xml-validation
 > python3 -m venv .
 > source bin/activate
-> pip install flask flask_cors xmlschema requests GitPython
+> pip install flask flask_cors xmlschema requests GitPython urlparse
 > ./server
 ```
 
diff --git a/config.json b/config.json
index d72f8bb118dad58ec3d18e35cff046241a10e761..87be2988d19d04ae8476e3534df41d2f62a54c4f 100644
--- a/config.json
+++ b/config.json
@@ -10,6 +10,6 @@
     "mode":"inline,external,local",
     "filename":"dcc.xsd",
     "localPath":"../xsd-dcc/",
-    "externalBaseURL":"https://ptb.de/dcc/"
+    "externalBaseURL":"https://www.ptb.de/dcc/"
   }
 }
diff --git a/server.py b/server.py
index 8199652c6a056acc00e1e9b867bbff6f0f0f40a4..12d2606da848762e8a9eb930366a8dc1fb3c7dfa 100644
--- a/server.py
+++ b/server.py
@@ -51,12 +51,16 @@ def update_xsd():
 @app.route('/validate', methods=['POST'])# TODO: '?v=2.2.0' 
 def validate():
     app.logger.debug('hit validate')
+    xv = request.args.get('v')
     xml_str = request.data
     xml_tree = utils.parse(xml_str)
     if xml_tree:
         print('=== xml_tree OK ===')
-        xsd_str = utils.get_xsd(config, xml_str=xml_str)
-        ret = utils.validate(xml_str=xml_str, xsd_str=xsd_str)
+        xsd_str = utils.get_xsd(config, xsd_version=xv, xml_str=xml_str)
+        if  xsd_str:
+            ret = utils.validate(xml_str=xml_str, xsd_str=xsd_str)
+        else:
+            ret = utils.return_error(error='xsd content not readable')
     else: 
         print('=== xml_tree ??? ===') 
         ret = utils.return_error(error='invalid xml data')
@@ -66,12 +70,13 @@ def validate():
 @app.route('/validation.html', methods=['GET'])
 def validation():
     app.logger.debug('hit validation.html')
-    # pprint(vars(request))
-    lang = str(request.accept_languages).split(',')[0][0:2]
-    print(lang)
-    if lang != 'de':
-        lang = 'en'
-    return trans.show_html(version=git_cmd.describe(), language=lang)
+    # pprint(vars(request)) 
+    l = str(request.accept_languages).split(',')[0][0:2]
+    if l != 'de':
+        l = 'en'
+    x = "['2.2.0','2.1.1','2.1.0']"
+    return trans.show_html(version=git_cmd.describe(), language=l, 
+      xsd_versions=x)
 
 @app.route('/js/<fn>', methods=['GET'])
 def js_folder(fn):
diff --git a/templates/html/validation.html b/templates/html/validation.html
index 121d6f7124bfe851f12d080a7ac14b5eed29c492..113fe47ba05651383efce8bb07ec84bc94bdd42d 100644
--- a/templates/html/validation.html
+++ b/templates/html/validation.html
@@ -37,10 +37,6 @@
         <select id="xsd_version" size="1">
           <option>{{INTERNAL}}</option>
           <option>{{LATEST}}</option>
-          <!-- TODO: Jinja-Schleife ... -->
-          <option>v2.1.0</option>
-          <option>v2.1.1</option>
-          <option>v2.2.0</option>
         </select>
 
     </div>
@@ -58,19 +54,40 @@
         $('#resultArea').hide();
         $('#XML_file').click();
       });
-      $('#XML_file').change(function(){
-        var $this = $(this);
-        var file = $this[0].files[0], name = file.name;
-        $('#log').text('');
+      xsd_list = {{ XSD_VERSIONS|safe }};
+      $xsd_v = $('#xsd_version');
+      for (var i=0; i<xsd_list.length; i++) {
+        $('<option>' + xsd_list[i] + '</option>').appendTo($xsd_v);
+      }
+      function getXSDversion() {
+        const idx = $xsd_v.prop('selectedIndex');
+        if (idx == 0) return false;
+        if (idx == 1) return 'latest';
+        return $xsd_v.val();
+      }
+      function _showError(s) {
+        $('#fname').addClass('ERROR');
+        $('#log').text(s).show();
+      }
+      function showError(s) {
+        _showError('<error>' + s + '</error>error>')
+      }
+      $xsd_v.change(function() {
+        $('#resultArea').hide();
+      });
+      $('#XML_file').change(function() {
+        var file = $(this)[0].files[0];
         $('#resultArea').show();
-        $('#log').hide();
+        $('#log').text('').hide();
         $('#fname').removeClass('SUCCESS ERROR').text(file.name);
         var reader = new FileReader();
         reader.onload = function(e) {
           var base64 = reader.result.replace(/^data.*base64,/, '');
           var dcc = window.atob(base64);
+          var v = getXSDversion();
+          var url = '/validate' + (v ? '?v=' + v : '');
           $.ajax({
-            type:'POST',url:'/validate',data:dcc,
+            type:'POST',url:url,data:dcc,
             dataType:'text',
             contentType:'text/xml;charset="utf-8"'
           })
@@ -78,20 +95,19 @@
             if (d.indexOf('<ok/>') > -1) {
               $('#fname').addClass('SUCCESS');
             } else {
-              $('#fname').addClass('ERROR');
-              $('#log').text(d).show();
+              _showError(d)
             }
           })
           .fail(function(jqXHR, status, e) {
-            alert('Error: ' + e);
+            showError(e);
           });
         }        
         reader.onerror = function(e) {
-          alert('Error: ' + e);
+          showError(e);
           reader.abort();
         }
         reader.onloadend = function() {
-          if (reader.error) alert('Error: ' + reader.error.message);
+          if (reader.error) showError(reader.error);
         };
         reader.readAsDataURL(file);
       });
diff --git a/trans.py b/trans.py
index fafda45527d308adc91f89a46f2fcfa607a7f191..74c9fd9d0e64a5a8c252a22a50141da6c9d2a3be 100644
--- a/trans.py
+++ b/trans.py
@@ -19,7 +19,9 @@ class Trans:
         'LATEST': 'latest'
       }
     }
-    def show_html(self, version, language):
+    def show_html(self, version, language, xsd_versions):
+        print('xsd_versions:' + xsd_versions)
         d = self.mapping[language]
         template = 'html/validation.html'
-        return render_template(template, VERSION=version, **d)
+        return render_template(template, VERSION=version, 
+          XSD_VERSIONS=xsd_versions, **d)
diff --git a/utils.py b/utils.py
index 4f6e4cde8102cb53dd94bd12f37b14ceee35aa5a..931c9dc8893bc9948357100c5e3140e86bd352ae 100644
--- a/utils.py
+++ b/utils.py
@@ -5,9 +5,19 @@ from flask import Response
 from xml.etree import ElementTree as ET
 import xmlschema
 import sys
+from urllib.parse import urlparse
+from pprint import pprint
 
 ns = {"w3":"http://www.w3.org/2001/XMLSchema"}
 
+# https://stackoverflow.com/questions/7160737/python-how-to-validate-a-url-in-python-malformed-or-not
+def uri_validator(x):
+    try:
+        result = urlparse(x)
+        return all([result.scheme, result.netloc, result.path])
+    except:
+        return False
+
 def get_config_dict():
     with open('./config.json') as json_config_file:
         config = json.load(json_config_file)
@@ -20,30 +30,32 @@ def git_cmd(config):
 def get_xsd_path_file(config, file_name):
     return "{dir}/{file_name}".format(dir=config['xsd']['dir'], file_name=file_name)
 
-def get_xsd(cfg, xml_str = None):
-    modes = cfg['xsd']['mode'].split(',')
+def get_xsd(cfg, xsd_version=None, xml_str = None):
     filename =  cfg['xsd']['filename']
+    baseURL = cfg['xsd']['externalBaseURL']
     xsd_str = ''
-    for i in modes: 
-        if i == 'inline' and xml_str:
-            root = parse(xml_str)
-            for item in root.attrib.items():
-                x = item[1].split()
-                for url in x:
-                    if url.endswith(filename):
-                        xsd_str = requests.get(url).text
-                        break 
-        elif i == 'external':
-            url = cfg['xsd']['externalBaseURL'] + filename
-            xsd_str = requests.get(url).text
-        elif i == 'local':
-            f = open(cfg['xsd']['localPath'] + filename, 'r')
-            try:
-                xsd_str = f.read()
-            finally:
-                f.close()
-        if  xsd_str:
-            break
+    url = ''
+    if xsd_version:
+        if xsd_version == 'latest':
+            url = baseURL + filename
+        else:
+            url = baseURL + 'v' + xsd_version + '/' + filename
+    else:
+      root = parse(xml_str)
+      for item in root.attrib.items():
+          x = item[1].split()
+          for url in x:
+              if url.endswith(filename):
+                  break
+    if uri_validator(url):
+        try:
+            r = requests.get(url)
+            #pprint(vars(r))
+            if r.url.endswith(filename): # no bad redirection
+                xsd_str = r.text
+        except:
+            pass
+            
     return xsd_str
 
 def save_xsd(config, xsd_str, file_name):
@@ -76,7 +88,8 @@ def validate(xml_str, xsd_str):
     try:
         schema.validate(tree)
         return return_ok()
-    except xmlschema.XMLSchemaValidationError as error:
+    except Exception as error:  
+        # except xmlschema.XMLSchemaValidationError as error:
         return return_error(error)
    
 def xml_response(xml_str):