From 3c5798cfa2e72d8b289fbfb0e81e94748922ccba Mon Sep 17 00:00:00 2001 From: Adam Bem Date: Mon, 12 Jun 2023 10:53:22 +0200 Subject: [PATCH] Added XQuery Tool and refactored tools-service (#220) Co-authored-by: Adam Bem Reviewed-on: https://gitea.release11.com/R11/release11-tools/pulls/220 Reviewed-by: Mikolaj Widla --- Backend-libXML/main.py | 2 +- .../java/com/r11/tools/SparkApplication.java | 7 +- .../r11/tools/controller/XPathController.java | 118 ++++++------------ .../tools/controller/XQueryController.java | 87 +++++++++++++ .../r11/tools/controller/XsdController.java | 81 ++++++------ .../r11/tools/controller/XsltController.java | 117 ++++++----------- .../com/r11/tools/model/XMLRequestBody.java | 34 +++++ .../com/r11/tools/model/XMLResponseBody.java | 59 +++++++++ .../internal => model}/XPathQueryResult.java | 2 +- .../main/java/com/r11/tools/xml/Saxon.java | 27 +++- .../main/java/com/r11/tools/xml/Xalan.java | 8 +- .../java/com/r11/tools/xml/XmlEngine.java | 4 +- Frontend/assets/samples/sampleXQuery.xquery | 7 ++ Frontend/assets/scripts/frame.js | 1 + Frontend/assets/scripts/tools/scripts.js | 20 ++- Frontend/assets/scripts/tools/xquery.js | 13 ++ Frontend/index.html | 1 + Frontend/tools/xquery.html | 87 +++++++++++++ Samples/xquery/sampleXML.xml | 33 +++++ Samples/xquery/xquery.curl | 4 + Samples/xquery/xquery.json | 6 + 21 files changed, 509 insertions(+), 209 deletions(-) create mode 100644 Backend/tools-services/src/main/java/com/r11/tools/controller/XQueryController.java create mode 100644 Backend/tools-services/src/main/java/com/r11/tools/model/XMLRequestBody.java create mode 100644 Backend/tools-services/src/main/java/com/r11/tools/model/XMLResponseBody.java rename Backend/tools-services/src/main/java/com/r11/tools/{controller/internal => model}/XPathQueryResult.java (90%) create mode 100644 Frontend/assets/samples/sampleXQuery.xquery create mode 100644 Frontend/assets/scripts/tools/xquery.js create mode 100644 Frontend/tools/xquery.html create mode 100644 Samples/xquery/sampleXML.xml create mode 100644 Samples/xquery/xquery.curl create mode 100644 Samples/xquery/xquery.json diff --git a/Backend-libXML/main.py b/Backend-libXML/main.py index e4fefe5..9155395 100644 --- a/Backend-libXML/main.py +++ b/Backend-libXML/main.py @@ -54,7 +54,7 @@ def process_xml(request: request, type: str) -> str: code = 400 finally: exec_time = (time.time_ns() - start) / 10**6 - response_json['time'] = f"{exec_time:.03f}" + response_json['duration'] = f"{exec_time:.03f}" response_json['processor'] = "libxml2 over lxml" return json.dumps(response_json), code diff --git a/Backend/tools-services/src/main/java/com/r11/tools/SparkApplication.java b/Backend/tools-services/src/main/java/com/r11/tools/SparkApplication.java index 58149be..4908e9b 100644 --- a/Backend/tools-services/src/main/java/com/r11/tools/SparkApplication.java +++ b/Backend/tools-services/src/main/java/com/r11/tools/SparkApplication.java @@ -2,11 +2,7 @@ package com.r11.tools; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.r11.tools.controller.JsonController; -import com.r11.tools.controller.ProcessorInfoController; -import com.r11.tools.controller.XPathController; -import com.r11.tools.controller.XsdController; -import com.r11.tools.controller.XsltController; +import com.r11.tools.controller.*; import com.r11.tools.controller.internal.RestControllerRegistry; import com.r11.tools.xml.Saxon; import com.r11.tools.xml.Xalan; @@ -48,6 +44,7 @@ public class SparkApplication { registry.registerController(new XPathController(gson, logger, saxon, xalan)); registry.registerController(new XsltController(gson, logger, saxon, xalan)); registry.registerController(new JsonController(gson, jsongson, logger)); + registry.registerController(new XQueryController(gson, logger, saxon)); registry.register(); diff --git a/Backend/tools-services/src/main/java/com/r11/tools/controller/XPathController.java b/Backend/tools-services/src/main/java/com/r11/tools/controller/XPathController.java index a188566..dbf3840 100644 --- a/Backend/tools-services/src/main/java/com/r11/tools/controller/XPathController.java +++ b/Backend/tools-services/src/main/java/com/r11/tools/controller/XPathController.java @@ -1,8 +1,10 @@ package com.r11.tools.controller; import com.google.gson.Gson; -import com.google.gson.JsonObject; import com.r11.tools.controller.internal.*; +import com.r11.tools.model.XMLRequestBody; +import com.r11.tools.model.XMLResponseBody; +import com.r11.tools.model.XPathQueryResult; import com.r11.tools.xml.XmlEngine; import org.apache.logging.log4j.Logger; import spark.Request; @@ -24,109 +26,69 @@ public class XPathController implements RestController { this.xalan = xalan; } + private XMLResponseBody errorResponse(String message, String processor) { + return new XMLResponseBody(message, "ERR", processor, -1); + } + + private void nonValidEngineSelectedResponse(Response response) { + XMLResponseBody responseBody = + errorResponse("Valid engines are: saxon, xalan", "N/A"); + response.body(this.gson.toJson(responseBody)); + response.status(400); + } + @ScopedControllerManifest(method = HandlerType.POST, path = "/xpath") - public void transform(Request request, Response response) { - String body = request.body(); - - JsonObject requestJson; + public void acceptRequest(Request request, Response response) { + XMLRequestBody requestBody; try { - requestJson = this.gson.fromJson(body, JsonObject.class); + requestBody = this.gson.fromJson(request.body(), XMLRequestBody.class); } catch (Exception e) { - JsonObject responseJson = new JsonObject(); - responseJson.addProperty("result", e.getMessage()); - responseJson.addProperty("processor", "N/A"); - responseJson.addProperty("status", "ERR"); - responseJson.addProperty("time", "N/A"); - + XMLResponseBody responseBody = errorResponse(e.getMessage(), "N/A"); response.status(400); - response.body(this.gson.toJson(responseJson)); + response.body(this.gson.toJson(responseBody)); return; } - String data = requestJson.get("data").getAsString(); - String query = requestJson.get("process").getAsString(); - String processor = requestJson.get("processor").getAsString(); - String version = requestJson.get("version").getAsString(); - - if (processor == null) { - response.body("saxon, xalan"); + if (requestBody.getProcessor() == null) { + nonValidEngineSelectedResponse(response); return; } - JsonObject responseJson = new JsonObject(); - switch (processor) { + switch (requestBody.getProcessor()) { case "saxon": - processWithSaxon(response, data, query, version, responseJson); + process(response, requestBody, saxon); break; case "xalan": - processWithXalan(response, data, query, responseJson); + process(response, requestBody, xalan); break; default: - response.body("saxon, xalan"); + nonValidEngineSelectedResponse(response); } } - private void processWithXalan(Response response, String data, String query, JsonObject responseJson) { - long timeStart; - long duration; - response.header("processor", xalan.getVersion()); - timeStart = System.currentTimeMillis(); - + private void process(Response response, XMLRequestBody requestBody, XmlEngine engine) { + long timeStart = System.currentTimeMillis(); + XMLResponseBody responseBody = null; try { - XPathQueryResult xPathQueryResult = xalan.processXPath(data, query, ""); + XPathQueryResult xPathQueryResult = + engine.processXPath(requestBody.getData(), requestBody.getProcess(), requestBody.getVersion()); response.status(200); - - responseJson.addProperty("result", xPathQueryResult.getData().trim()); - responseJson.addProperty("status", "OK"); - responseJson.addProperty("type", xPathQueryResult.getType()); + long duration = System.currentTimeMillis() - timeStart; + responseBody = new XMLResponseBody(xPathQueryResult.getData().trim(), + "OK", engine.getVersion(),duration); + + responseBody.setType(xPathQueryResult.getType()); + this.logger.info("Request (XPath, " + engine.getVersion() + ") processed in " + duration + " ms."); } catch (Exception ex) { - this.logger.error("Error on processing XPath using Xalan. " + ex); - + responseBody = errorResponse(ex.getMessage(), engine.getVersion()); response.status(400); - responseJson.addProperty("result", ex.getMessage()); - responseJson.addProperty("status", "ERR"); + this.logger.error("Error on processing XPath using " + engine.getVersion() + ". " + ex); + } finally { + response.body(this.gson.toJson(responseBody)); } - duration = System.currentTimeMillis() - timeStart; - this.logger.info("Request (XPath, Xalan) processed in " + duration + " ms."); - - responseJson.addProperty("processor", xalan.getVersion()); - responseJson.addProperty("time", duration); - - response.body(this.gson.toJson(responseJson)); } - private void processWithSaxon(Response response, String data, String query, String version, JsonObject responseJson) { - long timeStart; - String tmp; - long duration; - response.header("processor", "Saxon " + saxon.getVersion() + " " + version + " over s9api"); - timeStart = System.currentTimeMillis(); - - try { - tmp = saxon.processXPath(data, query, version).getData().trim(); - - response.status(200); - - responseJson.addProperty("result", tmp); - responseJson.addProperty("status", "OK"); - } catch (Exception ex) { - this.logger.error("Error on processing XPath using Saxon. " + ex); - - response.status(400); - - responseJson.addProperty("result", ex.getMessage()); - responseJson.addProperty("status", "ERR"); - } - - duration = System.currentTimeMillis() - timeStart; - this.logger.info("Request (XPath, Saxon) processed in " + duration + " ms."); - - responseJson.addProperty("processor", "Saxon " + saxon.getVersion() + " " + version + " over s9api"); - responseJson.addProperty("time", duration); - - response.body(this.gson.toJson(responseJson)); - } } diff --git a/Backend/tools-services/src/main/java/com/r11/tools/controller/XQueryController.java b/Backend/tools-services/src/main/java/com/r11/tools/controller/XQueryController.java new file mode 100644 index 0000000..59bec6a --- /dev/null +++ b/Backend/tools-services/src/main/java/com/r11/tools/controller/XQueryController.java @@ -0,0 +1,87 @@ +package com.r11.tools.controller; + +import com.google.gson.Gson; +import com.r11.tools.controller.internal.*; +import com.r11.tools.model.XMLRequestBody; +import com.r11.tools.model.XMLResponseBody; +import com.r11.tools.xml.XmlEngine; +import org.apache.logging.log4j.Logger; +import spark.Request; +import spark.Response; + +/** + * Controller used to handle XQuery tool. Currently, it supports Saxon engine + * @author Adam Bem + */ +@GlobalControllerManifest +public class XQueryController implements RestController { + + private final Gson gson; + private final Logger logger; + private final XmlEngine saxon; + + public XQueryController(Gson gson, Logger logger, XmlEngine saxon) { + this.gson = gson; + this.logger = logger; + this.saxon = saxon; + } + + private XMLResponseBody prepareErrorResponse(String message, String processor) { + return new XMLResponseBody(message, "ERR", processor, -1); + } + + private void nonValidEngineSelectedResponse(Response response) { + XMLResponseBody responseBody = + prepareErrorResponse("Valid engines are: saxon", "N/A"); + response.body(this.gson.toJson(responseBody)); + response.status(400); + } + + @ScopedControllerManifest(method = HandlerType.POST, path = "/xquery") + public void acceptRequest(Request request, Response response) { + XMLRequestBody requestBody; + try { + requestBody = this.gson.fromJson(request.body(), XMLRequestBody.class); + } catch (Exception e) { + XMLResponseBody responseBody = prepareErrorResponse(e.getMessage(), "N/A"); + + response.status(400); + response.body(this.gson.toJson(responseBody)); + return; + } + if (requestBody.getProcessor() == null) { + nonValidEngineSelectedResponse(response); + return; + } + + if (requestBody.getProcessor().equalsIgnoreCase("saxon")) + process(response, requestBody, saxon); + else + nonValidEngineSelectedResponse(response); + } + + private void process(Response response, XMLRequestBody requestBody, XmlEngine engine) { + XMLResponseBody responseBody = null; + long timeStart = System.currentTimeMillis(); + try { + String result = engine.executeXQuery(requestBody.getData(), requestBody.getProcess(), requestBody.getVersion()); + + response.status(200); + + long duration = System.currentTimeMillis() - timeStart; + responseBody = new XMLResponseBody(result, "OK", engine.getVersion(), duration); + + this.logger.info("Request (XQuery, " + engine.getVersion() + ") processed in " + duration + " ms."); + } catch (Exception ex) { + response.status(400); + responseBody = prepareErrorResponse(ex.getMessage(), engine.getVersion()); + + this.logger.error("Error on processing XQuery using " + engine.getVersion() + ". " + ex); + } + finally { + response.body(this.gson.toJson(responseBody)); + } + + } + +} diff --git a/Backend/tools-services/src/main/java/com/r11/tools/controller/XsdController.java b/Backend/tools-services/src/main/java/com/r11/tools/controller/XsdController.java index 3a04ce6..294c6dc 100644 --- a/Backend/tools-services/src/main/java/com/r11/tools/controller/XsdController.java +++ b/Backend/tools-services/src/main/java/com/r11/tools/controller/XsdController.java @@ -1,12 +1,9 @@ package com.r11.tools.controller; import com.google.gson.Gson; -import com.google.gson.JsonObject; -import com.r11.tools.controller.internal.GlobalControllerManifest; -import com.r11.tools.controller.internal.HandlerType; -import com.r11.tools.controller.internal.RestController; -import com.r11.tools.controller.internal.ScopedControllerManifest; -import com.r11.tools.xml.Xalan; +import com.r11.tools.controller.internal.*; +import com.r11.tools.model.XMLRequestBody; +import com.r11.tools.model.XMLResponseBody; import com.r11.tools.xml.XmlEngine; import org.apache.logging.log4j.Logger; import spark.Request; @@ -26,57 +23,63 @@ public class XsdController implements RestController { this.xalan = xalan; } - @ScopedControllerManifest(method = HandlerType.POST, path = "/xsd") - public Response transform(Request request, Response response) { - String body = request.body(); + private XMLResponseBody prepareErrorResponse(String message, String processor) { + return new XMLResponseBody(message, "ERR", processor, -1); + } - JsonObject requestJson; + private void nonValidEngineSelectedResponse(Response response) { + XMLResponseBody responseBody = + prepareErrorResponse("Valid engines is: xalan", "N/A"); + response.body(this.gson.toJson(responseBody)); + response.status(400); + } + @ScopedControllerManifest(method = HandlerType.POST, path = "/xsd") + public void acceptRequest(Request request, Response response) { + XMLRequestBody requestBody; try { - requestJson = this.gson.fromJson(body, JsonObject.class); + requestBody = this.gson.fromJson(request.body(), XMLRequestBody.class); } catch (Exception e) { - JsonObject responseJson = new JsonObject(); - responseJson.addProperty("result", e.getMessage()); - responseJson.addProperty("processor", "N/A"); - responseJson.addProperty("status", "ERR"); - responseJson.addProperty("time", "N/A"); + XMLResponseBody responseBody = prepareErrorResponse(e.getMessage(), "N/A"); response.status(400); - response.body(this.gson.toJson(responseJson)); - return response; + response.body(this.gson.toJson(responseBody)); + return; } - String data = requestJson.get("data").getAsString(); - String xsd = requestJson.get("process").getAsString(); + if (requestBody.getProcessor() == null) { + nonValidEngineSelectedResponse(response); + return; + } + if (requestBody.getProcessor().equalsIgnoreCase("xalan")) + process(response, requestBody, xalan); + else + nonValidEngineSelectedResponse(response); - response.header("processor", xalan.getVersion()); + } - long timeStart = System.currentTimeMillis(); - String tmp; - - JsonObject responseJson = new JsonObject(); + private void process(Response response, XMLRequestBody requestBody, XmlEngine engine) { + XMLResponseBody responseBody = null; try { - tmp = xalan.validate(data, xsd).trim(); + long timeStart = System.currentTimeMillis(); + String result = engine.validate(requestBody.getData(), requestBody.getProcess()).trim(); response.status(200); - responseJson.addProperty("result", tmp); - responseJson.addProperty("status", "OK"); - } catch (Exception ex) { - this.logger.error("Error on validation against XSD using Xalan. " + ex); + long duration = System.currentTimeMillis() - timeStart; + responseBody = new XMLResponseBody(result, "OK", engine.getVersion(), duration); + this.logger.info("Request (XSD, " + engine.getVersion() + ") processed in " + duration + " ms."); + } catch (Exception ex) { + responseBody = prepareErrorResponse(ex.getMessage(), engine.getVersion()); response.status(400); - responseJson.addProperty("result", ex.getMessage()); - responseJson.addProperty("status", "ERR"); + this.logger.error("Error on validation against XSD using " + engine.getVersion() + ". " + ex); + } + finally { + response.body(this.gson.toJson(responseBody)); } - long duration = System.currentTimeMillis() - timeStart; - this.logger.info("Request (XSD, Xalan) processed in " + duration + " ms."); - responseJson.addProperty("processor", xalan.getVersion()); - responseJson.addProperty("time", duration); - - response.body(this.gson.toJson(responseJson)); - return response; } + } diff --git a/Backend/tools-services/src/main/java/com/r11/tools/controller/XsltController.java b/Backend/tools-services/src/main/java/com/r11/tools/controller/XsltController.java index 29e0fd6..a2b7e95 100644 --- a/Backend/tools-services/src/main/java/com/r11/tools/controller/XsltController.java +++ b/Backend/tools-services/src/main/java/com/r11/tools/controller/XsltController.java @@ -1,13 +1,9 @@ package com.r11.tools.controller; import com.google.gson.Gson; -import com.google.gson.JsonObject; -import com.r11.tools.controller.internal.GlobalControllerManifest; -import com.r11.tools.controller.internal.HandlerType; -import com.r11.tools.controller.internal.RestController; -import com.r11.tools.controller.internal.ScopedControllerManifest; -import com.r11.tools.xml.Saxon; -import com.r11.tools.xml.Xalan; +import com.r11.tools.controller.internal.*; +import com.r11.tools.model.XMLRequestBody; +import com.r11.tools.model.XMLResponseBody; import com.r11.tools.xml.XmlEngine; import org.apache.logging.log4j.Logger; import spark.Request; @@ -29,106 +25,69 @@ public class XsltController implements RestController { this.xalan = xalan; } - @ScopedControllerManifest(method = HandlerType.POST, path = "/xslt") - public void transform(Request request, Response response) { - String body = request.body(); + private XMLResponseBody prepareErrorResponse(String message, String processor) { + return new XMLResponseBody(message, "ERR", processor, -1); + } - JsonObject requestJson; + private void nonValidEngineSelectedResponse(Response response) { + XMLResponseBody responseBody = + prepareErrorResponse("Valid engines are: saxon, xalan", "N/A"); + response.body(this.gson.toJson(responseBody)); + response.status(400); + } + + @ScopedControllerManifest(method = HandlerType.POST, path = "/xslt") + public void acceptRequest(Request request, Response response) { + XMLRequestBody requestBody; try { - requestJson = this.gson.fromJson(body, JsonObject.class); + requestBody = this.gson.fromJson(request.body(), XMLRequestBody.class); } catch (Exception e) { - JsonObject responseJson = new JsonObject(); - responseJson.addProperty("result", e.getMessage()); - responseJson.addProperty("processor", "N/A"); - responseJson.addProperty("status", "ERR"); - responseJson.addProperty("time", "N/A"); + XMLResponseBody responseBody = prepareErrorResponse(e.getMessage(), "N/A"); response.status(400); - response.body(this.gson.toJson(responseJson)); + response.body(this.gson.toJson(responseBody)); return; } - String data = requestJson.get("data").getAsString(); - String query = requestJson.get("process").getAsString(); - String processor = requestJson.get("processor").getAsString(); - String version = requestJson.get("version").getAsString(); - - if (processor == null) { - response.body("saxon, xalan"); + if (requestBody.getProcessor() == null) { + nonValidEngineSelectedResponse(response); return; } - JsonObject responseJson = new JsonObject(); - switch (processor) { + + switch (requestBody.getProcessor()) { case "saxon": - processWithSaxon(response, data, query, version, responseJson); + process(response, requestBody, saxon); return; case "xalan": - processWithXalan(response, data, query, responseJson); + process(response, requestBody, xalan); return; default: - response.body("saxon, xalan"); + nonValidEngineSelectedResponse(response); } } - private void processWithXalan(Response response, String data, String query, JsonObject responseJson) { - long duration; - long timeStart; - String tmp; - timeStart = System.currentTimeMillis(); + private void process(Response response, XMLRequestBody requestBody, XmlEngine engine) { + XMLResponseBody responseBody = null; + long timeStart = System.currentTimeMillis(); try { - tmp = xalan.processXSLT(data, query); - + String result = engine.processXSLT(requestBody.getData(), requestBody.getProcess()); response.status(200); - responseJson.addProperty("result", tmp); - responseJson.addProperty("status", "OK"); + long duration = System.currentTimeMillis() - timeStart; + responseBody = new XMLResponseBody(result, "OK", engine.getVersion(), duration); + + this.logger.info("Request (XSLT, " + engine.getVersion() + ") processed in " + duration + " ms."); } catch (Exception ex) { - this.logger.error("Error on processing XSLT using Xalan. " + ex); - + responseBody = prepareErrorResponse(ex.getMessage(), engine.getVersion()); response.status(400); + this.logger.error("Error on processing XSLT using " + engine.getVersion() + ". " + ex); - responseJson.addProperty("result", ex.getMessage()); - responseJson.addProperty("status", "ERR"); + } finally { + response.body(this.gson.toJson(responseBody)); } - duration = System.currentTimeMillis() - timeStart; - this.logger.info("Request (XSLT, Xalan) processed in " + duration + " ms."); - - responseJson.addProperty("processor", xalan.getVersion()); - responseJson.addProperty("time", duration); - - response.body(this.gson.toJson(responseJson)); } - private void processWithSaxon(Response response, String data, String query, String version, JsonObject responseJson) { - long duration; - String tmp; - long timeStart; - timeStart = System.currentTimeMillis(); - try { - tmp = saxon.processXSLT(data, query); - - response.status(200); - - responseJson.addProperty("result", tmp); - responseJson.addProperty("status", "OK"); - } catch (Exception ex) { - this.logger.error("Error on processing XSLT using Saxon. " + ex); - - response.status(400); - - responseJson.addProperty("result", ex.getMessage()); - responseJson.addProperty("status", "ERR"); - } - - duration = System.currentTimeMillis() - timeStart; - this.logger.info("Request (XSLT, Saxon) processed in " + duration + " ms."); - - responseJson.addProperty("processor", "Saxon " + saxon.getVersion() + " " + version); - responseJson.addProperty("time", duration); - - response.body(this.gson.toJson(responseJson)); - } } diff --git a/Backend/tools-services/src/main/java/com/r11/tools/model/XMLRequestBody.java b/Backend/tools-services/src/main/java/com/r11/tools/model/XMLRequestBody.java new file mode 100644 index 0000000..52e89eb --- /dev/null +++ b/Backend/tools-services/src/main/java/com/r11/tools/model/XMLRequestBody.java @@ -0,0 +1,34 @@ +package com.r11.tools.model; + +import com.google.gson.annotations.SerializedName; + +/** + * POJO class used to contain body of XML related requests + * @author Adam + */ +public class XMLRequestBody { + @SerializedName("data") + private String data; + @SerializedName("process") + private String process; + @SerializedName("processor") + private String processor; + @SerializedName("version") + private String version; + + public String getData() { + return data; + } + + public String getProcess() { + return process; + } + + public String getProcessor() { + return processor; + } + + public String getVersion() { + return version; + } +} diff --git a/Backend/tools-services/src/main/java/com/r11/tools/model/XMLResponseBody.java b/Backend/tools-services/src/main/java/com/r11/tools/model/XMLResponseBody.java new file mode 100644 index 0000000..42e52c1 --- /dev/null +++ b/Backend/tools-services/src/main/java/com/r11/tools/model/XMLResponseBody.java @@ -0,0 +1,59 @@ +package com.r11.tools.model; + +public class XMLResponseBody { + + private String result; + private String status; + private String processor; + private long duration; + + // Optional + private String type; + + public XMLResponseBody(String result, String status, String processor, long duration) { + this.result = result; + this.status = status; + this.processor = processor; + this.duration = duration; + } + + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getProcessor() { + return processor; + } + + public void setProcessor(String processor) { + this.processor = processor; + } + + public long getDuration() { + return duration; + } + + public void setDuration(long duration) { + this.duration = duration; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } +} diff --git a/Backend/tools-services/src/main/java/com/r11/tools/controller/internal/XPathQueryResult.java b/Backend/tools-services/src/main/java/com/r11/tools/model/XPathQueryResult.java similarity index 90% rename from Backend/tools-services/src/main/java/com/r11/tools/controller/internal/XPathQueryResult.java rename to Backend/tools-services/src/main/java/com/r11/tools/model/XPathQueryResult.java index 8bb8a00..601c8c9 100644 --- a/Backend/tools-services/src/main/java/com/r11/tools/controller/internal/XPathQueryResult.java +++ b/Backend/tools-services/src/main/java/com/r11/tools/model/XPathQueryResult.java @@ -1,4 +1,4 @@ -package com.r11.tools.controller.internal; +package com.r11.tools.model; /** * Class used to store data received from parser and type of that data (node, string, etc.) diff --git a/Backend/tools-services/src/main/java/com/r11/tools/xml/Saxon.java b/Backend/tools-services/src/main/java/com/r11/tools/xml/Saxon.java index f9f330b..897da0b 100644 --- a/Backend/tools-services/src/main/java/com/r11/tools/xml/Saxon.java +++ b/Backend/tools-services/src/main/java/com/r11/tools/xml/Saxon.java @@ -1,6 +1,6 @@ package com.r11.tools.xml; -import com.r11.tools.controller.internal.XPathQueryResult; +import com.r11.tools.model.XPathQueryResult; import net.sf.saxon.s9api.*; import javax.xml.transform.stream.StreamSource; @@ -39,6 +39,29 @@ public class Saxon implements XmlEngine{ throw new UnsupportedOperationException(); } + /** + * This method evaluates XQuery exporession on given xml + * @param data xml + * @param xquery expression + * @return + * @throws Exception + */ + @Override + public String executeXQuery(String data, String xquery, String version) throws Exception { + Processor processor = new Processor(false); + + XQueryCompiler compiler = processor.newXQueryCompiler(); + compiler.setLanguageVersion(version); + + XQueryExecutable executable = compiler.compile(xquery); + + XQueryEvaluator evaluator = executable.load(); + evaluator.setSource(new StreamSource(new StringReader(data))); + + XdmValue result = evaluator.evaluate(); + return result.toString(); + } + /** * Process xpath and return either node or wrapped atomic value * @param data xml to be querried @@ -76,6 +99,6 @@ public class Saxon implements XmlEngine{ * @return version of the processor */ public String getVersion() { - return new Processor(false).getSaxonProductVersion(); + return "Saxon " + new Processor(false).getSaxonProductVersion(); } } diff --git a/Backend/tools-services/src/main/java/com/r11/tools/xml/Xalan.java b/Backend/tools-services/src/main/java/com/r11/tools/xml/Xalan.java index 51ad04f..befbe23 100644 --- a/Backend/tools-services/src/main/java/com/r11/tools/xml/Xalan.java +++ b/Backend/tools-services/src/main/java/com/r11/tools/xml/Xalan.java @@ -1,8 +1,7 @@ package com.r11.tools.xml; -import com.r11.tools.controller.internal.XPathQueryResult; +import com.r11.tools.model.XPathQueryResult; import org.apache.xpath.XPathAPI; -import org.apache.xpath.objects.XObject; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.traversal.NodeIterator; @@ -133,4 +132,9 @@ public class Xalan implements XmlEngine{ validator.validate(dataSource); return "XML file is valid"; } + + @Override + public String executeXQuery(String data, String xquery, String version) throws Exception { + throw new UnsupportedOperationException("Xalan doesn't support XQuery evaluation"); + } } diff --git a/Backend/tools-services/src/main/java/com/r11/tools/xml/XmlEngine.java b/Backend/tools-services/src/main/java/com/r11/tools/xml/XmlEngine.java index 5742073..132c9d4 100644 --- a/Backend/tools-services/src/main/java/com/r11/tools/xml/XmlEngine.java +++ b/Backend/tools-services/src/main/java/com/r11/tools/xml/XmlEngine.java @@ -1,12 +1,14 @@ package com.r11.tools.xml; -import com.r11.tools.controller.internal.XPathQueryResult; +import com.r11.tools.model.XPathQueryResult; public interface XmlEngine { XPathQueryResult processXPath(String data, String query, String version) throws Exception; String processXSLT(String data, String transform) throws Exception; String validate(String data, String xsd) throws Exception; + String executeXQuery(String data, String xquery, String version) throws Exception; + public String getVersion(); } diff --git a/Frontend/assets/samples/sampleXQuery.xquery b/Frontend/assets/samples/sampleXQuery.xquery new file mode 100644 index 0000000..0a124d5 --- /dev/null +++ b/Frontend/assets/samples/sampleXQuery.xquery @@ -0,0 +1,7 @@ +declare namespace p="http://www.release11.com/person"; +declare namespace b="http://www.release11.com/book"; +declare namespace l="http://www.release11.com/library"; + + +for $x in //p:person +return string($x/p:name) \ No newline at end of file diff --git a/Frontend/assets/scripts/frame.js b/Frontend/assets/scripts/frame.js index 5b89901..75781ec 100644 --- a/Frontend/assets/scripts/frame.js +++ b/Frontend/assets/scripts/frame.js @@ -25,6 +25,7 @@ function init() { tools.set("xpath", "tools/xpath.html"); tools.set("xsd", "tools/xsd.html"); tools.set("xslt", "tools/xslt.html"); + tools.set("xquery", "tools/xquery.html"); tools.set("xmlform", "tools/xmlFormatter.html"); tools.set("jsonform", "tools/jsonFormatter.html"); tools.set("mock", "tools/mock.html"); diff --git a/Frontend/assets/scripts/tools/scripts.js b/Frontend/assets/scripts/tools/scripts.js index 729ee8e..5119d50 100644 --- a/Frontend/assets/scripts/tools/scripts.js +++ b/Frontend/assets/scripts/tools/scripts.js @@ -135,6 +135,24 @@ function fillDefaultXSLT() { } ) } +/** + * The `fillDefaultXQuery()` function fetches a default XQuery from the server and sets the value of the element with id "transformArea" to the fetched template. + * + * @function + * @name fillDefaultXQuery + * @kind function + * @returns {void} + */ +function fillDefaultXQuery() { + const serverAddress = window.location.protocol + "//" + window.location.hostname; + fetch(serverAddress + "/assets/samples/sampleXQuery.xquery") + .then( response => response.text() ) + .then( (XQueryTemplate) => { + document.getElementById('transformArea').innerText = XQueryTemplate; + highlightSyntax("transformArea"); + } ) +} + /** * It sets default content for the element an changes it's color to grey * @@ -300,7 +318,7 @@ function performRequest(endpoint, checkXML, checkTransform) { if (result.status == "OK") { - document.getElementById("procinfo").innerText += " (" + result.time + "ms)"; + document.getElementById("procinfo").innerText += " (" + result.duration + "ms)"; if (result.type) document.getElementById("procinfo").innerText += ". Returned: " + result.type; else diff --git a/Frontend/assets/scripts/tools/xquery.js b/Frontend/assets/scripts/tools/xquery.js new file mode 100644 index 0000000..e723a8c --- /dev/null +++ b/Frontend/assets/scripts/tools/xquery.js @@ -0,0 +1,13 @@ +/** + * This function is executed after the page is loaded. + * + * @function + * @name init + * @kind function + */ +function init() { + // Make sure that only plain text is pasted + configurePastingInElement("xmlArea"); + configurePastingInElement("transformArea"); + +} \ No newline at end of file diff --git a/Frontend/index.html b/Frontend/index.html index d8aeaa6..1e7b80a 100644 --- a/Frontend/index.html +++ b/Frontend/index.html @@ -36,6 +36,7 @@
  • XPath
  • XSLT
  • XSD
  • +
  • XQuery
  • XML Formatter
  • JSON Formatter
  • diff --git a/Frontend/tools/xquery.html b/Frontend/tools/xquery.html new file mode 100644 index 0000000..682f04b --- /dev/null +++ b/Frontend/tools/xquery.html @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + +
    +
    +
    +
    +

    Online XQuery Interpreter

    +
    +
    +
    + + + + +
    +
    + + + +
    +
    + + Supports XQuery up to 4.0
    +
    + + +
    +
    + +
    + +
    + +
    +
    +
    +
    + +
    + + +
    + +
    +
    +
    +

    What is XQuery?

    +

    XQuery (XML Query) is a query and functional programming language that queries and transforms collections of structured and unstructured data, usually in the form of XML, text and with vendor-specific extensions for other data formats (JSON, binary, etc.).

    +

    Source: Wikipedia

    +
    + + +
    + + + + + + + + \ No newline at end of file diff --git a/Samples/xquery/sampleXML.xml b/Samples/xquery/sampleXML.xml new file mode 100644 index 0000000..cd89168 --- /dev/null +++ b/Samples/xquery/sampleXML.xml @@ -0,0 +1,33 @@ + + + City library + 345123 + + + 7321 + Adam + Choke + + + 5123 + Lauren + Wong + + + + + 6422 + Harry Potter + 7542 + + + 1234 + Macbeth + 5123 + + + 9556 + Romeo and Juliet + + + \ No newline at end of file diff --git a/Samples/xquery/xquery.curl b/Samples/xquery/xquery.curl new file mode 100644 index 0000000..2e4c4fc --- /dev/null +++ b/Samples/xquery/xquery.curl @@ -0,0 +1,4 @@ +url = "localhost/java/xquery" +#url = "localhost/libxml/xslt" +data = "@xquery.json" +request = POST diff --git a/Samples/xquery/xquery.json b/Samples/xquery/xquery.json new file mode 100644 index 0000000..f4d96bb --- /dev/null +++ b/Samples/xquery/xquery.json @@ -0,0 +1,6 @@ +{ + "data": "John67Anna69", + "process": "for $x in //person return string($x/name)", + "processor": "saxon", + "version": "3.1" +}