finished_milestone (#279)

Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #279
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Co-committed-by: widlam <mikolaj.widla@gmail.com>
This commit is contained in:
2024-01-04 08:08:16 +01:00
committed by Mikolaj Widla
parent 971cc5f36a
commit f0dd41a86e
91 changed files with 2007 additions and 882 deletions

View File

@@ -29,13 +29,13 @@ def process_xml(request: request, type: str) -> str:
try:
request_data = json.loads(request.get_data(as_text=True))
data = request_data['data']
process = request_data['process']
processorData = request_data['processorData']
if (type == "xsd"):
response_json['result'] = Parser.xsd(data, process)
response_json['result'] = Parser.xsd(data, processorData)
elif (type == "xslt"):
response_json['result'] = Parser.xslt(data, process)
response_json['result'] = Parser.xslt(data, processorData)
elif (type == "xpath"):
response_json['result'], response_json['type'] = Parser.xpath(data, process)
response_json['result'], response_json['type'] = Parser.xpath(data, processorData)
elif (type == "prettify"):
response_json['result'] = Parser.formatXML(data, True)
elif (type == "minimize"):
@@ -45,7 +45,7 @@ def process_xml(request: request, type: str) -> str:
elif (type == "minimizeHtml"):
response_json['result'] = Parser.formatHTML(data, False)
elif (type == "convertHTML"):
response_json['result'] = Parser.convertHTML(data, process)
response_json['result'] = Parser.convertHTML(data, processorData)
else:
raise ValueError("Valid operation types are: xsd, xslt, xpath")

View File

@@ -11,6 +11,6 @@ spring.redis.host=redis
spring.redis.port=6379
#retention
retention.minutes-to-delete-message=120
retention.minutes-to-delete-message=1440
retention.minutes-to-delete-history-record=1440
retention.retention-cooldown=1440

View File

@@ -40,11 +40,10 @@ public class SparkApplication {
RestControllerRegistry registry = new RestControllerRegistry();
registry.registerController(new ProcessorInfoController(logger, saxon, xalan));
registry.registerController(new XsdController(gson, logger, xalan));
registry.registerController(new XPathController(gson, logger, saxon, xalan));
registry.registerController(new XsltController(gson, logger, saxon, xalan));
registry.registerController(new XmlController(gson, logger, saxon, xalan));
registry.registerController(new MultipleXMLController(gson,logger, saxon));
registry.registerController(new JsonController(gson, jsongson, logger));
registry.registerController(new XQueryController(gson, logger, saxon));
registry.register();

View File

@@ -36,7 +36,7 @@ public class JsonController implements RestController {
try {
Object requestJson = this.gson.fromJson(request.body(), Object.class);
responseJson.addProperty("data", this.prettyGson.toJson(requestJson));
responseJson.addProperty("result", this.prettyGson.toJson(requestJson));
responseJson.addProperty("time", System.currentTimeMillis() - startProcess);
@@ -46,7 +46,7 @@ public class JsonController implements RestController {
response.status(400);
responseJson.addProperty("data", cause == null ? e.getMessage() : cause.getMessage());
responseJson.addProperty("result", cause == null ? e.getMessage() : cause.getMessage());
responseJson.addProperty("time", System.currentTimeMillis() - startProcess);
@@ -65,17 +65,17 @@ public class JsonController implements RestController {
response.status(200);
responseJson.addProperty("data", this.gson.toJson(requestJson));
responseJson.addProperty("result", this.gson.toJson(requestJson));
responseJson.addProperty("time", System.currentTimeMillis() - startProcess);
response.body(this.gson.toJson(responseJson));
} catch (Exception e) {
this.logger.error("Error on minimizeing Json " + e);
this.logger.error("Error on minimizing Json " + e);
Throwable cause = e.getCause();
response.status(400);
responseJson.addProperty("data", cause == null ? e.getMessage() : cause.getMessage());
responseJson.addProperty("result", cause == null ? e.getMessage() : cause.getMessage());
responseJson.addProperty("time", System.currentTimeMillis() - startProcess);
response.body(this.prettyGson.toJson(responseJson));

View File

@@ -0,0 +1,96 @@
package com.r11.tools.controller;
import com.google.gson.Gson;
import com.r11.tools.controller.internal.*;
import com.r11.tools.model.XMLMultipleFilesBody;
import com.r11.tools.model.XMLResponseBody;
import com.r11.tools.xml.XmlEngine;
import org.apache.logging.log4j.Logger;
import spark.Request;
import spark.Response;
@GlobalControllerManifest
public class MultipleXMLController implements RestController {
private final Gson gson;
private final Logger logger;
private final XmlEngine engine;
public MultipleXMLController(Gson gson, Logger logger, XmlEngine engine) {
this.gson = gson;
this.logger = logger;
this.engine = engine;
}
@ScopedControllerManifest(method = HandlerType.POST, path = "/multiple/xslt")
public void acceptRequestXslt(Request request, Response response) {
acceptRequest(request, response, XmlJobType.XSLT);
}
private void acceptRequest(Request request, Response response, XmlJobType xmlJobType) {
XMLMultipleFilesBody requestBody;
try {
requestBody = this.gson.fromJson(request.body(), XMLMultipleFilesBody.class);
} catch (Exception e) {
requestErrorResponse(response, e);
return;
}
processRequest(new MultipleXmlJob(response, requestBody, engine, xmlJobType));
}
private void processRequest(MultipleXmlJob xmlJob) {
XMLResponseBody responseBody = null;
long timeStart = System.currentTimeMillis();
long duration;
try {
responseBody = processData(xmlJob);
duration = System.currentTimeMillis() - timeStart;
responseBody.setDuration(duration);
xmlJob.getResponse().status(200);
this.logger.info("Request (" + xmlJob.getXmlJobType() + ", " +
xmlJob.getEngine().getVersion() +
") processed in " + duration + " ms.");
} catch (Exception ex) {
responseBody = processingErrorResponse(ex, xmlJob);
} finally {
xmlJob.getResponse().body(this.gson.toJson(responseBody));
}
}
private XMLResponseBody processData(MultipleXmlJob xmlJob) throws Exception {
XmlEngine engine = xmlJob.getEngine();
XMLMultipleFilesBody requestBody = xmlJob.getRequestBody();
String result = engine.processXSLT(requestBody.getData(), requestBody.getProcessorData());
return new XMLResponseBody(result, "OK", requestBody.getVersion());
}
private XMLResponseBody processingErrorResponse(Exception ex, MultipleXmlJob xmlJob) {
XmlEngine engine = xmlJob.getEngine();
XmlJobType xmlJobType = xmlJob.getXmlJobType();
Response response = xmlJob.getResponse();
XMLResponseBody responseBody =
new XMLResponseBody(ex.getMessage(), "ERR", engine.getVersion(), -1);
response.status(400);
this.logger.error("Error on processing " + xmlJobType + " using " + engine.getVersion() + ". " + ex);
return responseBody;
}
private void requestErrorResponse(Response response, Exception ex) {
XMLResponseBody responseBody = new XMLResponseBody(ex.getMessage(), "ERR", "N/A", -1);
response.status(400);
response.body(this.gson.toJson(responseBody));
}
}

View File

@@ -1,94 +0,0 @@
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.model.XPathQueryResult;
import com.r11.tools.xml.XmlEngine;
import org.apache.logging.log4j.Logger;
import spark.Request;
import spark.Response;
@GlobalControllerManifest
public class XPathController implements RestController {
private final Gson gson;
private final Logger logger;
private final XmlEngine saxon;
private final XmlEngine xalan;
public XPathController(Gson gson, Logger logger, XmlEngine saxon, XmlEngine xalan) {
this.gson = gson;
this.logger = logger;
this.saxon = saxon;
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 acceptRequest(Request request, Response response) {
XMLRequestBody requestBody;
try {
requestBody = this.gson.fromJson(request.body(), XMLRequestBody.class);
} catch (Exception e) {
XMLResponseBody responseBody = errorResponse(e.getMessage(), "N/A");
response.status(400);
response.body(this.gson.toJson(responseBody));
return;
}
if (requestBody.getProcessor() == null) {
nonValidEngineSelectedResponse(response);
return;
}
switch (requestBody.getProcessor()) {
case "saxon":
process(response, requestBody, saxon);
break;
case "xalan":
process(response, requestBody, xalan);
break;
default:
nonValidEngineSelectedResponse(response);
}
}
private void process(Response response, XMLRequestBody requestBody, XmlEngine engine) {
long timeStart = System.currentTimeMillis();
XMLResponseBody responseBody = null;
try {
XPathQueryResult xPathQueryResult =
engine.processXPath(requestBody.getData(), requestBody.getProcess(), requestBody.getVersion());
response.status(200);
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) {
responseBody = errorResponse(ex.getMessage(), engine.getVersion());
response.status(400);
this.logger.error("Error on processing XPath using " + engine.getVersion() + ". " + ex);
} finally {
response.body(this.gson.toJson(responseBody));
}
}
}

View File

@@ -1,87 +0,0 @@
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));
}
}
}

View File

@@ -0,0 +1,173 @@
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.model.XPathQueryResult;
import com.r11.tools.xml.XmlEngine;
import org.apache.logging.log4j.Logger;
import spark.Request;
import spark.Response;
/**
* Controller used to handle XML tools: XPath, XSD validation, XQuery and XSLT
* @author Adam Bem
*/
@GlobalControllerManifest
public class XmlController implements RestController {
private final Gson gson;
private final Logger logger;
private final XmlEngine saxon;
private final XmlEngine xalan;
public XmlController(Gson gson, Logger logger, XmlEngine saxon, XmlEngine xalan) {
this.gson = gson;
this.logger = logger;
this.saxon = saxon;
this.xalan = xalan;
}
@ScopedControllerManifest(method = HandlerType.POST, path = "/xpath")
public void acceptRequestXPath(Request request, Response response) {
acceptRequest(request, response, XmlJobType.XPath);
}
@ScopedControllerManifest(method = HandlerType.POST, path = "/xquery")
public void acceptRequestXQuery(Request request, Response response) {
acceptRequest(request, response, XmlJobType.XQuery);
}
@ScopedControllerManifest(method = HandlerType.POST, path = "/xsd")
public void acceptRequestXsd(Request request, Response response) {
acceptRequest(request, response, XmlJobType.XSD);
}
@ScopedControllerManifest(method = HandlerType.POST, path = "/xslt")
public void acceptRequestXslt(Request request, Response response) {
acceptRequest(request, response, XmlJobType.XSLT);
}
private void acceptRequest(Request request, Response response, XmlJobType xmlJobType) {
XMLRequestBody requestBody;
try {
requestBody = this.gson.fromJson(request.body(), XMLRequestBody.class);
} catch (Exception e) {
requestErrorResponse(response, e);
return;
}
if (requestBody.getProcessor() == null) {
invalidEngineSelectedResponse(response);
return;
}
switch (requestBody.getProcessor().toLowerCase()) {
case "saxon":
processRequest(new XmlJob(response, requestBody, saxon, xmlJobType));
return;
case "xalan":
processRequest(new XmlJob(response, requestBody, xalan, xmlJobType));
return;
default:
invalidEngineSelectedResponse(response);
}
}
private void processRequest(XmlJob xmlJob) {
XMLResponseBody responseBody = null;
long timeStart = System.currentTimeMillis();
long duration;
try {
responseBody = processData(xmlJob);
duration = System.currentTimeMillis() - timeStart;
responseBody.setDuration(duration);
xmlJob.getResponse().status(200);
this.logger.info("Request (" + xmlJob.getXmlJobType() + ", " +
xmlJob.getEngine().getVersion() +
") processed in " + duration + " ms.");
} catch (Exception ex) {
responseBody = processingErrorResponse(ex, xmlJob);
} finally {
xmlJob.getResponse().body(this.gson.toJson(responseBody));
}
}
private XMLResponseBody processData(XmlJob xmlJob) throws Exception {
if (xmlJob.getXmlJobType() == XmlJobType.XPath)
return processXPath(xmlJob);
else
return processOther(xmlJob);
}
private XMLResponseBody processXPath(XmlJob xmlJob) throws Exception {
XmlEngine engine = xmlJob.getEngine();
XMLRequestBody requestBody = xmlJob.getRequestBody();
XPathQueryResult xPathQueryResult =
engine.processXPath(requestBody.getData(), requestBody.getProcessorData(), requestBody.getVersion());
return new XMLResponseBody(xPathQueryResult.getData().trim(),
"OK", engine.getVersion(), xPathQueryResult.getType());
}
private XMLResponseBody processOther(XmlJob xmlJob) throws Exception {
XmlEngine engine = xmlJob.getEngine();
XMLRequestBody requestBody = xmlJob.getRequestBody();
String result = null;
switch (xmlJob.getXmlJobType()) {
case XSLT:
result = engine.processXSLT(requestBody.getData(), requestBody.getProcessorData());
break;
case XSD:
result = engine.validate(requestBody.getData(), requestBody.getProcessorData()).trim();
break;
case XQuery:
result = engine.executeXQuery(requestBody.getData(),
requestBody.getProcessorData(),
requestBody.getVersion());
break;
}
return new XMLResponseBody(result, "OK", requestBody.getVersion());
}
private XMLResponseBody processingErrorResponse(Exception ex, XmlJob xmlJob) {
XmlEngine engine = xmlJob.getEngine();
XmlJobType xmlJobType = xmlJob.getXmlJobType();
Response response = xmlJob.getResponse();
XMLResponseBody responseBody =
new XMLResponseBody(ex.getMessage(), "ERR", engine.getVersion(), -1);
response.status(400);
this.logger.error("Error on processing " + xmlJobType + " using " + engine.getVersion() + ". " + ex);
return responseBody;
}
private void invalidEngineSelectedResponse(Response response) {
XMLResponseBody responseBody =
new XMLResponseBody("Valid engines are: saxon, xalan", "ERR", "N/A", -1);
response.body(this.gson.toJson(responseBody));
response.status(400);
}
private void requestErrorResponse(Response response, Exception ex) {
XMLResponseBody responseBody = new XMLResponseBody(ex.getMessage(), "ERR", "N/A", -1);
response.status(400);
response.body(this.gson.toJson(responseBody));
}
}

View File

@@ -1,85 +0,0 @@
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;
@GlobalControllerManifest
public class XsdController implements RestController {
private final Gson gson;
private final Logger logger;
private final XmlEngine xalan;
public XsdController(Gson gson, Logger logger, XmlEngine xalan) {
this.gson = gson;
this.logger = logger;
this.xalan = xalan;
}
private XMLResponseBody prepareErrorResponse(String message, String processor) {
return new XMLResponseBody(message, "ERR", processor, -1);
}
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 {
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("xalan"))
process(response, requestBody, xalan);
else
nonValidEngineSelectedResponse(response);
}
private void process(Response response, XMLRequestBody requestBody, XmlEngine engine) {
XMLResponseBody responseBody = null;
try {
long timeStart = System.currentTimeMillis();
String result = engine.validate(requestBody.getData(), requestBody.getProcess()).trim();
response.status(200);
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);
this.logger.error("Error on validation against XSD using " + engine.getVersion() + ". " + ex);
}
finally {
response.body(this.gson.toJson(responseBody));
}
}
}

