From d6895aa80f3a9786bce8092d2c1d6879ede6f397 Mon Sep 17 00:00:00 2001 From: Rolf Niepraschk <Rolf.Niepraschk@ptb.de> Date: Thu, 31 Oct 2019 08:16:08 +0100 Subject: [PATCH] better xsd version management; better error handling --- README.md | 2 +- config.json | 2 +- server.py | 21 +++++++----- templates/html/validation.html | 46 +++++++++++++++++--------- trans.py | 6 ++-- utils.py | 59 +++++++++++++++++++++------------- 6 files changed, 86 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index b962730..95e106b 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 d72f8bb..87be298 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 8199652..12d2606 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 121d6f7..113fe47 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 fafda45..74c9fd9 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 4f6e4cd..931c9dc 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): -- GitLab