diff --git a/.gitignore b/.gitignore index ab3e096..4a86338 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ .vscode nbactions.xml target/ +__pycache__ +venv diff --git a/Backend-libXML/.gitignore b/Backend-libXML/.gitignore new file mode 100644 index 0000000..9ca9383 --- /dev/null +++ b/Backend-libXML/.gitignore @@ -0,0 +1,3 @@ +.idea +__pycache** +venv diff --git a/Backend-libXML/Dockerfile b/Backend-libXML/Dockerfile new file mode 100644 index 0000000..f3524b4 --- /dev/null +++ b/Backend-libXML/Dockerfile @@ -0,0 +1,8 @@ +FROM tiangolo/meinheld-gunicorn-flask:python3.9 + +COPY ./requirements.txt /app/requirements.txt + +RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt + +COPY ./main.py /app/ +COPY ./Parser.py /app/ \ No newline at end of file diff --git a/Backend-libXML/Parser.py b/Backend-libXML/Parser.py new file mode 100644 index 0000000..3b492b1 --- /dev/null +++ b/Backend-libXML/Parser.py @@ -0,0 +1,67 @@ +from lxml import etree + + +def xpath(source: str, xpath: str) -> str: + """ + Method used to get nodes from XML string using XPath + + :param source: XML string used for selection + :type source: str + :param xpath: XPath query used for selection + :type xpath: str + :return: Nodes selected using XPath + :rtype: str + """ + + + root = etree.XML(source) + nsmap = root.nsmap + + # LXML doesn't accept empty (None) namespace prefix, + # so it need to be deleted if exists + if None in nsmap: + nsmap.pop(None) + + result = root.xpath(xpath, namespaces=nsmap) + result_string = "" + for e in result: + result_string += etree.tostring(e, pretty_print=True).decode() + "\n" + return result_string + + + +def xsd(source: str, xsd: str) -> bool: + """ + Method used to validate XML string against XSD schema + :param source: XML string used for validation + :type source: str + :param xsd: XSD schema to validate XML against + :type xsd: str + :return: If the validation was successful or not + :rtype: bool + """ + xml_schema = etree.XMLSchema(etree.XML(xsd)) + + xml = etree.XML(source) + + return xml_schema.validate(xml) + + +def xslt(source: str, xslt: str) -> str: + """ + Method used to transformate XML string using XSLT + + :param source: XML string to transform + :type source: str + :param xslt: XSLT string used to transformate XML + :type xslt: str + :return: Result of transformation + :rtype: str + """ + xslt_transform = etree.XSLT(etree.XML(xslt)) + + xml = etree.XML(source) + + transformated = xslt_transform(xml) + print(transformated) + return str(transformated) \ No newline at end of file diff --git a/Backend-libXML/main.py b/Backend-libXML/main.py new file mode 100644 index 0000000..78fc6cf --- /dev/null +++ b/Backend-libXML/main.py @@ -0,0 +1,68 @@ +from flask import Flask +from flask import request +from lxml import etree +import json +import time +import Parser + + +app = Flask(__name__) + + +def process_xml(request: request, type: str) -> str: + """Function to process + + :param request: Received request + :type request: request + :param type: Type of needed processing: xsd, xslt or xpath + :type type: str + :raises ValueError: is raised when type is different than those provided above + :return: response JSON converted to string and response code + :rtype: str, int + """ + start = time.time_ns() + code = 200 + response_json = dict() + try: + request_data = json.loads(request.get_data(as_text=True)) + data = request_data['data'] + process = request_data['process'] + if (type == "xsd"): + response_json['result'] = Parser.xsd(data, process) + elif (type == "xslt"): + response_json['result'] = Parser.xslt(data, process) + elif (type == "xpath"): + response_json['result'] = Parser.xpath(data, process) + else: + raise ValueError("Valid operation types are: xsd, xslt, xpath") + + response_json['status'] = "OK" + except KeyError as e: + response_json['result'] = "Missing key: " + str(e) + response_json['status'] = "ERR" + code = 400 + except Exception as e: + response_json['result'] = str(e) + response_json['status'] = "ERR" + code = 400 + finally: + exec_time = (time.time_ns() - start) / 10**6 + response_json['time'] = f"{exec_time:.03f}" + response_json['processor'] = "libxml2 over lxml" + return json.dumps(response_json), code + + +@app.route("/xpathpost", methods=["POST"]) +def xpath(): + return process_xml(request, "xpath") + +@app.route("/xsdpost", methods=["POST"]) +def xsd(): + return process_xml(request, "xsd") + +@app.route("/xsltpost", methods=["POST"]) +def xslt(): + return process_xml(request, "xslt") + +if __name__ == "__main__": + app.run() \ No newline at end of file diff --git a/Backend-libXML/requirements.txt b/Backend-libXML/requirements.txt new file mode 100644 index 0000000..d176ffe --- /dev/null +++ b/Backend-libXML/requirements.txt @@ -0,0 +1,2 @@ +lxml +flask diff --git a/Backend-libXML/sample/xpath/data.json b/Backend-libXML/sample/xpath/data.json new file mode 100644 index 0000000..2de1632 --- /dev/null +++ b/Backend-libXML/sample/xpath/data.json @@ -0,0 +1,6 @@ +{ + "data": "Hamlet2001-05-041falseMacbeth2000-12-131falseHarry Potter and the Sorcerer's Stone2005-04-292trueThe Long Walk2018-07-014trueMisery2018-01-314trueThink and Grow Rich2004-09-106trueThe Law of Success1982-05-096falsePatriot Games1995-10-215falseThe Sum of All Fears1992-09-195falseThe Alchemist2017-02-203falseHamlet1994-06-011falseMeasure for Measure1990-03-231falseHamlet1989-05-051trueHamlet1999-05-301trueThe Law of Success2004-11-266trueRomeo and Juliet1997-02-081trueThe Alchemist2009-08-213true", + "process": "/books/book[name = 'The Law of Success']", + "processor": "saxon", + "version": "2.0" +} diff --git a/Backend-libXML/sample/xpath/dataNS.json b/Backend-libXML/sample/xpath/dataNS.json new file mode 100644 index 0000000..ec5eb94 --- /dev/null +++ b/Backend-libXML/sample/xpath/dataNS.json @@ -0,0 +1,6 @@ +{ + "data": "Hamlet2001-05-041falseMacbeth2000-12-131falseHarry Potter and the Sorcerer's Stone2005-04-292trueThe Long Walk2018-07-014trueMisery2018-01-314trueThink and Grow Rich2004-09-106trueThe Law of Success1982-05-096falsePatriot Games1995-10-215falseThe Sum of All Fears1992-09-195falseThe Alchemist2017-02-203falseHamlet1994-06-011falseMeasure for Measure1990-03-231falseHamlet1989-05-051trueHamlet1999-05-301trueThe Law of Success2004-11-266trueRomeo and Juliet1997-02-081trueThe Alchemist2009-08-213true", + "process": "/b:books/b:book[b:name = 'The Law of Success']", + "processor": "saxon", + "version": "2.0" +} diff --git a/Backend-libXML/sample/xpath/non-ns.curl b/Backend-libXML/sample/xpath/non-ns.curl new file mode 100644 index 0000000..7d4219f --- /dev/null +++ b/Backend-libXML/sample/xpath/non-ns.curl @@ -0,0 +1,4 @@ +#url = "localhost:8081/xpathpost" +url = "localhost:5000/xpath" +request = "POST" +data = "@data.json" diff --git a/Backend-libXML/sample/xpath/ns.curl b/Backend-libXML/sample/xpath/ns.curl new file mode 100644 index 0000000..f439c0e --- /dev/null +++ b/Backend-libXML/sample/xpath/ns.curl @@ -0,0 +1,4 @@ +#url = "localhost:8081/xpathpost" +url = "localhost:5000/xpath" +request = "POST" +data = "@dataNS.json" diff --git a/Backend-libXML/sample/xsd/xsd.curl b/Backend-libXML/sample/xsd/xsd.curl new file mode 100644 index 0000000..2481c02 --- /dev/null +++ b/Backend-libXML/sample/xsd/xsd.curl @@ -0,0 +1,4 @@ +#url = "http://localhost:8082/xsd" +url = "http://localhost:5000/xsd" +data = "@xsd.json" +request = POST diff --git a/Backend-libXML/sample/xsd/xsd.json b/Backend-libXML/sample/xsd/xsd.json new file mode 100644 index 0000000..91dd2f2 --- /dev/null +++ b/Backend-libXML/sample/xsd/xsd.json @@ -0,0 +1,6 @@ +{ + "data": "TestTest3", + "process": " ", + "processor": "saxon", + "version": "1.0" +} diff --git a/Backend-libXML/sample/xslt/xslt.curl b/Backend-libXML/sample/xslt/xslt.curl new file mode 100644 index 0000000..d50edd1 --- /dev/null +++ b/Backend-libXML/sample/xslt/xslt.curl @@ -0,0 +1,3 @@ +url = "http://localhost:5000/xslt" +data = "@xslt.json" +request = POST diff --git a/Backend-libXML/sample/xslt/xslt.json b/Backend-libXML/sample/xslt/xslt.json new file mode 100644 index 0000000..f833a40 --- /dev/null +++ b/Backend-libXML/sample/xslt/xslt.json @@ -0,0 +1,6 @@ +{ + "data": "Hamlet2001-05-041falseMacbeth2000-12-131falseHarry Potter and the Sorcerer's Stone2005-04-292trueThe Long Walk2018-07-014trueMisery2018-01-314trueThink and Grow Rich2004-09-106trueThe Law of Success1982-05-096falsePatriot Games1995-10-215falseThe Sum of All Fears1992-09-195falseThe Alchemist2017-02-203falseHamlet1994-06-011falseMeasure for Measure1990-03-231falseHamlet1989-05-051trueHamlet1999-05-301trueThe Law of Success2004-11-266trueRomeo and Juliet1997-02-081trueThe Alchemist2009-08-213true", + "process": "", + "processor": "saxon", + "version": "1.0" +} diff --git a/Backend/mocked-services/src/main/resources/static/html/mock.html b/Backend/mocked-services/src/main/resources/static/html/mock.html index 79f52b4..f597720 100644 --- a/Backend/mocked-services/src/main/resources/static/html/mock.html +++ b/Backend/mocked-services/src/main/resources/static/html/mock.html @@ -8,6 +8,7 @@ +
diff --git a/Backend/mocked-services/src/main/resources/static/js/dyn_host.js b/Backend/mocked-services/src/main/resources/static/js/dyn_host.js new file mode 100644 index 0000000..b13a6e1 --- /dev/null +++ b/Backend/mocked-services/src/main/resources/static/js/dyn_host.js @@ -0,0 +1,11 @@ +$(document).ready( function() { + console.log("Here") + let links = document.getElementsByTagName("link") + for (let i = 0; i < links.length; i++) { + let oldStr = links[i].href.split("/") + let endpoint = oldStr.slice(3).join("/") + links[i].href = window.location.protocol + "//" + window.location.hostname + ":8086/" + endpoint + } + +}); + diff --git a/Frontend/assets/scripts/tools/jquery-3.6.0.slim.min.js b/Frontend/assets/scripts/common/jquery-3.6.0.slim.min.js similarity index 100% rename from Frontend/assets/scripts/tools/jquery-3.6.0.slim.min.js rename to Frontend/assets/scripts/common/jquery-3.6.0.slim.min.js diff --git a/Frontend/assets/scripts/dyn_host.js b/Frontend/assets/scripts/dyn_host.js new file mode 100644 index 0000000..0a1110f --- /dev/null +++ b/Frontend/assets/scripts/dyn_host.js @@ -0,0 +1,8 @@ +$(document).ready( function() { + document.getElementsByName("iframe")[0].src = + window.location.protocol + "//" + window.location.hostname + ":8097"; + document.getElementById("rest-mock").href = + window.location.protocol + "//" + window.location.hostname + ":8097"; + console.log("DONE") +}); + \ No newline at end of file diff --git a/Frontend/assets/scripts/tools/scripts.js b/Frontend/assets/scripts/tools/scripts.js index f0ced97..23818b3 100644 --- a/Frontend/assets/scripts/tools/scripts.js +++ b/Frontend/assets/scripts/tools/scripts.js @@ -106,7 +106,7 @@ function performRequest(text, checkXML, checkTransform){ async function restRequest(text) { const escapeChar = "specialEscapeChar"; // const addr = "http://localhost:8081/" + text; - const addr = "http://tools.zipper.release11.com" + text; + const addr = window.location.protocol + "//" + window.location.hostname + ":8081/" + text; var xmlData = document.getElementById("xmlArea").value.trim(); var transformData = document.getElementById("transformArea").value.trim(); diff --git a/Frontend/index.html b/Frontend/index.html index 0bb9ddf..a5647f6 100644 --- a/Frontend/index.html +++ b/Frontend/index.html @@ -4,8 +4,12 @@ + + + - + + @@ -16,16 +20,20 @@
- +
+ + diff --git a/Frontend/tools/xpath.html b/Frontend/tools/xpath.html index 3d0a6b3..1d4a84d 100644 --- a/Frontend/tools/xpath.html +++ b/Frontend/tools/xpath.html @@ -24,7 +24,7 @@ - +
diff --git a/Frontend/tools/xslt.html b/Frontend/tools/xslt.html index cc77f34..f1656e9 100644 --- a/Frontend/tools/xslt.html +++ b/Frontend/tools/xslt.html @@ -19,6 +19,7 @@ procInfo

diff --git a/docker-compose.yml b/docker-compose.yml index 559be61..6524db5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -19,6 +19,13 @@ services: ports: - 8081:8081 + xmltools-libxml-backend: + build: ./Backend-libXML + container_name: xmltools-libxml-backend + image: xmltools-libxml-backend + ports: + - 8082:80 + xmltools-mocked-services: build: context: ./Backend/mocked-services diff --git a/readme.md b/readme.md index d5600b6..c1a3e1b 100644 --- a/readme.md +++ b/readme.md @@ -17,6 +17,11 @@ openapi.yml Rest API accepts xml documents, given querry and processor version to call requested xml engine to perform given operation and finally returns outcome in response body. +## Flask Python backend + +This is module providing support for processing XMLs using libxml library. It consumes same JSON as Java backend. + + ## Mocked services MockedServices is a tool that allows developer to create, in easy and simple way, http server mocked endpoints for integration tests