View File

@@ -1,93 +0,0 @@
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;
@GlobalControllerManifest
public class XsltController implements RestController {
private final Gson gson;
private final Logger logger;
private final XmlEngine saxon;
private final XmlEngine xalan;
public XsltController(Gson gson, Logger logger, XmlEngine saxon, XmlEngine xalan) {
this.gson = gson;
this.logger = logger;
this.saxon = saxon;
this.xalan = xalan;
}
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, 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 {
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;
}
switch (requestBody.getProcessor()) {
case "saxon":
process(response, requestBody, saxon);
return;
case "xalan":
process(response, requestBody, xalan);
return;
default:
nonValidEngineSelectedResponse(response);
}
}
private void process(Response response, XMLRequestBody requestBody, XmlEngine engine) {
XMLResponseBody responseBody = null;
long timeStart = System.currentTimeMillis();
try {
String result = engine.processXSLT(requestBody.getData(), requestBody.getProcess());
response.status(200);
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) {
responseBody = prepareErrorResponse(ex.getMessage(), engine.getVersion());
response.status(400);
this.logger.error("Error on processing XSLT using " + engine.getVersion() + ". " + ex);
} finally {
response.body(this.gson.toJson(responseBody));
}
}
}

View File

@@ -0,0 +1,36 @@
package com.r11.tools.controller.internal;
import com.r11.tools.model.XMLMultipleFilesBody;
import com.r11.tools.xml.XmlEngine;
import spark.Response;
public class MultipleXmlJob {
private final Response response;
private final XMLMultipleFilesBody requestBody;
private final XmlEngine engine;
private final XmlJobType xmlJobType;
public MultipleXmlJob(Response response, XMLMultipleFilesBody requestBody, XmlEngine engine, XmlJobType xmlJobType) {
this.response = response;
this.requestBody = requestBody;
this.engine = engine;
this.xmlJobType = xmlJobType;
}
public Response getResponse() {
return response;
}
public XMLMultipleFilesBody getRequestBody() {
return requestBody;
}
public XmlEngine getEngine() {
return engine;
}
public XmlJobType getXmlJobType() {
return xmlJobType;
}
}

View File

@@ -0,0 +1,35 @@
package com.r11.tools.controller.internal;
import com.r11.tools.model.XMLRequestBody;
import com.r11.tools.xml.XmlEngine;
import spark.Response;
public class XmlJob {
private final Response response;
private final XMLRequestBody requestBody;
private final XmlEngine engine;
private final XmlJobType xmlJobType;
public XmlJob(Response response, XMLRequestBody requestBody, XmlEngine engine, XmlJobType xmlJobType) {
this.response = response;
this.requestBody = requestBody;
this.engine = engine;
this.xmlJobType = xmlJobType;
}
public Response getResponse() {
return response;
}
public XMLRequestBody getRequestBody() {
return requestBody;
}
public XmlEngine getEngine() {
return engine;
}
public XmlJobType getXmlJobType() {
return xmlJobType;
}
}

View File

@@ -0,0 +1,8 @@
package com.r11.tools.controller.internal;
public enum XmlJobType {
XPath("XPath"), XSD("XSD"), XQuery("XQuery"), XSLT("XSLT");
XmlJobType(String type) {
}
}

View File

@@ -0,0 +1,32 @@
package com.r11.tools.model;
import com.google.gson.annotations.SerializedName;
public class XMLMultipleFilesBody {
@SerializedName("data")
private XMLMultipleFilesData[] data;
@SerializedName("processorData")
private String processorData;
@SerializedName("processor")
private String processor;
@SerializedName("version")
private String version;
public String getProcessorData() {
return processorData;
}
public String getProcessor() {
return processor;
}
public String getVersion() {
return version;
}
public XMLMultipleFilesData[] getData() {
return data;
}
}

View File

@@ -0,0 +1,18 @@
package com.r11.tools.model;
import com.google.gson.annotations.SerializedName;
public class XMLMultipleFilesData {
@SerializedName("fileName")
private String filename;
@SerializedName("fileData")
private String data;
public String getFilename() {
return filename;
}
public String getData() {
return data;
}
}

View File

