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):