@@ -4,13 +4,13 @@ import com.google.gson.annotations.SerializedName;
/**
* POJO class used to contain body of XML related requests
* @author Adam
* @author Adam Bem
*/
public class XMLRequestBody {
@SerializedName("data")
private String data;
@SerializedName("process")
private String process;
@SerializedName("processorData")
private String processorData;
@SerializedName("processor")
private String processor;
@SerializedName("version")
@@ -20,8 +20,8 @@ public class XMLRequestBody {
return data;
}
public String getProcess() {
return process;
public String getProcessorData() {
return processorData;
}
public String getProcessor() {

View File

@@ -10,6 +10,11 @@ public class XMLResponseBody {
// Optional
private String type;
public XMLResponseBody(String result, String status, String processor) {
this.result = result;
this.status = status;
this.processor = processor;
}
public XMLResponseBody(String result, String status, String processor, long duration) {
this.result = result;
this.status = status;
@@ -17,6 +22,13 @@ public class XMLResponseBody {
this.duration = duration;
}
public XMLResponseBody(String result, String status, String processor, String type) {
this.result = result;
this.status = status;
this.processor = processor;
this.type = type;
}
public String getResult() {
return result;
}

View File

@@ -1,11 +1,16 @@
package com.r11.tools.xml;
import com.r11.tools.model.XMLMultipleFilesData;
import com.r11.tools.model.XPathQueryResult;
import net.sf.saxon.s9api.*;
import javax.xml.transform.stream.StreamSource;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Comparator;
import java.util.UUID;
/**
* Handler for Saxon engine
@@ -13,6 +18,64 @@ import java.io.StringWriter;
*/
public class Saxon implements XmlEngine{
/**
* Transforms many XML documents via XSLT.
* @param data XML Files to be transformed.
* @param transform XSLT
* @return transformed xml
* @throws SaxonApiException thrown on stylesheet or transformation error
* @throws IOException thrown when file does not exist, or cannot be read.
*/
public String processXSLT(XMLMultipleFilesData[] data, String transform) throws SaxonApiException, IOException{
Processor processor = new Processor(false);
XsltCompiler compiler = processor.newXsltCompiler();
String filesPath = "/tmp/"+UUID.randomUUID()+"/";
try{
createXMLFilesFromData(data, filesPath);
Path transformPath = createXSLTFileAndReturnPath(transform,filesPath);
XsltExecutable stylesheet = compiler.compile( new StreamSource( transformPath.toFile() ));
StringWriter sw = new StringWriter();
Serializer out = processor.newSerializer(sw);
out.setOutputProperty(Serializer.Property.METHOD, "xml");
out.setOutputProperty(Serializer.Property.INDENT, "yes");
Xslt30Transformer transformer = stylesheet.load30();
transformer.transform( new StreamSource( new File(filesPath+data[0].getFilename()) ) , out );
return sw.toString();
} finally {
deleteTemporaryFiles(filesPath);
}
}
private void createXMLFilesFromData( XMLMultipleFilesData[] data , String filesPath ) throws IOException {
Files.createDirectories(Paths.get(filesPath));
for (XMLMultipleFilesData fileData : data) {
Path filePath = Files.createFile( Paths.get(filesPath + fileData.getFilename() ) );
try (FileWriter writer = new FileWriter(filePath.toFile())) {
writer.write(fileData.getData());
}
}
}
private Path createXSLTFileAndReturnPath( String xsltTransform, String filesPath ) throws IOException {
Path transformPath = Files.createFile( Paths.get(filesPath + "transform.xsl") );
FileWriter writer = new FileWriter(transformPath.toFile());
writer.write(xsltTransform);
writer.close();
return transformPath;
}
private void deleteTemporaryFiles(String filesPath) throws IOException {
Files
.walk( Paths.get(filesPath) )
.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.forEach(File::delete);
}
/**
* Transforms string containing xml document via xslt
* @param data xml to be transformed
@@ -40,7 +103,7 @@ public class Saxon implements XmlEngine{
}
/**
* This method evaluates XQuery exporession on given xml
* This method evaluates XQuery expression on given xml
* @param data xml
* @param xquery expression
* @return
@@ -64,8 +127,8 @@ public class Saxon implements XmlEngine{
/**
* Process xpath and return either node or wrapped atomic value
* @param data xml to be querried
* @param query xpath queryy
* @param data xml to be processed
* @param query xpath query
* @param version processor version
* @return string xml representation of the node
* @throws Exception thrown on node building errors or invalid xpath

View File

@@ -1,5 +1,6 @@
package com.r11.tools.xml;
import com.r11.tools.model.XMLMultipleFilesData;
import com.r11.tools.model.XPathQueryResult;
import org.apache.xpath.XPathAPI;
import org.w3c.dom.Document;
@@ -17,7 +18,10 @@ import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.*;
import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.StringWriter;
/**
* Handler for Xalan engine
@@ -57,6 +61,11 @@ public class Xalan implements XmlEngine{
return nodeType == Node.CDATA_SECTION_NODE || nodeType == Node.TEXT_NODE;
}
@Override
public String processXSLT(XMLMultipleFilesData[] data, String transform) throws Exception {
throw new UnsupportedOperationException("Xalan does not support multiple files XSLT processing");
}
/**
* Process xpath and return either node or wrapped atomic value
* @param data xml

View File

@@ -1,8 +1,11 @@
package com.r11.tools.xml;
import com.r11.tools.model.XMLMultipleFilesData;
import com.r11.tools.model.XPathQueryResult;
public interface XmlEngine {
String processXSLT(XMLMultipleFilesData[] data, String transform) throws Exception;
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;

View File

@@ -1,4 +1,4 @@
FROM node:latest as build-stage
FROM node:20.9.0-bullseye-slim as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
@@ -7,7 +7,7 @@ RUN npm run build
FROM nginx:stable-alpine as production-stage
FROM nginx:stable-alpine3.17-slim as production-stage
RUN mkdir /app
RUN apk add --no-cache tzdata
@@ -20,7 +20,7 @@ EXPOSE 80
EXPOSE 443
FROM node:latest as dev
FROM node:20.9.0-bullseye-slim as dev
WORKDIR /app
COPY package*.json ./
RUN npm install

View File

@@ -13,6 +13,7 @@
"@codemirror/lang-xml": "^6.0.2",
"@codemirror/theme-one-dark": "^6.1.2",
"codemirror": "^6.0.1",
"thememirror": "^2.0.1",
"vue": "^3.3.4",
"vue-codemirror": "^6.1.1",
"vue-router": "^4.2.2"
@@ -3190,9 +3191,9 @@
}
},
"node_modules/normalize-package-data/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"bin": {
"semver": "bin/semver"
@@ -3326,9 +3327,9 @@
}
},
"node_modules/npm-run-all/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true,
"bin": {
"semver": "bin/semver"
@@ -3616,9 +3617,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.24",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
"integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==",
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"funding": [
{
"type": "opencollective",
@@ -4305,6 +4306,16 @@
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
"dev": true
},
"node_modules/thememirror": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/thememirror/-/thememirror-2.0.1.tgz",
"integrity": "sha512-d5i6FVvWWPkwrm4cHLI3t9AT1OrkAt7Ig8dtdYSofgF7C/eiyNuq6zQzSTusWTde3jpW9WLvA9J/fzNKMUsd0w==",
"peerDependencies": {
"@codemirror/language": "^6.0.0",
"@codemirror/state": "^6.0.0",
"@codemirror/view": "^6.0.0"
}
},
"node_modules/thenify": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
@@ -6994,9 +7005,9 @@
},
"dependencies": {
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true
}
}
@@ -7097,9 +7108,9 @@
"dev": true
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"dev": true
},
"shebang-command": {
@@ -7302,9 +7313,9 @@
"dev": true
},
"postcss": {
"version": "8.4.24",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
"integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==",
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"requires": {
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
@@ -7756,6 +7767,12 @@
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
"dev": true
},
"thememirror": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/thememirror/-/thememirror-2.0.1.tgz",
"integrity": "sha512-d5i6FVvWWPkwrm4cHLI3t9AT1OrkAt7Ig8dtdYSofgF7C/eiyNuq6zQzSTusWTde3jpW9WLvA9J/fzNKMUsd0w==",
"requires": {}
},
"thenify": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",

View File

@@ -17,6 +17,7 @@
"@codemirror/lang-xml": "^6.0.2",
"@codemirror/theme-one-dark": "^6.1.2",
"codemirror": "^6.0.1",
"thememirror": "^2.0.1",
"vue": "^3.3.4",
"vue-codemirror": "^6.1.1",
"vue-router": "^4.2.2"

View File

@@ -1,14 +1,53 @@
<script setup lang="ts">
import { RouterView } from 'vue-router';
import SidebarComponent from '@components/sidebar/SidebarComponent.vue';
import {onMounted, provide, ref } from 'vue';
const theme = ref( getTheme() );
provide('theme', theme );
onMounted( ()=> {
if (localStorage.theme)
selectThemeFromLocalStorage();
else if (browserPrefersDarkMode()) {
setDarkTheme();
}
})
function setDarkTheme() {
document.documentElement.classList.add('dark');
theme.value = "dark";
localStorage.setItem("theme", "dark");
}
function selectThemeFromLocalStorage() {
if (localStorage.theme == "dark")
document.documentElement.classList.add('dark');
else
document.documentElement.classList.remove('dark');
theme.value = localStorage.theme;
}
function browserPrefersDarkMode(){
return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
}
function setTheme(newTheme : string){
theme.value = newTheme;
}
function getTheme(){
return localStorage.theme;
}
</script>
<template>
<div id="layout" class="flex h-screen bg-gradient-to-r from-white to-sky-200 dark:from-slate-800 dark:to-indigo-950">
<SidebarComponent />
<div class="relative p-4 w-full m-4 bg-blue-50 dark:bg-gray-700 rounded-2xl overflow-hidden shadow-lg">
<div id="layout" class="font-sans flex h-screen bg-gradient-to-br from-sky-200 to-indigo-200 dark:from-sky-950 dark:to-indigo-950">
<SidebarComponent @theme:changed="setTheme" />
<div class="relative p-4 w-full m-4 ml-0 bg-blue-50 dark:bg-gray-700 rounded-2xl overflow-hidden shadow-lg">
<RouterView></RouterView>
</div>
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -2,11 +2,11 @@
"universalInfo":
[
{
"category":"What is XPath",
"category":"What is XPath?",
"description":"XPath is a query language used for selecting nodes from XML and processing them. It may perform operations on strings, numbers and boolean values."
},
{
"category":"What's new in XPath?"
"category":"What's new in XPath"
}
],
"VersionDiffs":

View File

@@ -6,7 +6,7 @@
"description":"XSLT (Extensible Stylesheet Language Transformations) is a language for converting and manipulating XML data into various formats. It uses rules defined in stylesheets to transform XML documents into HTML, XML, or other text-based outputs."
},
{
"category":"What's differences between XSLT versions"
"category":"Differences between XSLT versions"
}
],
"VersionDiffs":

View File

@@ -0,0 +1,88 @@
<script setup lang="ts">
import { onBeforeUpdate, inject } from 'vue'
import { Codemirror } from 'vue-codemirror'
import { oneDark } from '@codemirror/theme-one-dark'
import { espresso } from 'thememirror';
import {xml} from '@codemirror/lang-xml'
import {json} from '@codemirror/lang-json'
import {html} from '@codemirror/lang-html'
function isDarkModeSet(){
return localStorage.theme == "dark";
}
const theme : string = inject('theme')! ;
const props= defineProps({
code : {
type: String,
required: true
},
config: {
type: Object,
required: true
},
})
const emit = defineEmits(
[
'update:updatedCode'
]
)
function dataUpdated(newData:String){
emit('update:updatedCode',newData)
}
function selectTheme() {
if (isDarkModeSet()) {
return oneDark;
}
else {
return espresso;
}
}
let extensions = parseExtensions();
function parseExtensions(){
return [
selectTheme(),
parseLanguage(props.config.language),
]
}
function parseLanguage(name: String){
switch(name.toUpperCase()){
case "JSON": {
return json();
}
case "HTML": {
return html();
}
default: {
return xml();
}
}
}
onBeforeUpdate( () => { extensions = parseExtensions(); } )
</script>
<template>
<div class="editor w-full h-full rounded-2xl overflow-x-auto">
<codemirror
:key="theme"
style="height: 100%; width: 100%; padding:1rem ; border-radius: 1rem; font-size: large;"
:model-value="code"
@update:model-value="dataUpdated"
:extensions="extensions"
:disabled="config.disabled"
/>
</div>
</template>

View File

@@ -45,5 +45,5 @@ function setDefault() {
</script>
<template>
<button class="tool-button" @click="setDefault()">Default {{ stylizedName }}</button>
<button class="tool-button" @click="setDefault()">Example {{ stylizedName }}</button>
</template>

View File

@@ -0,0 +1,5 @@
export interface TabData {
id: number;
name: string;
data: string;
}

View File

@@ -0,0 +1,46 @@
<script setup lang="ts">
import lightThemeIcon from '@/assets/light_theme.svg';
import darkThemeIcon from '@/assets/dark_theme.svg';
const emit = defineEmits([
"theme",
]);
function toDarkMode(){
localStorage.theme = "dark";
document.documentElement.classList.add('dark');
emit('theme',"dark");
}
function toLightMode(){
localStorage.theme = "light";
document.documentElement.classList.remove('dark');
emit('theme',"light");
}
</script>
<template>
<div class="mb-4 flex flex-row gap-8">
<button id="header__moon" @click="toDarkMode()" title="Switch to dark mode" class="w-full h-10 focus:outline-none focus:shadow-outline text-gray-500">
<svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" viewBox="0 0 24 24">
<path fill="currentColor" d="M17.75,4.09L15.22,6.03L16.13,9.09L13.5,7.28L10.87,9.09L11.78,6.03L9.25,4.09L12.44,4L13.5,1L14.56,4L17.75,4.09M21.25,11L19.61,12.25L20.2,14.23L18.5,13.06L16.8,14.23L17.39,12.25L15.75,11L17.81,10.95L18.5,9L19.19,10.95L21.25,11M18.97,15.95C19.8,15.87 20.69,17.05 20.16,17.8C19.84,18.25 19.5,18.67 19.08,19.07C15.17,23 8.84,23 4.94,19.07C1.03,15.17 1.03,8.83 4.94,4.93C5.34,4.53 5.76,4.17 6.21,3.85C6.96,3.32 8.14,4.21 8.06,5.04C7.79,7.9 8.75,10.87 10.95,13.06C13.14,15.26 16.1,16.22 18.97,15.95M17.33,17.97C14.5,17.81 11.7,16.64 9.53,14.5C7.36,12.31 6.2,9.5 6.04,6.68C3.23,9.82 3.34,14.64 6.35,17.66C9.37,20.67 14.19,20.78 17.33,17.97Z" />
</svg>
</button>
<button id="header__indeterminate" @click="toLightMode()" title="Switch to light mode" class="w-full h-10 focus:outline-none focus:shadow-outline text-gray-500">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-sun" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<circle cx="12" cy="12" r="4"></circle>
<path d="M3 12h1m8 -9v1m8 8h1m-9 8v1m-6.4 -15.4l.7 .7m12.1 -.7l-.7 .7m0 11.4l.7 .7m-12.1 -.7l-.7 .7"></path>
</svg>
</button>
</div>
</template>

View File

@@ -0,0 +1,35 @@
<script setup lang="ts">
const props = defineProps(
{
operation: {type:String,required:true},
code: {type: String, required: true}
}
)
const emit = defineEmits([
'update:result'
])
function encode(){
switch(props.operation.toLowerCase()){
case "encode":{
emit('update:result', encodeURI(props.code) )
break;
}
case "decode":{
emit('update:result', decodeURI(props.code) )
break;
}
}
}
</script>
<template>
<button @click="encode()" class="tool-button">{{ props.operation }}</button>
</template>

View File

@@ -0,0 +1,39 @@
<script setup lang="ts">
const props = defineProps(
{
operationType: {type:String,required:true},
code: {type: String, required: true}
}
)
const emit = defineEmits([
'update:result',
'image:show'
])
function convert(){
console.log("works")
switch(props.operationType.toLowerCase()){
case "encode":{
emit('update:result', btoa(props.code) )
break;
}
case "decode":{
emit('update:result', atob(props.code) )
break;
}
case "show image":{
emit('image:show', props.code )
break;
}
}
}
</script>
<template>
<button @click="convert()" class="tool-button">{{ props.operationType }}</button>
</template>

View File

@@ -0,0 +1,114 @@
<script setup lang="ts">
import XMLButtonFormatterComponent from '@/components/formatter/XMLButtonFormatterComponent.vue';
import JsonButtonFormatterComponent from '@/components/formatter/JsonButtonFormatterComponent.vue';
import HtmlButtonFormatterComponent from '@/components/formatter/HtmlButtonFormatterComponent.vue';
import InsertTemplateComponent from '@components/common/InsertTemplateComponent.vue';
import CodeEditorComponent from '@/components/common/CodeEditorComponent.vue';
import { ref } from 'vue';
const data = ref('');
const inputFile = ref()
const errorOccurred = ref(false);
const successOccurred = ref(false);
const props = defineProps({
formatterLanguage: {
type: String,
required: true
}
})
function setTextFieldValue(newData: string) {
successOccurred.value = false;
errorOccurred.value = false;
data.value = newData;
}
function format(formatted: any) {
data.value = formatted.result;
}
function setErrorOccurred(occurred: boolean) {
errorOccurred.value = occurred;
successOccurred.value = !(occurred);
}
function setExample(data: string) {
inputFile.value.value = ''
setTextFieldValue(data)
}
function clear() {
data.value = '';
successOccurred.value = false;
errorOccurred.value = false;
inputFile.value.value = ''
}
function readFile(file : any) {
const reader = new FileReader()
reader.onloadend = () => {
var result = reader.result?.toString()
if (typeof result == "string")
setTextFieldValue(result);
}
reader.readAsText(file.target.files[0])
}
function highlightTextField() {
if (successOccurred.value)
return "text-field-success";
if (errorOccurred.value)
return "text-field-error";
return "";
}
</script>
<template>
<div id="layout" class="flex flex-col w-full h-full gap-4">
<div id="toolbar" class= "flex flex-col gap-4 items-center lg:flex-row place-content-between">
<span class="dark:text-slate-100"> {{ formatterLanguage }} Formatter</span>
<!-- XML Formatter Toolbar -->
<div v-if="formatterLanguage.toLowerCase() == 'xml'" class="flex flex-wrap gap-2 justify-center">
<div class="flex items-stretch w-64">
<input id="fileLoader" ref="inputFile" class="file-selector" type="file" accept=".xml,.xql,.xquery,.xslt,text/xml,text/plain" @change="readFile" />
</div>
<InsertTemplateComponent stylized-name="XML" @update:defaultData="(data: string) => setExample(data)"></InsertTemplateComponent>
<button class="tool-button" @click="clear()">Clear</button>
<XMLButtonFormatterComponent @update:error="setErrorOccurred" is-minimizer :xml="data" @update:result="format"></XMLButtonFormatterComponent>
<XMLButtonFormatterComponent @update:error="setErrorOccurred" :xml="data" @update:result="format"></XMLButtonFormatterComponent>
</div>
<!-- JSON Formatter Toolbar -->
<div v-if="formatterLanguage.toLowerCase() == 'json'" class="flex flex-wrap gap-2 justify-center">
<div class="flex items-stretch w-64">
<input id="fileLoader" ref="inputFile" class="file-selector" type="file" accept=".json,text/xml,text/plain,text/json,application/json" @change="readFile" />
</div>
<InsertTemplateComponent stylized-name="JSON" @update:defaultData="(data: string) => setExample(data)"></InsertTemplateComponent>
<button class="tool-button" @click="clear()">Clear</button>
<JsonButtonFormatterComponent isMinimizer :json="data" @update:result="format" @update:error="setErrorOccurred"></JsonButtonFormatterComponent>
<JsonButtonFormatterComponent :json="data" @update:result="format" @update:error="setErrorOccurred"></JsonButtonFormatterComponent>
</div>
<!-- HTML Formatter Toolbar -->
<div v-if="formatterLanguage.toLowerCase() == 'html'" class="flex flex-wrap gap-2 justify-center">
<div class="flex items-stretch w-64">
<input id="fileLoader" ref="inputFile" class="file-selector" type="file" accept=".xml,.html,.htm,text/xml,text/plain,text/html" @change="readFile" />
</div>
<InsertTemplateComponent stylized-name="HTML" @update:defaultData="setExample"></InsertTemplateComponent>
<button class="tool-button" @click="clear()">Clear</button>
<HtmlButtonFormatterComponent @update:result="format" @update:error="setErrorOccurred" :code="data" format-type="Minimize" />
<HtmlButtonFormatterComponent @update:result="format" @update:error="setErrorOccurred" :code="data" format-type="Prettify" />
<HtmlButtonFormatterComponent @update:result="format" @update:error="setErrorOccurred" :code="data" format-type="HTML -> XML" />
</div>
</div>
<CodeEditorComponent :class="highlightTextField()" @update:updated-code="setTextFieldValue" :code="data" :config="{disabled:false,language:formatterLanguage.toLowerCase()}" />
</div>
</template>

View File

@@ -1,13 +1,28 @@
<script setup lang="ts">
const props = defineProps(
{
formatType: {type:String,required:true},
code: {type:String,required:true},
formatType: {
type:String,
required:true
},
code: {
type:String,
required:true
},
isError: {
type:Boolean,
required:false
},
}
)
const emit = defineEmits([
'update:result',
'update:error'
])
function chooseType(formatType: String){
if (formatType == "XML Converter"){
if (formatType == "HTML -> XML"){
return "convert";
}
return formatType.toLowerCase();
@@ -24,7 +39,7 @@ function getTypeInfo(){
function createBody(){
return JSON.stringify({
"data": props.code,
"process": getTypeInfo(),
"processorData": getTypeInfo(),
"processor": "libxml",
"version": "1.0"
});
@@ -32,19 +47,16 @@ function createBody(){
const fetchLink = document.location.protocol + "//" + document.location.hostname + "/libxml/html/" + chooseType(props.formatType);
const emit = defineEmits([
'update:result'
])
function processResponse(formattedCode : any){
var result = formattedCode.result;
return result
}
function process(){
fetch(fetchLink, {body:createBody(), method: "POST"})
.then( response => response.json() )
.then( formattedCode => emit('update:result', processResponse(formattedCode) ) )
.then( formattedCode => processResponse(formattedCode) )
}
function processResponse(formattedCode : any){
emit('update:result', formattedCode )
emit("update:error", formattedCode.status == "ERR")
}
</script>

View File

@@ -5,12 +5,12 @@ const props = defineProps({
isMinimizer: {type: Boolean}
})
const emit = defineEmits(["update:result"])
const emit = defineEmits(["update:result", "update:error"])
function process() {
var request:Request = prepareRequest();
fetchRequest(request).then((data) => {
sendProcessedData(data);
sendProcessedData(data);
})
}
@@ -36,9 +36,11 @@ function prepareRequestBody():string {
async function fetchRequest(request: Request):Promise<JSON> {
var responseBody = await fetch(request)
.then(response => response.json())
.then(response => {
emit('update:error', response.status != 200)
return response.json()
})
.then((body) => body);
console.log(responseBody);
return responseBody;
}

View File

@@ -5,12 +5,15 @@ const props = defineProps({
isMinimizer: {type: Boolean}
})
const emit = defineEmits(["update:result"])
const emit = defineEmits([
'update:result',
'update:error'
])
function process() {
var request:Request = prepareRequest();
var request:Request = prepareRequest()
fetchRequest(request).then((data) => {
sendProcessedData(data);
sendProcessedData(data)
})
}
@@ -18,36 +21,39 @@ function prepareRequest():Request {
var request = new Request(prepareURL(), {
body: prepareRequestBody(),
method: "POST"
});
})
return request
}
function prepareURL(): string {
var mode = "prettify";
var mode = "prettify"
if (props.isMinimizer)
mode = "minimize";
return document.location.protocol + "//" + document.location.hostname + "/libxml/" + mode;
mode = "minimize"
return document.location.protocol + "//" + document.location.hostname + "/libxml/" + mode
}
function prepareRequestBody():string {
var requestBody = JSON.stringify({
"data": props.xml,
"process": "N/A",
"processorData": "N/A",
"processor": "libxml",
"version": "1.0"
});
return requestBody;
})
return requestBody
}
async function fetchRequest(request: Request):Promise<JSON> {
var responseBody = await fetch(request)
.then(response => response.json())
.then((body) => body);
return responseBody;
.then((body) => {
emit("update:error", body.status == "ERR")
return body
})
return responseBody
}
function sendProcessedData(data: JSON) {
emit("update:result", data);
emit("update:result", data)
}
</script>

View File

@@ -5,12 +5,35 @@
<template>
<div class="dark:text-slate-100">
<h1 class="text-3xl mb-4">Welcome to Release11 Tools</h1>
<h2 class="text-xl">Our toolset is split to three main categories:</h2>
<ol class="list-decimal ml-5">
<h2 class="text-xl">Our tool set is split to three main categories:</h2>
<ul class="list-decimal ml-5">
<li><strong>XML</strong> - containing various tools that allow to validate and transform any XML</li>
<li><strong>Formatter</strong> - containing tools for formatting text files in various formats</li>
<li><strong>REST</strong> - consist of Mock that allows to create mocked REST endpoint</li>
</ol>
<li><strong>Encoder</strong> - consist of encoders for Base64 and URL</li>
</ul>
<br/>
<h2 class="text-xl mt-2">XML - Tools:</h2>
<ul class="list-decimal ml-5">
<li><strong>XPath</strong> - This is tool that allows to parse XPath on selected XML</li>
<li><strong>XQuery</strong> - Allows to execute XQuery on provided XML file.</li>
<li><strong>XSD</strong> - Allows to validate XML against provided XSD schema.</li>
<li><strong>XSLT</strong> - Allows to transformate XML using XSLT transformate.</li>
</ul>
<h2 class="text-xl mt-2">Formatter - Tools:</h2>
<p>These are tools that allow to format or minimize files in bespoken formats.</p>
<h2 class="text-xl mt-2">REST - Tools:</h2>
<p>This is tools that allow to created mocked REST Service that can be used to test REST clients.</p>
<h2 class="text-xl mt-2">Encoder - Tools:</h2>
<ul class="list-decimal ml-5">
<li><strong>Base64</strong> - This is tool allowing to encode text to base64 and decode base64 to text or image.</li>
<li><strong>URL</strong> - This tool allow to encode string in the way that is used by browser when you put it in address bar.</li>
</ul>
</div>
</template>

View File

@@ -0,0 +1,18 @@
<script setup lang="ts">
import { ref } from 'vue'
const props = defineProps(
{
name: {type: String, required: true}
}
)
</script>
<template>
<h3 class="text-lg font-medium mt-2">{{ name }}</h3>
<p><slot></slot></p>
</template>

View File

@@ -0,0 +1,21 @@
<script setup lang="ts">
import { ref } from 'vue'
const props = defineProps(
{
imgPath: {type: String, required: true},
label: {type: String, required: true}
}
)
</script>
<template>
<div class="flex flex-col gap-2 w-fit h-fit shadow-sm bg-slate-200 dark:bg-slate-800 p-2 rounded-md my-2 text-center self-center">
<img id="url_section" class="rounded-md" :src="imgPath" />
<label for="url_section" class="text-sm mb-0 text-slate-600 dark:text-slate-300">{{ label }}</label>
</div>
</template>

View File

@@ -0,0 +1,38 @@
<script setup lang="ts">
import { ref } from 'vue';
// const props = defineProps({
// version: {
// type: String,
// required: true
// },
// toolType: {
// type: String,
// required: true
// }
// })
const emit = defineEmits([
"update:visible"
])
const areTooltipsHidden = ref(true)
function toggleTooltips() {
areTooltipsHidden.value = !areTooltipsHidden.value;
emit("update:visible", !areTooltipsHidden.value)
}
</script>
<template>
<div :class="areTooltipsHidden ? 'w-fit' : 'w-5/12'" class="hidden xl:flex items-stretch p-2 flex-row rounded-xl shadow-lg bg-gradient-to-r from-blue-400 to-blue-300 dark:from-sky-600 dark:to-sky-800 ">
<button :class="{'mr-2' : !areTooltipsHidden }" class="text-xl w-6 dark:text-slate-100" @click="toggleTooltips()">
T<br/>o<br/>o<br/>l<br/>t<br/>i<br/>p<br/>s
</button>
<div id="content" :class="{'hidden' : areTooltipsHidden}" class="w-full flex flex-col gap-4 p-2 overflow-auto rounded-xl dark:text-white bg-indigo-50 dark:bg-gray-700" >
<slot></slot>
</div>
</div>
</template>

View File

@@ -0,0 +1,71 @@
<script setup lang="ts">
import ImgMan from './ImgMan.vue';
import ElementDescription from './ElementDescription.vue';
import urlSectionImg from '@assets/man/rest-mock/URL_section.png';
import statusSectionImg from '@assets/man/rest-mock/Status_section.png';
import bodySectionImg from '@assets/man/rest-mock/Body_section.png';
import headerSectionImg from '@assets/man/rest-mock/Header_section.png';
</script>
<template>
<div class="flex flex-col dark:text-slate-100 w-full h-full text-justify overflow-auto px-2">
<h2 class="text-2xl font-bold mt-4 mb-2">Description</h2>
<p><span class="font-medium">REST Mock</span> is a tool allowing to create temporary REST endpoint called REST Mock, that allows to test REST clients.</p>
<br>
<p>Its main functions are:</p>
<ul class="list-disc ml-5">
<li>Generating random URL for each user, one per user, with persistence for 24h.</li>
<li>Customizable HTTP response status code</li>
<li>Customizable response body and its content type</li>
<li>Customizable response headers</li>
<li>History of connections to generated endpoint with ability to look into request method, headers and body</li>
</ul>
<h2 class="text-2xl font-bold mt-4 mb-2">GUI elements</h2>
<p>This section describe how certain elements of the application work:</p>
<ElementDescription name="URL field">This field contains autogenerated URL for your REST Mock. All links are removed every 24h.</ElementDescription>
<ElementDescription name="'Save' button">Applies every change made on this page and saves it between sessions.</ElementDescription>
<ElementDescription name="Response Content Type field">Its just convenient way to set "Content-Type" header in the response.</ElementDescription>
<ElementDescription name="Response HTTP Status field">This field sets HTTP status that will be sent to client. Any valid HTTP status can be used, by default it's 200 OK.</ElementDescription>
<ElementDescription name="Response Body field">Here you can set response body. This is sophisticated text editor with syntax-highlighting based on detected language. It works both with JSON and XML data.</ElementDescription>
<ElementDescription name="Response Headers section">This section contains three default and unremovable headers ("Connection", "Date", "Keep-Alive") as well as empty field used to adding custom header. Adding header with empty value is possible, but every header has to have a name. When adding new header is possible, the "Add" button becomes active. New header is added after "Add" button is clicked.</ElementDescription>
<ElementDescription name="History">This section allows to look into history of requests sent to current REST Mock. Entries are sorted by descending by date (newer are first). If request has body, "Show body" button appears in its entry. Also there is option to look into every request's headers by clicking "Show Headers" button. For now, History doesn't refresh automatically. To refresh it, click small refresh button on the right-hand side.</ElementDescription>
<h2 class="text-2xl font-bold mt-4 mb-2">Example</h2>
<p>Let's say we want to create temporary endpoint that returns code 200 with body:</p>
<div class="w-fit p-2 my-2 bg-slate-200 dark:bg-slate-800 rounded-md self-center"><pre>{
"status": "completed",
"warnings": "none"
}</pre></div>
<p>Additionally we want to set some headers:</p>
<div class="w-fit p-2 my-2 bg-slate-200 dark:bg-slate-800 rounded-md self-center"><pre> Name Value
operation addition
priority urgent
</pre></div>
<p>In this example we will focus on the left-hand side panel first as it contains most of the settings. On the top you see autogenerated URL link to your REST Mock service and the "Save" button that saves every setting on this page.</p>
<ImgMan :imgPath="urlSectionImg" label="Screenshot of Rest Mock URL bar and Save button"></ImgMan>
<p>Next, down from REST Mock URL are two text fields. One for content type of a response and second for the HTTP status of a response. </p>
<ImgMan :imgPath="statusSectionImg" label='Screenshot of "Response Content Type" and "Response HTTP Status"'></ImgMan>
<p>These two fields are first things that we will set in this example. Out content type is JSON, so we will put "application/json" in "Response Content Type" field. The "Response HTTP Status" field we'll leave
unchanged for now.</p><br/>
<p>Next element of this tool is big "Response Body" text field. Here you can put data that you want your REST Mock to respond with. In this example we will put JSON from few lines above.</p>
<ImgMan :imgPath="bodySectionImg" label='Screenshot of Response Body field filled with example JSON'></ImgMan>
<p>Last thing that we have to set are headers. Those we can set in Headers section.</p>
<ImgMan :imgPath="headerSectionImg" label='Screenshot of Headers Section with added custom headers.'></ImgMan>
</div>
</template>
<style scoped></style>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import CodeEditorComponent from '../CodeEditorComponent.vue';
import CodeEditorComponent from '@/components/common/CodeEditorComponent.vue';
const props = defineProps(

View File

@@ -55,6 +55,7 @@ function addNewHeader(name : string, value : string){
<template>
<div class="flex flex-col gap-4">
<label>Response Headers</label>
<div class="flex flex-row gap-4">
<div class="w-full">Header name</div>
<div class="w-full">Header value</div>

View File

@@ -10,14 +10,14 @@ const props = defineProps(
</script>
<template>
<div class="w-full text-center text-white mt-2 flex flex-col gap-4 ">
<div class="w-full h-2/3 text-center dark:text-white mt-2 flex flex-col gap-4 overflow-auto">
<div class="flex flex-row gap-4">
<div class="w-full font-bold">Name</div>
<div class="w-full font-bold">Value</div>
</div >
<div class="flex flex-row gap-4" v-for="(value,name) in JSON.parse(data)" :key="name">
<div class="w-full overflow-hidden">{{ name }}</div>
<div class="w-full overflow-hidden">{{ value }}</div>
<div class="w-1/2 break-words">{{ name }}</div>
<div class="w-1/2 break-words">{{ value }}</div>
</div>
</div>
</template>

View File

@@ -34,8 +34,9 @@ function showHeaders(headers: object, index: number){
<template>
<div class="w-full xl:w-2/5 flex flex-none flex-col gap-y-4">
<HistoryRecords class="xl:h-1/3 overflow-y-scroll" @click:show-headers="showHeaders" @click:show-body="showBody"></HistoryRecords>
<div class="flex flex-1 flex-col xl:w-3/12 justify-items-stretch gap-y-4">
<label class="dark:text-white text-center"><span class="font-bold">Attention! </span>History doesn't refresh automatically! Use refresh button (⟳) on the right!</label>
<HistoryRecords class="xl:h-1/3 overflow-y-auto" @click:show-headers="showHeaders" @click:show-body="showBody"></HistoryRecords>
<BodyDetailComponent :content-type="currentContentType" :data="currentShownData" v-if="shownDetail == 'body' "></BodyDetailComponent>
<HeadersDetailComponent :data="currentShownData" v-if="shownDetail == 'headers' "></HeadersDetailComponent>
</div>

View File

@@ -45,12 +45,12 @@ function refreshHistory(){
</script>
<template>
<div>
<table class="text-white h-28 w-full text-center">
<div class="h-28 text-center text-grey-900 dark:text-white">
<table class="w-full">
<tr>
<th>Time</th>
<th>HTTP Method</th>
<th>HTTP Headers</th>
<th>Request <br>HTTP Method</th>
<th>Request Headers</th>
<th>Request Body</th>
<th class="text-2xl"><button @click="refreshHistory()"></button></th>
</tr>
@@ -60,7 +60,7 @@ function refreshHistory(){
<td> <button @click="showHeaders(item.headers, index)" class="underline">Show Headers</button> </td>
<td>
<button v-if="item.requestBody.length != 0" @click="showBody(item.requestBody, index, item.headers['content-type'])" class="underline">Show Body</button>
<span v-else>Empty Body</span>
<span v-else>Empty</span>
</td>
</tr>
</table>

View File

@@ -2,7 +2,7 @@
import {ref, type Ref} from 'vue';
import HeadersComponent from './HeadersComponent.vue';
import SaveComponent from './SaveComponent.vue';
import CodeEditorComponent from '../CodeEditorComponent.vue';
import CodeEditorComponent from '@/components/common/CodeEditorComponent.vue';
const clientUUID = ref('');
const host = window.location.protocol + "//" + window.location.hostname + "/mock";
@@ -44,31 +44,30 @@ function showUpdatedCode(newCode : string){
</script>
<template>
<div class="flex flex-col flex-none w-full xl:w-3/5 text-center dark:text-white gap-6 p-1">
<div class="flex flex-col flex-none w-full xl:w-3/5 text-center dark:text-white gap-3 p-1">
<div class="flex flex-col md:flex-row gap-4 items-center md:justify-stretch md:items-end">
<div class="flex flex-col w-full">
<label for="link">Link</label><br/>
<label for="link">REST Service URL</label>
<div class="p-2 w-full border-slate-400 border-2 rounded-lg">
<a class="underline" :href="mockMessageLink">{{ mockMessageLink }}</a>
</div>
</div>
<SaveComponent v-bind:message-data="messageData"></SaveComponent>
</div>
<div class="flex flex-col md:flex-row w-full gap-4">
<div class="w-full">
<label for="contentType">Content Type</label><br/>
<label for="contentType">Response Content Type</label><br/>
<input class="text-field" id="contentType" type="text" v-model="messageData.contentType"/>
</div>
<div class="w-full">
<label for="httpStatus">HttpStatus</label><br/>
<label for="httpStatus">Response HTTP Status</label><br/>
<input class="text-field" id="httpStatus" type="text" v-model="messageData.httpStatus"/>
</div>
</div>
<div class="flex text-left flex-col overflow-scroll h-3/4">
<label for="messageBody text-center">Body</label>
<div class="flex text-left flex-col overflow-auto gap-2 h-3/4">
<label class="text-center" for="messageBody text-center">Response Body</label>
<CodeEditorComponent
@update:updated-code="showUpdatedCode"
v-model="messageData.messageBody"

View File

@@ -15,7 +15,7 @@ const visible = ref('hidden');
const fetchLink = window.location.protocol + "//" + window.location.hostname + "/mock/api/mock";
function prepareAndSendData(){
if (props.messageData != null|| props.messageData != undefined ){
if (props.messageData != null || props.messageData != undefined ){
fetch(fetchLink, { method: "put", body:JSON.stringify(props.messageData), headers: { "Content-Type" : "application/json" }})
.then( response => response.text() )
.then( data => {message.value = data} )

View File

@@ -1,10 +1,16 @@
<script setup lang="ts">
import ThemeSwitcherComponent from '../common/ThemeSwitcherComponent.vue';
const emit = defineEmits([
"theme",
]);
</script>
<template>
<div class="flex flex-col gap-4 text-center font-thin text-slate-600 dark:text-slate-400 ">
<div class="flex flex-col gap-4 items-center text-center font-thin text-slate-600 dark:text-slate-400 ">
<ThemeSwitcherComponent @theme="(theme)=>emit('theme',theme)"></ThemeSwitcherComponent>
<div class="flex flex-col">
<a href="mailto:bugs@release11.com">Found a bug?</a>
<a href="#" class="hidden">Privacy Policy</a>

View File

@@ -8,15 +8,27 @@ import logoWhite from '@assets/logo_czarne.svg';
const logoR11 = ref( logoDark );
const emit = defineEmits([
'theme:changed'
])
function changeLogoForTheme(){
logoR11.value = isDarkModeSet() ? logoDark : logoWhite;
}
function isDarkModeSet(){
return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
if (localStorage.theme)
return localStorage.theme == "dark";
else
return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
}
function changeTheme(theme:string){
changeLogoForTheme()
emit('theme:changed',theme);
}
onMounted( () => {
changeLogoForTheme();
})
@@ -29,8 +41,8 @@ onMounted( () => {
<a href="https://release11.com/">
<img :src="logoR11" class="w-72 h-16 p-2 pt-0"/>
</a>
<div class="flex basis-full flex-col font-medium items-center">
<sidebar-menu-element-component category-name="XML">
<div class="flex basis-full flex-col font-normal items-center">
<sidebar-menu-element-component category-name="Parser">
<SidebarToolLinkComponent path-to="/xml/xpath" element-content="XPath" />
<SidebarToolLinkComponent path-to="/xml/xquery" element-content="XQuery" />
<SidebarToolLinkComponent path-to="/xml/xsd" element-content="XSD" />
@@ -48,8 +60,14 @@ onMounted( () => {
<SidebarToolLinkComponent path-to="/rest/mock" element-content="Mock" />
</sidebar-menu-element-component>
<sidebar-menu-element-component category-name="Encoder">
<SidebarToolLinkComponent path-to="/encoder/base64" element-content="Base64" />
<SidebarToolLinkComponent path-to="/encoder/url" element-content="URL" />
</sidebar-menu-element-component>
</div>
<FooterComponent></FooterComponent>
<FooterComponent @theme="changeTheme"></FooterComponent>
</div>
</aside>
</template>

View File

@@ -18,10 +18,10 @@ const props = defineProps(
<template>
<div class="w-full mb-4 p-2 rounded-xl shadow-lg bg-gradient-to-r from-blue-400 to-blue-300 dark:from-sky-700 dark:to-sky-900">
<button @click="switchHiddenElement()" type="button" :class="[isActive ? 'rounded-lg' : 'rounded-lg']" class="w-full p-2 text-lg font-bold text-gray-900 transition duration-75 hover:bg-blue-100 dark:text-gray-100 dark:hover:bg-slate-600">
<button @click="switchHiddenElement()" type="button" :class="[isActive ? 'rounded-lg' : 'rounded-lg']" class="w-full p-1 text-lg font-normal text-gray-900 transition duration-75 hover:bg-blue-100 dark:text-gray-100 dark:hover:bg-slate-600">
<span class="flex-1 whitespace-nowrap">{{props.categoryName}}</span>
</button>
<div class="flex flex-col w-full py-2 bg-indigo-50 dark:bg-slate-800 rounded-xl font-thin overflow-hidden" :class="[isActive ? 'active' : 'hidden']">
<div class="flex flex-col w-full mt-2 py-2 bg-indigo-50 dark:bg-slate-800 rounded-xl font-light overflow-hidden" :class="[isActive ? 'active' : 'hidden']">
<slot></slot>
</div>
</div>

View File

@@ -17,6 +17,6 @@ const props = defineProps(
<style>
.router-link-active {
font-weight: 500;
font-weight: 600;
}
</style>

View File

@@ -0,0 +1,32 @@
<script setup lang="ts">
const props = defineProps({
id: {
type: Number,
required: true
},
isActive: {
type: Boolean,
default: false,
required: false
}
})
const emit = defineEmits(["click:activate", "click:remove"])
function activate() {
emit("click:activate", props.id);
}
function remove() {
emit("click:remove", props.id);
}
</script>
<template>
<div :class=" isActive ? 'tab-active' : 'tab'" class="flex flex-row gap-3">
<button @click="activate" class="hover:brightness-110"><slot /></button>
<button @click="remove" class="hover:brightness-110 hover:bg-blue-100 hover:dark:bg-slate-400 hover:dark:text-black px-2 rounded-full">x</button>
</div>
</template>

View File

@@ -1,10 +1,8 @@
<script setup lang="ts">
import InsertTemplateComponent from '@components/common/InsertTemplateComponent.vue';
import InsertTemplateComponent from '@components/common/InsertTemplateComponent.vue'
import XMLButtonFormatterComponent from '@components/formatter/XMLButtonFormatterComponent.vue'
import { ref } from 'vue';
import CodeEditor from '../CodeEditorComponent.vue';
const data = ref('')
import { ref } from 'vue'
import CodeEditor from '@/components/common/CodeEditorComponent.vue'
const props = defineProps(
{
@@ -12,45 +10,60 @@ const props = defineProps(
data: {type: String},
}
)
const emit = defineEmits(['update'])
const emit = defineEmits(['update:modelValue'])
const data = ref('')
const inputFile = ref()
function sendValue() {
console.log("input works")
emit('update', data.value)
emit('update:modelValue', data.value)
}
function sendNewValue(newValue : string) {
data.value = newValue
emit('update', data.value)
}
function updateData(newData: string) {
data.value = newData;
sendValue();
function updateData(newData: string, clearFileSelector: boolean = true) {
data.value = newData
if (clearFileSelector)
inputFile.value.value = '';
sendValue()
}
function clear() {
updateData('');
updateData('')
}
function canBeFormatted() {
return props.stylizedName.toLowerCase() == 'xml' ||
props.stylizedName.toLowerCase() == 'xsd' ||
props.stylizedName.toLowerCase() == 'xslt';
props.stylizedName.toLowerCase() == 'xslt'
}
function readFile(file : any) {
const reader = new FileReader()
reader.onloadend = () => {
let result = reader.result?.toString()
if (typeof result == "string")
updateData(result, false);
}
reader.readAsText(file.target.files[0])
}
</script>
<template>
<div class="flex flex-col w-full h-1/2 lg:h-1/2 flex-none pr-4 pb-2">
<div class="flex flex-col w-full h-1/2 lg:h-1/2 flex-none xl:pr-2 2xl:pr-4 pb-2">
<div class="flex place-content-between w-full items-center">
<span class="dark:text-white">{{ stylizedName }}</span>
<div class="flex space-x-2 pb-2">
<InsertTemplateComponent :stylized-name="props.stylizedName" @update:default-data="(data: string) => updateData(data)"></InsertTemplateComponent>
<span class="dark:text-white mr-2">{{ stylizedName }}</span>
<div class="flex space-x-2 pb-2 overflow-x-auto">
<div class="flex items-stretch w-64">
<input id="fileLoader" ref="inputFile" class="file-selector" type="file" accept=".xml,.xql,.xquery,.xslt,text/xml,text/plain" @change="readFile" />
</div>
<InsertTemplateComponent :stylized-name="props.stylizedName" @update:default-data="updateData"></InsertTemplateComponent>
<XMLButtonFormatterComponent v-if="canBeFormatted()" :xml="data" @update:result="(data:any) => updateData(data.result)"></XMLButtonFormatterComponent>
<button class="tool-button" @click="clear">Clear</button>
</div>
</div>
<CodeEditor @update:updated-code="sendNewValue" v-model="data" :code="data" :config="{disabled:false, language:stylizedName}"></CodeEditor>
<CodeEditor @update:updated-code="updateData" v-model="data" :code="data" :config="{disabled:false, language:stylizedName}"></CodeEditor>
</div>
</template>

View File

@@ -1,13 +1,13 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import CodeEditor from '../CodeEditorComponent.vue';
import { type TabData } from '../common/TabData'
import CodeEditor from '@/components/common/CodeEditorComponent.vue';
const props = defineProps(
{
tool: {type: String, required: true},
xml: {type: String},
query: {type: String}
xml: {type: [String, Array<TabData>], required: true},
query: {type: String, required: true}
}
)
@@ -15,14 +15,21 @@ const emit = defineEmits(["update"]);
const result = ref('');
var enginesForCurrentTool = ref(["saxon", "xalan", "libxml"]);
let enginesForCurrentTool = ref(["saxon", "xalan", "libxml"]);
const allVersions = ["1.0", "2.0", "3.0", "3.1"];
var versionsForCurrentEngine = ref([""]);
let versionsForCurrentEngine = ref([""]);
const engine = ref('');
const version = ref('');
const errorOccurred = ref(false);
const successOccurred = ref(false);
interface XmlFile {
fileName: string;
fileData: string;
}
onMounted(() => {
changeAvailableEngines();
@@ -72,79 +79,147 @@ function selectDefaultEngine() {
}
function selectDefaultVersion() {
const lastVersion = versionsForCurrentEngine.value.length - 1
const lastVersion = versionsForCurrentEngine.value.length - 1;
version.value = versionsForCurrentEngine.value[lastVersion];
emitVersionChange();
}
function process() {
var request:Request = prepareRequest();
let request:Request = prepareRequest();
fetchRequest(request).then((data) => {
updateOutputField(data);
})
}
function updateOutputField(data: any) {
result.value = data.result
errorOccurred.value = data.status != "OK"
successOccurred.value = data.status == "OK"
}
function prepareRequest():Request {
var request = new Request(prepareURL(), {
body: prepareRequestBody(),
let request = new Request(prepareURL(), {
body: selectRequestBodyType(),
method: "POST"
});
return request
}
function prepareURL(): string {
const engineEndpoint = engine.value == "libxml" ? "libxml" : "java";
return document.location.protocol + "//" + document.location.hostname + "/" + engineEndpoint + "/" + props.tool;
const engineEndpoint = engine.value == "libxml" ? "libxml" : "java";
let tool = props.tool;
if (Array.isArray(props.xml) && props.xml.length > 1)
tool = "multiple/xslt";
return document.location.protocol + "//" + document.location.hostname + "/" + engineEndpoint + "/" + tool;
}
function prepareRequestBody():string {
var requestBody = JSON.stringify({
"data": props.xml,
"process": props.query,
function selectRequestBodyType() : string {
if (Array.isArray(props.xml) && props.xml.length > 1)
return prepareRequestBodyMultiXml();
else if (Array.isArray(props.xml))
return prepareRequestBodySingleXml(props.xml.at(0)!.data);
else
return prepareRequestBodySingleXml(props.xml!);
}
function prepareRequestBodySingleXml(data: string):string {
let requestBody = JSON.stringify({
"data": data,
"processorData": props.query,
"processor": engine.value,
"version": version.value
});
return requestBody;
}
async function fetchRequest(request: Request):Promise<JSON> {
var responseBody = await fetch(request)
.then(response => response.json())
.then((body) => body);
return responseBody;
function prepareRequestBodyMultiXml():string {
if (!Array.isArray(props.xml))
return "";
let xmlFilesArray = convertDataArray(props.xml);
let requestBody = JSON.stringify({
"data": xmlFilesArray,
"processorData": props.query,
"processor": engine.value,
"version": version.value
});
return requestBody;
}
function updateOutputField(data: any) {
result.value = data.result;
function convertDataArray(data: Array<TabData>) {
let result = new Array<XmlFile>;
data.forEach(element => {
let fileName = element.name;
if (!fileName.endsWith(".xml")) {
fileName += ".xml";
}
result.push({
fileName: fileName,
fileData: element.data,
});
});
return result;
}
async function fetchRequest(request: Request):Promise<JSON> {
let responseBody = await fetch(request)
.then(response => response.json())
.then((body) => body)
return responseBody
}
function clear() {
result.value = "";
result.value = ""
errorOccurred.value = false
successOccurred.value = false
}
function emitVersionChange() {
emit("update", version.value);
}
function isVersionSelectionAvailable() {
return !(versionsForCurrentEngine.value.length == 1 && versionsForCurrentEngine.value.at(0) == "N/A");
}
function highlightField() {
if (errorOccurred.value)
return "text-field-error";
if (successOccurred.value)
return "text-field-success";
return "";
}
</script>
<template>
<div class="flex flex-col flex-none w-full lg:w-1/2 h-1/3 lg:h-full items-center pb-2 pr-2">
<div class="flex flex-col flex-none w-full 2xl:w-1/2 h-1/3 2xl:h-full items-center pb-2 xl:pr-2">
<div class="flex place-content-between w-full items-center pb-2">
<span class="dark:text-white">Result:</span>
<div class="flex space-x-2">
<div class="flex space-x-2 overflow-x-auto">
<select v-model="engine" name="engine" @change="changeAvailableVersions()" class="px-3 rounded-full border border-slate-400 bg-white dark:text-slate-100 dark:bg-gray-600">
<option v-for="engine in enginesForCurrentTool" :value="engine">{{ engine }}</option>
</select>
<select v-model="version" name="version" @change="emitVersionChange()" class="px-3 rounded-full border border-slate-400 bg-white dark:text-slate-100 dark:bg-gray-600">
<select v-model="version" v-if="isVersionSelectionAvailable()" name="version" @change="emitVersionChange()" class="px-3 rounded-full border border-slate-400 bg-white dark:text-slate-100 dark:bg-gray-600">
<option v-for="version in versionsForCurrentEngine" :value="version">{{ version }}</option>
</select>
<button class="tool-button" @click="clear">Clear</button>
<button class="tool-button" @click="process">Process</button>
</div>
</div>
<div class="overflow-scroll h-full w-full">
<CodeEditor :code="result" :config="{disabled:true,language:tool}"></CodeEditor>
<div class="overflow-auto h-full w-full rounded-2xl" :class="highlightField()">
<CodeEditor :code="result" :config="{disabled:false,language:tool}"></CodeEditor>
</div>
</div>

View File

@@ -0,0 +1,153 @@
<script setup lang="ts">
import TabComponent from './TabComponent.vue'
import InsertTemplateComponent from '@components/common/InsertTemplateComponent.vue'
import XMLButtonFormatterComponent from '@components/formatter/XMLButtonFormatterComponent.vue'
import { type TabData } from '../common/TabData'
import { ref } from 'vue'
import CodeEditor from '@/components/common/CodeEditorComponent.vue';
const props = defineProps(
{
stylizedName: {type: String, required: true},
data: {type: Array<TabData>},
tabCountLimit: {type: Number, required: false, validator: (value) => typeof value == "number" && value > 0}
}
)
const emit = defineEmits(['update:modelValue'])
const newTabId = ref(0);
const activeTabId = ref(0);
const tabs = ref(new Array<TabData>);
tabs.value.push({
id: newTabId.value++,
name: "xml1.xml",
data: "",
})
const data = ref('')
const inputFile = ref()
function sendValue() {
emit('update:modelValue', tabs.value);
}
function updateData(newData: string) {
data.value = newData;
tabs.value.at(findIndexWithID(activeTabId.value))!.data = newData;
inputFile.value.value = '';
sendValue();
}
function clear() {
updateData('');
}
function canBeFormatted() {
return props.stylizedName.toLowerCase() == 'xml' ||
props.stylizedName.toLowerCase() == 'xsd' ||
props.stylizedName.toLowerCase() == 'xslt'
}
function readFile(file : any) {
const reader = new FileReader()
reader.onloadend = () => {
let result = reader.result!.toString();
let activeIndex = findIndexWithID(activeTabId.value);
let filePath = inputFile.value.value.split("\\");
let fileName = filePath.at(filePath.length - 1);
tabs.value.at(activeIndex)!.name = fileName;
updateData(result);
}
reader.readAsText(file.target.files[0]);
}
function changeActiveTab(id : number) {
let index = findIndexWithID(activeTabId.value);
let newIndex = findIndexWithID(id);
tabs.value.at(index)!.data = data.value;
activeTabId.value = id;
data.value = tabs.value.at(newIndex)!.data;
sendValue();
}
function addTab() {
if (isTabCountLimitAchieved())
return
tabs.value.push({
id: newTabId.value++,
name: "xml" + newTabId.value + ".xml",
data: ""
});
}
function isTabCountLimitAchieved() {
return props.tabCountLimit && tabs.value.length == props.tabCountLimit
}
function removeTab(id : number) {
if (tabs.value.length == 1)
return
let indexToRemove = findIndexWithID(id);
switchToExistingTab(indexToRemove);
tabs.value.splice(indexToRemove, 1);
}
function switchToExistingTab(indexToRemove: number) {
let activeIndex = findIndexWithID(activeTabId.value);
if (indexToRemove == activeIndex && activeIndex == 0)
changeActiveTab(tabs.value.at(1)!.id)
else if (indexToRemove == activeIndex)
changeActiveTab(tabs.value.at(0)!.id)
}
function findIndexWithID(id : number) : number {
for (let i = 0; tabs.value.length; i++)
if (tabs.value.at(i)!.id == id)
return i;
return -1;
}
</script>
<template>
<div class="flex flex-col w-full h-1/2 lg:h-1/2 flex-none xl:pr-2 2xl:pr-4 pb-2">
<div class="flex justify-between mb-2">
<div class="flex gap-2 overflow-x-auto">
<TabComponent @click:activate="changeActiveTab" @click:remove="removeTab" v-for="tab in tabs" :id="tab.id" :isActive="tab.id == activeTabId">{{ tab.name }}</TabComponent>
</div>
<div class="flex gap-2">
<div class="flex items-stretch w-64">
<input id="fileLoader" ref="inputFile" class="file-selector" type="file" accept=".xml,.xql,.xquery,.xslt,text/xml,text/plain" @change="readFile" />
</div>
<button :class="isTabCountLimitAchieved() ? 'inactive-button' : 'tool-button'" @click="addTab">New</button>
</div>
</div>
<div class="flex place-content-between w-full items-center">
<span class="dark:text-white mr-2">{{ stylizedName }}</span>
<div class="flex space-x-2 pb-2 overflow-x-auto">
<InsertTemplateComponent :stylized-name="props.stylizedName" @update:default-data="updateData"></InsertTemplateComponent>
<XMLButtonFormatterComponent v-if="canBeFormatted()" :xml="data" @update:result="(data:any) => updateData(data.result)"></XMLButtonFormatterComponent>
<button class="tool-button" @click="clear">Clear</button>
</div>
</div>
<CodeEditor @update:updated-code="updateData" v-model="data" :code="data" :config="{disabled:false, language:stylizedName}"></CodeEditor>
</div>
</template>

View File

@@ -13,7 +13,7 @@ function toggleTooltips() {
</script>
<template>
<div class="flex p-2 flex-col rounded-xl shadow-lg bg-gradient-to-r from-zinc-400 to-slate-400 dark:from-slate-600 dark:to-slate-700">
<div class="flex p-2 flex-col rounded-xl shadow-lg bg-gradient-to-r from-gray-300 to-slate-300 dark:from-slate-500 dark:to-slate-600">
<button :class="{ 'mb-2' : !isCategoryHidden }" class="dark:text-slate-100 hover:font-bold" @click="toggleTooltips()">{{ props.name }}</button>
<div id="content" :class="{'hidden' : isCategoryHidden}" class="flex flex-col gap-4 w-full h-fit p-2 rounded-xl dark:text-white bg-indigo-50 dark:bg-slate-800" >
<slot></slot>

View File

@@ -58,11 +58,11 @@ function toggleTooltips() {
</script>
<template>
<div :class="areTooltipsHidden ? 'w-fit' : 'w-4/12'" class="hidden 2xl:flex shrink-0 items-stretch p-2 flex-row rounded-xl shadow-lg bg-gradient-to-r from-blue-400 to-blue-300 dark:from-sky-600 dark:to-sky-800 ">
<div :class="areTooltipsHidden ? 'w-fit' : 'w-[26rem]'" class="hidden xl:flex shrink-0 items-stretch p-2 flex-row rounded-xl shadow-lg bg-gradient-to-r from-blue-400 to-blue-300 dark:from-sky-600 dark:to-sky-800 ">
<button :class="{'mr-2' : !areTooltipsHidden }" class="text-xl w-6 dark:text-slate-100" @click="toggleTooltips()">
T<br/>o<br/>o<br/>l<br/>t<br/>i<br/>p<br/>s
</button>
<div id="content" :class="{'hidden' : areTooltipsHidden}" class="w-full flex flex-col gap-4 p-2 overflow-scroll rounded-xl dark:text-white bg-indigo-50 dark:bg-slate-800" >
<div id="content" :class="{'hidden' : areTooltipsHidden}" class="w-full flex flex-col gap-4 p-2 overflow-auto rounded-xl dark:text-white bg-indigo-50 dark:bg-gray-700" >
<TooltipDiffsComponent :tool-name="toolType" :tool-version="props.version"></TooltipDiffsComponent>
<div class="w-full h-2"> </div>
<tooltipCategoryComponent v-for="category in selectTooltip()" :key="category.name" :name="category.name">

View File

@@ -12,19 +12,19 @@ const props = defineProps({
function getDiffEntry(toolVersion : String) : string[] {
if ( props.toolName == "xpath" ){
switch(toolVersion){
case "2.0" : {
return xpathDiffs.VersionDiffs[0].diffs
case "2.0" : {
return xpathDiffs.VersionDiffs[0].diffs
}
case "3.0" : {
return xpathDiffs.VersionDiffs[1].diffs
}
case "3.1" : {
return xpathDiffs.VersionDiffs[2].diffs
}
default: {
return xpathDiffs.VersionDiffs[2].diffs
}
}
case "3.0" : {
return xpathDiffs.VersionDiffs[1].diffs
}
case "3.1" : {
return xpathDiffs.VersionDiffs[2].diffs
}
default: {
return xpathDiffs.VersionDiffs[2].diffs
}
}
} else if (props.toolName == "xslt") {
return ["XSLT 2.0"].concat(xsltDiffs.VersionDiffs[0].diffs).concat(["XSLT 3.0"]).concat(xsltDiffs.VersionDiffs[1].diffs) ;
} else{
@@ -56,7 +56,7 @@ function getInfo(num : number ){
</span>
</TooltipCategoryComponent>
<TooltipCategoryComponent v-if="toolVersion !== '1.0'" :name="getInfo(1).category">
<TooltipCategoryComponent v-if="toolVersion !== '1.0'" :name="getInfo(1).category + ' ' + toolVersion + '?'">
<span v-for=" diff in getDiffEntry(toolVersion)" v-bind:key="diff" class=" text-justify" >
<div class="w-full h-4 text-center" v-if="diff.includes('XSLT')">
------------ {{ diff }} ------------

Binary file not shown.

Binary file not shown.

View File

@@ -12,6 +12,11 @@ const xsdTool = import("@views/XSDView.vue")
const xpathTool = import("@views/XPathView.vue")
const xqueryTool = import("@views/XQueryView.vue")
const base64Encoder = import("@views/Base64EncoderView.vue")
const urlEncoder = import("@views/UrlEncoderView.vue")
const restMockMan = import("@views/man/RestMockManView.vue")
const routes = [
{
path: '/',
@@ -57,6 +62,21 @@ const routes = [
path: '/rest/mock',
name: 'restmock',
component: () => restMock
},
{
path: '/encoder/base64',
name: 'base64encoder',
component: () => base64Encoder
},
{
path: '/encoder/url',
name: 'urlEncoder',
component: () => urlEncoder
},
{
path: '/man/rest-mock',
name: 'RestMockManView',
component: () => restMockMan
}
]

View File

@@ -2,14 +2,44 @@
@tailwind components;
@tailwind utilities;
@font-face {
font-family: "Raleway";
src: url("fonts/Raleway-Variable.ttf");
}
@font-face {
font-family: "Sono";
src: url("fonts/Sono-Variable.ttf");
}
.inactive-button {
@apply py-2 px-4 h-fit text-slate-400 border border-slate-400 rounded-full
@apply py-2 px-3 h-fit text-slate-400 border border-slate-400 rounded-full
}
.tool-button {
@apply hover:brightness-110 py-2 px-4 h-fit rounded-full bg-gradient-to-r from-blue-400 to-sky-300 dark:text-white dark:from-sky-600 dark:to-sky-800 hover:bg-blue-400
@apply hover:brightness-110 py-2 px-3 h-fit min-w-fit rounded-full bg-gradient-to-r from-blue-400 to-sky-300 dark:text-white dark:from-sky-600 dark:to-sky-800 hover:bg-blue-400
}
.text-field {
@apply w-full font-mono dark:text-slate-100 bg-slate-50 dark:bg-gray-600 border border-slate-400 p-2 rounded-lg
}
}
.file-selector {
@apply block file:border-none file:font-sans file:text-base file:hover:brightness-110 file:py-2 file:px-3 file:h-full file:w-fit file:rounded-full file:bg-gradient-to-r file:from-blue-400 file:to-sky-300 file:dark:text-white file:dark:from-sky-600 file:dark:to-sky-800 file:hover:bg-blue-400 w-fit rounded-full text-sm text-gray-900 border border-gray-300 cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400
}
.text-field-error {
@apply shadow-[0px_0px_10px_0px_rgba(255,0,0,1)];
}
.text-field-success {
@apply shadow-[0px_0px_10px_0px_rgba(52,211,153,1)];
}
.tab {
@apply py-2 px-3 h-fit dark:text-slate-400 rounded-t-2xl border-t border-l border-r border-slate-400
}
.tab-active {
@apply py-2 px-3 h-fit text-slate-700 border-t border-l border-r border-slate-400 rounded-t-2xl bg-gradient-to-r from-blue-400 to-sky-300 dark:text-white dark:from-sky-600 dark:to-sky-800 hover:bg-blue-400
}

View File

@@ -0,0 +1,75 @@
<script setup lang="ts">
import CodeEditorComponent from '@/components/common/CodeEditorComponent.vue'
import EncoderButton from '@/components/encoder/EncoderButtonComponent.vue'
import { ref } from 'vue'
const data : any = ref("")
const imageData = ref("")
const DoshowImage = ref(false)
const inputImage = ref()
function setTextFieldValue(newData: string) {
data.value = newData.toString()
DoshowImage.value = false
}
function showImage(newImage : string){
imageData.value = "data:image/jpeg;base64,"+newImage
DoshowImage.value = true
}
function convertImageToBase64(file : any){
const reader = new FileReader()
reader.onloadend = () => {
data.value = reader.result?.toString().split(',')[1]
showImage(data.value)
}
reader.readAsDataURL(file.target.files[0])
}
function clear(){
data.value = ""
imageData.value = ""
DoshowImage.value = false
inputImage.value.value = null
}
</script>
<template>
<div id="layoutFull" class="w-full h-full flex flex-col xl:flex-row gap-4">
<div id="layoutLeft" class="flex flex-col w-full xl:w-1/2 h-1/3 xl:h-full gap-4">
<div class="w-full flex flex-row place-content-between items-center">
<label class="dark:text-white text-center">Base64 Encoder</label>
<div class="flex flex-row items-center gap-2 overflow-x-auto">
<button class="tool-button" @click="clear()">Clear</button>
<EncoderButton @image:show="showImage" :code="data" operation-type="Show Image"></EncoderButton>
<div class="w-2"></div>
<EncoderButton @update:result="setTextFieldValue" :code="data" operation-type="Encode"></EncoderButton>
<EncoderButton @update:result="setTextFieldValue" :code="data" operation-type="Decode"></EncoderButton>
</div>
</div>
<div id="codeEditor" class="w-full h-full xl:h-1/3 flex flex-col">
<CodeEditorComponent @update:updated-code="setTextFieldValue" :config="{language:'base64'}" :code="data"></CodeEditorComponent>
</div>
<div class="flex flex-row justify-center w-full">
<div class="flex flex-col items-center w-fit" id="imageImporter">
<label class="block mb-2 text-sm font-medium text-gray-900 dark:text-white" for="file_input">Upload image</label>
<input id="imageLoader" ref="inputImage" class="file-selector" accept=".gif, .jpg, .jpeg, .png, .webm, image/gif, image/jpeg, image/png, image/webm" type="file" @change="convertImageToBase64" />
</div>
</div>
</div>
<div id="layoutRight" class="w-full xl:w-1/2 min-h-[66%] xl:h-full">
<div class="border-2 rounded-lg border-gray-300 dark:border-gray-600 min-h-[50%]" v-on="DoshowImage">
<img :src="imageData"/>
</div>
</div>
</div>
</template>

View File

@@ -1,34 +1,8 @@
<script setup lang="ts">
import InsertTemplateComponent from '@components/common/InsertTemplateComponent.vue';
import CodeEditorComponent from '@/components/CodeEditorComponent.vue';
import { ref } from 'vue';
import HtmlButtonFormatterComponent from '@/components/formatter/HtmlButtonFormatterComponent.vue';
const html = ref('');
function clear() {
html.value = '';
}
function setTextFieldValue(data: string) {
html.value = data.toString()
}
import FormatterComponent from '@/components/formatter/FormatterComponent.vue';
</script>
<template>
<div id="layout" class="flex flex-col w-full h-full gap-4">
<div id="toolbar" class="flex flex-col gap-4 items-center lg:flex-row place-content-between">
<span class="dark:text-slate-100">HTML Formatter</span>
<div class="flex flex-wrap gap-2 justify-center">
<InsertTemplateComponent stylized-name="HTML" @update:defaultData="setTextFieldValue"></InsertTemplateComponent>
<button class="tool-button" @click="clear()">Clear</button>
<HtmlButtonFormatterComponent @update:result="setTextFieldValue" :code="html" format-type="Minimize" />
<HtmlButtonFormatterComponent @update:result="setTextFieldValue" :code="html" format-type="Prettify" />
<HtmlButtonFormatterComponent @update:result="setTextFieldValue" :code="html" format-type="XML Converter" />
</div>
</div>
<CodeEditorComponent @update:updated-code="setTextFieldValue" :code="html" :config="{disabled:false,language:'html'}" />
</div>
<FormatterComponent formatter-language="HTML"></FormatterComponent>
</template>

View File

@@ -1,37 +1,8 @@
<script setup lang="ts">
import CodeEditorComponent from '@/components/CodeEditorComponent.vue';
import JsonButtonFormatterComponent from '@/components/formatter/JsonButtonFormatterComponent.vue';
import InsertTemplateComponent from '@components/common/InsertTemplateComponent.vue';
import { ref } from 'vue';
const json = ref('');
function setTextFieldValue(data: string) {
json.value = data
}
function format(formattedXml: any) {
json.value = formattedXml.data;
}
function clear() {
json.value = '';
}
import FormatterComponent from '@/components/formatter/FormatterComponent.vue';
</script>
<template>
<div id="layout" class="flex flex-col w-full h-full gap-4">
<div id="toolbar" class= "flex flex-col gap-4 items-center lg:flex-row place-content-between">
<span class="dark:text-slate-100">JSON Formatter</span>
<div class="flex flex-wrap gap-2 justify-center">
<InsertTemplateComponent stylized-name="JSON" @update:defaultData="(data: string) => setTextFieldValue(data)"></InsertTemplateComponent>
<button class="tool-button" @click="clear()">Clear</button>
<JsonButtonFormatterComponent isMinimizer :json="json" @update:result="(data: any) => format(data)"></JsonButtonFormatterComponent>
<JsonButtonFormatterComponent :json="json" @update:result="(data: any) => format(data)"></JsonButtonFormatterComponent>
</div>
</div>
<CodeEditorComponent @update:updated-code="setTextFieldValue" :code="json" :config="{disabled:false,language:'json'}" />
</div>
<FormatterComponent formatter-language="JSON"></FormatterComponent>
</template>

View File

@@ -1,14 +1,29 @@
<script setup lang="ts">
import RestMockMessageComponent from '@components/mock/RestMockMessageComponent.vue'
import HistoryComponent from '@components/mock/HistoryComponent.vue'
import ManTooltipComponent from '@/components/man/ManTooltipComponent.vue';
import RestMockManComponent from '@/components/man/RestMockManComponent.vue';
import { ref } from 'vue';
const historyVisibility = ref(true);
function setHistoryVisibility(visibility : boolean) {
historyVisibility.value = !visibility;
}
</script>
<template>
<div class="flex flex-col xl:flex-row gap-6 w-full overflow-y-scroll overflow-x-hidden h-full">
<div class="flex flex-col xl:flex-row gap-6 w-full overflow-y-auto overflow-x-hidden h-full">
<RestMockMessageComponent></RestMockMessageComponent>
<HistoryComponent></HistoryComponent>
<HistoryComponent :class="{'hidden': !historyVisibility}"></HistoryComponent>
<ManTooltipComponent @update:visible="setHistoryVisibility">
<div class="mt-2">
<a class="tool-button" href="/man/rest-mock">Expand</a>
</div>
<RestMockManComponent></RestMockManComponent>
</ManTooltipComponent>
</div>
</template>

View File

@@ -0,0 +1,31 @@
<script setup lang="ts">
import { ref } from 'vue';
import EncodeUriButton from '@components/encoder/EncodeUriButtonComponent.vue'
import CodeEditorComponent from '@/components/common/CodeEditorComponent.vue';
const uri = ref("")
function setTextFieldValue(newVal : string){
console.log(newVal)
uri.value = newVal
}
function clear(){
uri.value = "";
}
</script>
<template>
<div class="flex flex-col w-full h-full gap-4" id="layout">
<div id="toolbar" class="flex flex-col gap-4 items-center lg:flex-row place-content-between">
<span class="dark:text-slate-100">URI Encoder</span>
<div class="flex flex-wrap gap-2 justify-center">
<button class="tool-button" @click="clear()">Clear</button>
<EncodeUriButton @update:result="setTextFieldValue" :code="uri" operation="Encode" />
<EncodeUriButton @update:result="setTextFieldValue" :code="uri" operation="Decode" />
</div>
</div>
<CodeEditorComponent @update:updated-code="setTextFieldValue" :code="uri" :config="{disabled:false,language:'uri'}" />
</div>
</template>

View File

@@ -16,11 +16,11 @@ function updateVersion(newVersion: string) {
</script>
<template>
<div id="layout" class="flex flex-col lg:flex-row w-full h-full">
<div class="flex flex-col lg:flex-row w-full lg:w-7/12 grow overflow-hide px-2">
<div class="flex flex-col w-full lg:w-1/2 h-2/3 lg:h-full flex-none items-center">
<xmlInputFieldComponent stylized-name="XML" :data="xml" @update="(data) => {xml = data}"></xmlInputFieldComponent>
<xmlInputFieldComponent stylized-name="XPath" :data="query" @update="(data) => {query = data}"></xmlInputFieldComponent>
<div id="layout" class="flex flex-row w-full h-full">
<div class="flex flex-col 2xl:flex-row w-full xl:w-7/12 grow overflow-hide xl:pr-2">
<div class="flex flex-col w-full 2xl:w-1/2 h-2/3 2xl:h-full flex-none items-center">
<xmlInputFieldComponent stylized-name="XML" v-model="xml"></xmlInputFieldComponent>
<xmlInputFieldComponent stylized-name="XPath" v-model="query"></xmlInputFieldComponent>
</div>
<xmlOutputFieldComponent tool="xpath" :xml="xml" :query="query" @update="(version) => updateVersion(version)"></xmlOutputFieldComponent>
</div>

View File

@@ -10,10 +10,10 @@ const query = ref('');
</script>
<template>
<div id="layout" class="flex flex-col lg:flex-row w-full h-full">
<div class="flex flex-col w-full lg:w-1/2 h-2/3 lg:h-full flex-none items-center">
<xmlInputFieldComponent stylized-name="XML" @update="(data) => {xml = data}"></xmlInputFieldComponent>
<xmlInputFieldComponent stylized-name="XQuery" @update="(data) => {query = data}"></xmlInputFieldComponent>
<div id="layout" class="flex flex-col 2xl:flex-row w-full h-full">
<div class="flex flex-col w-full 2xl:w-1/2 h-2/3 2xl:h-full flex-none items-center">
<xmlInputFieldComponent stylized-name="XML" v-model="xml"></xmlInputFieldComponent>
<xmlInputFieldComponent stylized-name="XQuery" v-model="query"></xmlInputFieldComponent>
</div>
<xmlOutputFieldComponent tool="xquery" :xml="xml" :query="query"></xmlOutputFieldComponent>
</div>

View File

@@ -10,10 +10,10 @@ const query = ref('');
</script>
<template>
<div id="layout" class="flex flex-col lg:flex-row w-full h-full">
<div class="flex flex-col w-full lg:w-1/2 h-2/3 lg:h-full flex-none items-center">
<xmlInputFieldComponent stylized-name="XML" @update="(data) => {xml = data}"></xmlInputFieldComponent>
<xmlInputFieldComponent stylized-name="XSD" @update="(data) => {query = data}"></xmlInputFieldComponent>
<div id="layout" class="flex flex-col 2xl:flex-row w-full h-full">
<div class="flex flex-col w-full 2xl:w-1/2 h-2/3 2xl:h-full flex-none items-center">
<xmlInputFieldComponent stylized-name="XML" v-model="xml"></xmlInputFieldComponent>
<xmlInputFieldComponent stylized-name="XSD" v-model="query"></xmlInputFieldComponent>
</div>
<xmlOutputFieldComponent tool="xsd" :xml="xml" :query="query"></xmlOutputFieldComponent>
</div>

View File

@@ -1,27 +1,31 @@
<script setup lang="ts">
import xmlInputFieldComponent from '@/components/xml/XmlInputFieldComponent.vue';
import xmlTabbedInputComponent from '@/components/xml/XmlTabbedInputComponent.vue';
import xmlOutputFieldComponent from '@/components/xml/XmlOutputFieldComponent.vue';
import TooltipComponent from '@/components/xml/tooltips/TooltipComponent.vue';
import { type TabData } from '@/components/common/TabData';
import { ref } from 'vue';
const xml = ref('');
const xml = ref(new Array<TabData>);
const query = ref('');
const version = ref('');
function updateVersion(newVersion: string) {
version.value = newVersion;
}
</script>
<template>
<div id="layout" class="flex flex-col lg:flex-row w-full h-full">
<div class="flex flex-col lg:flex-row w-full lg:w-7/12 grow overflow-hide px-2">
<div class="flex flex-col w-full lg:w-1/2 h-2/3 lg:h-full flex-none items-center">
<xmlInputFieldComponent stylized-name="XML" @update="(data) => {xml = data}"></xmlInputFieldComponent>
<xmlInputFieldComponent stylized-name="XSLT" @update="(data) => {query = data}"></xmlInputFieldComponent>
</div>
<xmlOutputFieldComponent tool="xslt" :xml="xml" :query="query" @update="(version) => updateVersion(version)"></xmlOutputFieldComponent>
<div id="layout" class="flex flex-row w-full h-full">
<div class="flex flex-col 2xl:flex-row w-full xl:w-7/12 grow overflow-hide pr-2">
<div class="flex flex-col w-full 2xl:w-1/2 h-2/3 2xl:h-full flex-none items-center">
<xmlTabbedInputComponent stylized-name="XML" :tab-count-limit="3" v-model="xml"></xmlTabbedInputComponent>
<xmlInputFieldComponent stylized-name="XSLT" :data="query" v-model="query"></xmlInputFieldComponent>
</div>
<xmlOutputFieldComponent tool="xslt" :xml="xml" :query="query" @update="updateVersion"></xmlOutputFieldComponent>
</div>
<TooltipComponent tool-type="xslt" :version="version"></TooltipComponent>
</div>

View File

@@ -1,37 +1,8 @@
<script setup lang="ts">
import XMLButtonFormatterComponent from '@/components/formatter/XMLButtonFormatterComponent.vue';
import InsertTemplateComponent from '@components/common/InsertTemplateComponent.vue';
import CodeEditorComponent from '@/components/CodeEditorComponent.vue';
import { ref } from 'vue';
const xml = ref('');
function setTextFieldValue(data: string) {
xml.value = data
}
function format(formattedXml: any) {
xml.value = formattedXml.result;
}
function clear() {
xml.value = '';
}
import FormatterComponent from '@/components/formatter/FormatterComponent.vue';
</script>
<template>
<div id="layout" class="flex flex-col w-full h-full gap-4">
<div id="toolbar" class= "flex flex-col gap-4 items-center lg:flex-row place-content-between">
<span class="dark:text-slate-100">XML Formatter</span>
<div class="flex flex-wrap gap-2 justify-center">
<InsertTemplateComponent stylized-name="XML" @update:defaultData="(data: string) => setTextFieldValue(data)"></InsertTemplateComponent>
<button class="tool-button" @click="clear()">Clear</button>
<XMLButtonFormatterComponent is-minimizer :xml="xml" @update:result="(data: any) => format(data)"></XMLButtonFormatterComponent>
<XMLButtonFormatterComponent :xml="xml" @update:result="(data: any) => format(data)"></XMLButtonFormatterComponent>
</div>
</div>
<CodeEditorComponent @update:updated-code="setTextFieldValue" :code="xml" :config="{disabled:false,language:'xml'}" />
</div>
<FormatterComponent formatter-language="XML"></FormatterComponent>
</template>

View File

@@ -0,0 +1,20 @@
<script lang="ts">
import RestMockManComponent from '@man/RestMockManComponent.vue'
export default {
name:"RestMockManView",
components: {RestMockManComponent}
}
</script>
<template>
<div class="flex flex-col h-full gap-4">
<div class="flex flex-row">
<a href="/rest/mock" class="tool-button">Back to REST Mock</a>
</div>
<RestMockManComponent></RestMockManComponent>
</div>
</template>

View File

@@ -6,6 +6,11 @@ export default {
],
theme: {
extend: {},
fontFamily: {
'sans': ['Raleway'],
'mono': ["Sono"],
}
},
darkMode: 'class',
plugins: [],
}

View File

@@ -3,6 +3,11 @@
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"lib": [
"DOM",
"ES2022",
"ESNext"
],
"composite": true,
"baseUrl": ".",
"paths": {

View File

@@ -35,6 +35,7 @@ export default defineConfig({
'@components': fileURLToPath(new URL('./src/components', import.meta.url)),
'@views': fileURLToPath(new URL('./src/views', import.meta.url)),
'@assets': fileURLToPath(new URL('./src/assets', import.meta.url)),
'@man': fileURLToPath(new URL('./src/components/man', import.meta.url)),
}
}
})

View File

@@ -1,5 +1,6 @@
{
"data": "<b:books xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://www.demo.com' xmlns:b='http://www.book.com' xmlns:a='http://www.author.com'><b:book id='1'><b:name>Hamlet</b:name><b:date>2001-05-04</b:date><a:authorId>1</a:authorId><b:availability>false</b:availability></b:book><b:book id='2'><b:name>Macbeth</b:name><b:date>2000-12-13</b:date><a:authorId>1</a:authorId><b:availability>false</b:availability></b:book><b:book id='3'><b:name>Harry Potter and the Sorcerer's Stone</b:name><b:date>2005-04-29</b:date><a:authorId>2</a:authorId><b:availability>true</b:availability></b:book><b:book id='4'><b:name>The Long Walk</b:name><b:date>2018-07-01</b:date><a:authorId>4</a:authorId><b:availability>true</b:availability></b:book><b:book id='5'><b:name>Misery</b:name><b:date>2018-01-31</b:date><a:authorId>4</a:authorId><b:availability>true</b:availability></b:book><b:book id='6'><b:name>Think and Grow Rich</b:name><b:date>2004-09-10</b:date><a:authorId>6</a:authorId><b:availability>true</b:availability></b:book><b:book id='7'><b:name>The Law of Success</b:name><b:date>1982-05-09</b:date><a:authorId>6</a:authorId><b:availability>false</b:availability></b:book><b:book id='8'><b:name>Patriot Games</b:name><b:date>1995-10-21</b:date><a:authorId>5</a:authorId><b:availability>false</b:availability></b:book><b:book id='9'><b:name>The Sum of All Fears</b:name><b:date>1992-09-19</b:date><a:authorId>5</a:authorId><b:availability>false</b:availability></b:book><b:book id='10'><b:name>The Alchemist</b:name><b:date>2017-02-20</b:date><a:authorId>3</a:authorId><b:availability>false</b:availability></b:book><b:book id='11'><b:name>Hamlet</b:name><b:date>1994-06-01</b:date><a:authorId>1</a:authorId><b:availability>false</b:availability></b:book><b:book id='12'><b:name>Measure for Measure</b:name><b:date>1990-03-23</b:date><a:authorId>1</a:authorId><b:availability>false</b:availability></b:book><b:book id='13'><b:name>Hamlet</b:name><b:date>1989-05-05</b:date><a:authorId>1</a:authorId><b:availability>true</b:availability></b:book><b:book id='14'><b:name>Hamlet</b:name><b:date>1999-05-30</b:date><a:authorId>1</a:authorId><b:availability>true</b:availability></b:book><b:book id='15'><b:name>The Law of Success</b:name><b:date>2004-11-26</b:date><a:authorId>6</a:authorId><b:availability>true</b:availability></b:book><b:book id='16'><b:name>Romeo and Juliet</b:name><b:date>1997-02-08</b:date><a:authorId>1</a:authorId><b:availability>true</b:availability></b:book><b:book id='17'><b:name>The Alchemist</b:name><b:date>2009-08-21</b:date><a:authorId>3</a:authorId><b:availability>true</b:availability></b:book></b:books>",
"processorData": "N/A",
"processor": "libxml",
"version": "1.0"
}

View File

@@ -1,6 +1,6 @@
{
"data": "<b:books xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://www.demo.com' xmlns:b='http://www.book.com' xmlns:a='http://www.author.com'><b:book id='1'><b:name>Hamlet</b:name><b:date>2001-05-04</b:date><a:authorId>1</a:authorId><b:availability>false</b:availability></b:book><b:book id='2'><b:name>Macbeth</b:name><b:date>2000-12-13</b:date><a:authorId>1</a:authorId><b:availability>false</b:availability></b:book><b:book id='3'><b:name>Harry Potter and the Sorcerer's Stone</b:name><b:date>2005-04-29</b:date><a:authorId>2</a:authorId><b:availability>true</b:availability></b:book><b:book id='4'><b:name>The Long Walk</b:name><b:date>2018-07-01</b:date><a:authorId>4</a:authorId><b:availability>true</b:availability></b:book><b:book id='5'><b:name>Misery</b:name><b:date>2018-01-31</b:date><a:authorId>4</a:authorId><b:availability>true</b:availability></b:book><b:book id='6'><b:name>Think and Grow Rich</b:name><b:date>2004-09-10</b:date><a:authorId>6</a:authorId><b:availability>true</b:availability></b:book><b:book id='7'><b:name>The Law of Success</b:name><b:date>1982-05-09</b:date><a:authorId>6</a:authorId><b:availability>false</b:availability></b:book><b:book id='8'><b:name>Patriot Games</b:name><b:date>1995-10-21</b:date><a:authorId>5</a:authorId><b:availability>false</b:availability></b:book><b:book id='9'><b:name>The Sum of All Fears</b:name><b:date>1992-09-19</b:date><a:authorId>5</a:authorId><b:availability>false</b:availability></b:book><b:book id='10'><b:name>The Alchemist</b:name><b:date>2017-02-20</b:date><a:authorId>3</a:authorId><b:availability>false</b:availability></b:book><b:book id='11'><b:name>Hamlet</b:name><b:date>1994-06-01</b:date><a:authorId>1</a:authorId><b:availability>false</b:availability></b:book><b:book id='12'><b:name>Measure for Measure</b:name><b:date>1990-03-23</b:date><a:authorId>1</a:authorId><b:availability>false</b:availability></b:book><b:book id='13'><b:name>Hamlet</b:name><b:date>1989-05-05</b:date><a:authorId>1</a:authorId><b:availability>true</b:availability></b:book><b:book id='14'><b:name>Hamlet</b:name><b:date>1999-05-30</b:date><a:authorId>1</a:authorId><b:availability>true</b:availability></b:book><b:book id='15'><b:name>The Law of Success</b:name><b:date>2004-11-26</b:date><a:authorId>6</a:authorId><b:availability>true</b:availability></b:book><b:book id='16'><b:name>Romeo and Juliet</b:name><b:date>1997-02-08</b:date><a:authorId>1</a:authorId><b:availability>true</b:availability></b:book><b:book id='17'><b:name>The Alchemist</b:name><b:date>2009-08-21</b:date><a:authorId>3</a:authorId><b:availability>true</b:availability></b:book></b:books>",
"process": "whatever",
"processorData": "N/A",
"processor": "libxml",
"version": "1.0"
}

View File

@@ -1,6 +1,6 @@
{
"data": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<books><book id='1'><name>Hamlet</name><date>2001-05-04</date><authorId>1</authorId><availability>false</availability></book><book id='2'><name>Macbeth</name><date>2000-12-13</date><authorId>1</authorId><availability>false</availability></book><book id='3'><name>Harry Potter and the Sorcerer's Stone</name><date>2005-04-29</date><authorId>2</authorId><availability>true</availability></book><book id='4'><name>The Long Walk</name><date>2018-07-01</date><authorId>4</authorId><availability>true</availability></book><book id='5'><name>Misery</name><date>2018-01-31</date><authorId>4</authorId><availability>true</availability></book><book id='6'><name>Think and Grow Rich</name><date>2004-09-10</date><authorId>6</authorId><availability>true</availability></book><book id='7'><name>The Law of Success</name><date>1982-05-09</date><authorId>6</authorId><availability>false</availability></book><book id='8'><name>Patriot Games</name><date>1995-10-21</date><authorId>5</authorId><availability>false</availability></book><book id='9'><name>The Sum of All Fears</name><date>1992-09-19</date><authorId>5</authorId><availability>false</availability></book><book id='10'><name>The Alchemist</name><date>2017-02-20</date><authorId>3</authorId><availability>false</availability></book><book id='11'><name>Hamlet</name><date>1994-06-01</date><authorId>1</authorId><availability>false</availability></book><book id='12'><name>Measure for Measure</name><date>1990-03-23</date><authorId>1</authorId><availability>false</availability></book><book id='13'><name>Hamlet</name><date>1989-05-05</date><authorId>1</authorId><availability>true</availability></book><book id='14'><name>Hamlet</name><date>1999-05-30</date><authorId>1</authorId><availability>true</availability></book><book id='15'><name>The Law of Success</name><date>2004-11-26</date><authorId>6</authorId><availability>true</availability></book><book id='16'><name>Romeo and Juliet</name><date>1997-02-08</date><authorId>1</authorId><availability>true</availability></book><book id='17'><name>The Alchemist</name><date>2009-08-21</date><authorId>3</authorId><availability>true</availability></book></books>",
"process": "/books/book[name = 'The Law of Success']",
"processorData": "/books/book[name = 'The Law of Success']",
"processor": "saxon",
"version": "2.0"
}

View File

@@ -1,6 +1,6 @@
{
"data": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<b:books xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns='http://www.demo.com' xmlns:b='http://www.book.com' xmlns:a='http://www.author.com'><b:book id='1'><b:name>Hamlet</b:name><b:date>2001-05-04</b:date><a:authorId>1</a:authorId><b:availability>false</b:availability></b:book><b:book id='2'><b:name>Macbeth</b:name><b:date>2000-12-13</b:date><a:authorId>1</a:authorId><b:availability>false</b:availability></b:book><b:book id='3'><b:name>Harry Potter and the Sorcerer's Stone</b:name><b:date>2005-04-29</b:date><a:authorId>2</a:authorId><b:availability>true</b:availability></b:book><b:book id='4'><b:name>The Long Walk</b:name><b:date>2018-07-01</b:date><a:authorId>4</a:authorId><b:availability>true</b:availability></b:book><b:book id='5'><b:name>Misery</b:name><b:date>2018-01-31</b:date><a:authorId>4</a:authorId><b:availability>true</b:availability></b:book><b:book id='6'><b:name>Think and Grow Rich</b:name><b:date>2004-09-10</b:date><a:authorId>6</a:authorId><b:availability>true</b:availability></b:book><b:book id='7'><b:name>The Law of Success</b:name><b:date>1982-05-09</b:date><a:authorId>6</a:authorId><b:availability>false</b:availability></b:book><b:book id='8'><b:name>Patriot Games</b:name><b:date>1995-10-21</b:date><a:authorId>5</a:authorId><b:availability>false</b:availability></b:book><b:book id='9'><b:name>The Sum of All Fears</b:name><b:date>1992-09-19</b:date><a:authorId>5</a:authorId><b:availability>false</b:availability></b:book><b:book id='10'><b:name>The Alchemist</b:name><b:date>2017-02-20</b:date><a:authorId>3</a:authorId><b:availability>false</b:availability></b:book><b:book id='11'><b:name>Hamlet</b:name><b:date>1994-06-01</b:date><a:authorId>1</a:authorId><b:availability>false</b:availability></b:book><b:book id='12'><b:name>Measure for Measure</b:name><b:date>1990-03-23</b:date><a:authorId>1</a:authorId><b:availability>false</b:availability></b:book><b:book id='13'><b:name>Hamlet</b:name><b:date>1989-05-05</b:date><a:authorId>1</a:authorId><b:availability>true</b:availability></b:book><b:book id='14'><b:name>Hamlet</b:name><b:date>1999-05-30</b:date><a:authorId>1</a:authorId><b:availability>true</b:availability></b:book><b:book id='15'><b:name>The Law of Success</b:name><b:date>2004-11-26</b:date><a:authorId>6</a:authorId><b:availability>true</b:availability></b:book><b:book id='16'><b:name>Romeo and Juliet</b:name><b:date>1997-02-08</b:date><a:authorId>1</a:authorId><b:availability>true</b:availability></b:book><b:book id='17'><b:name>The Alchemist</b:name><b:date>2009-08-21</b:date><a:authorId>3</a:authorId><b:availability>true</b:availability></b:book></b:books>",
"process": "/b:books/b:book[b:name = 'The Law of Success']",
"processorData": "/b:books/b:book[b:name = 'The Law of Success']",
"processor": "saxon",
"version": "2.0"
}

View File

@@ -1,6 +1,10 @@
{
"data": "<people><person><name>John</name><age>67</age></person><person><name>Anna</name><age>69</age></person></people>",
<<<<<<< HEAD
"process": "for $x in //person return string($x/name)",
=======
"processorData": "for $x in //person return string($x/name)",
>>>>>>> 307e732608fca31b60027b417412691ff0e1c2f0
"processor": "saxon",
"version": "3.1"
}

View File

@@ -1,6 +1,6 @@
{
"data": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ns0:values xmlns:ns0 = \"http://www.tibco.com/schemas/test/Test/Resources/Schema.xsd\"><ns0:value>Test</ns0:value><ns0:value>Test3</ns0:value></ns0:values>",
"process": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns=\"http://www.tibco.com/schemas/test/Test/Resources/Schema.xsd\" targetNamespace=\"http://www.tibco.com/schemas/test/Test/Resources/Schema.xsd\" elementFormDefault=\"qualified\" attributeFormDefault=\"unqualified\"> <xs:element name=\"values\"><xs:complexType><xs:sequence><xs:element name=\"value\" type=\"xs:string\" minOccurs=\"0\" maxOccurs=\"unbounded\"/></xs:sequence></xs:complexType></xs:element></xs:schema>",
"processorData": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns=\"http://www.tibco.com/schemas/test/Test/Resources/Schema.xsd\" targetNamespace=\"http://www.tibco.com/schemas/test/Test/Resources/Schema.xsd\" elementFormDefault=\"qualified\" attributeFormDefault=\"unqualified\"> <xs:element name=\"values\"><xs:complexType><xs:sequence><xs:element name=\"value\" type=\"xs:string\" minOccurs=\"0\" maxOccurs=\"unbounded\"/></xs:sequence></xs:complexType></xs:element></xs:schema>",
"processor": "saxon",
"version": "1.0"
}

View File

@@ -1,6 +1,6 @@
{
"data": "<?xml version=\"1.0\" encoding=\"utf-8\"?><l:library xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.release11.com\" xmlns:l=\"http://www.release11.com/library\" xmlns:p=\"http://www.release11.com/person\" xmlns:b=\"http://www.release11.com/book\"><l:libraryName>City library</l:libraryName><l:libraryID>345123</l:libraryID><l:readerList><p:person><p:readerID>7321</p:readerID><p:name>Adam</p:name><p:surname>Choke</p:surname></p:person><p:person><p:readerID>5123</p:readerID><p:name>Lauren</p:name><p:surname>Wong</p:surname></p:person></l:readerList><l:bookList><b:book><b:bookID>6422</b:bookID><b:title>Harry Potter</b:title><p:readerID>7542</p:readerID></b:book><b:book><b:bookID>1234</b:bookID><b:title>Macbeth</b:title><p:readerID>5123</p:readerID></b:book><b:book><b:bookID>9556</b:bookID><b:title>Romeo and Juliet</b:title></b:book></l:bookList></l:library>",
"process": "<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:b=\"http://www.demo.com\" xmlns:p=\"http://www.release11.com/person\" xmlns:l=\"http://www.release11.com/library\" version=\"1.0\"><xsl:template match=\"/\"><Library><ReaderCount><xsl:value-of select=\"count(//p:person)\"/></ReaderCount><BookCount><xsl:value-of select=\"count(/l:library/l:bookList/b:book)\"/></BookCount></Library></xsl:template></xsl:stylesheet>",
"processorData": "<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:b=\"http://www.demo.com\" xmlns:p=\"http://www.release11.com/person\" xmlns:l=\"http://www.release11.com/library\" version=\"1.0\"><xsl:template match=\"/\"><Library><ReaderCount><xsl:value-of select=\"count(//p:person)\"/></ReaderCount><BookCount><xsl:value-of select=\"count(/l:library/l:bookList/b:book)\"/></BookCount></Library></xsl:template></xsl:stylesheet>",
"processor": "saxon",
"version": "1.0"
}

View File

@@ -895,7 +895,7 @@
"example": "<values><value>2</value><value>8</value></values>",
"description": "The XML data to be processed"
},
"process": {
"processorData": {
"type": "string",
"example": "count(//value)",
"description": "XPath tranform to be executed"
@@ -925,7 +925,7 @@
"example": "<values><value>2</value><value>8</value></values>",
"description": "The XML data to be processed"
},
"process": {
"processorData": {
"type": "string",
"example": "count(//value)",
"description": "XSLT tranform to be executed"
@@ -955,7 +955,7 @@
"example": "<values><value>2</value><value>8</value></values>",
"description": "The XML data to be processed"
},
"process": {
"processorData": {
"type": "string",
"example": "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns=\"http://www.tibco.com/schemas/test/Test/Resources/Schema.xsd\" targetNamespace=\"http://www.tibco.com/schemas/test/Test/Resources/Schema.xsd\" elementFormDefault=\"qualified\" attributeFormDefault=\"unqualified\"> <xs:element name=\"values\"><xs:complexType><xs:sequence><xs:element name=\"value\" type=\"xs:string\" minOccurs=\"0\" maxOccurs=\"unbounded\"/></xs:sequence></xs:complexType></xs:element></xs:schema>",
"description": "XSD to perform verification with"
@@ -1130,7 +1130,7 @@
"example": "<values><value>2</value><value>8</value></values>",
"description": "The XML data to be prettified"
},
"process": {
"processorData": {
"type": "string",
"example": "",
"description": "Unused here, required only to use same json for whole project"
@@ -1157,7 +1157,7 @@
"example": "<values><value>2</value><value>8</value></values>",
"description": "The XML data to be minimized"
},
"process": {
"processorData": {
"type": "string",
"example": "",
"description": "Unused here, required only to use same json for whole project"

File diff suppressed because it is too large Load Diff