Merge pull request 'dev' (#26) from dev into master

Reviewed-on: R11/release11-tools-web#26
This commit is contained in:
2023-02-13 11:04:15 +01:00
30 changed files with 346 additions and 678 deletions

3
Backend-libXML/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.idea
__pycache**
venv

View File

@@ -0,0 +1,8 @@
FROM tiangolo/meinheld-gunicorn-flask:python3.9
COPY ./requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt
COPY ./main.py /app/
COPY ./Parser.py /app/

69
Backend-libXML/Parser.py Normal file
View File

@@ -0,0 +1,69 @@
from lxml import etree
def xpath(source: str, xpath: str) -> str:
"""
Method used to get nodes from XML string using XPath
:param source: XML string used for selection
:type source: str
:param xpath: XPath query used for selection
:type xpath: str
:return: Nodes selected using XPath
:rtype: str
"""
root = etree.XML(source)
nsmap = root.nsmap
# LXML doesn't accept empty (None) namespace prefix,
# so it need to be deleted if exists
if None in nsmap:
nsmap.pop(None)
result = root.xpath(xpath, namespaces=nsmap)
result_string = ""
for e in result:
result_string += etree.tostring(e, pretty_print=True).decode() + "\n"
return result_string
def xsd(source: str, xsd: str) -> bool:
"""
Method used to validate XML string against XSD schema
:param source: XML string used for validation
:type source: str
:param xsd: XSD schema to validate XML against
:type xsd: str
:return: Message saying, if the validation was successful or not
:rtype: str
"""
xml_schema = etree.XMLSchema(etree.XML(xsd))
xml = etree.XML(source)
if xml_schema.validate(xml):
return "XML is valid."
else:
return "XML is NOT valid."
def xslt(source: str, xslt: str) -> str:
"""
Method used to transformate XML string using XSLT
:param source: XML string to transform
:type source: str
:param xslt: XSLT string used to transformate XML
:type xslt: str
:return: Result of transformation
:rtype: str
"""
xslt_transform = etree.XSLT(etree.XML(xslt))
xml = etree.XML(source)
transformated = xslt_transform(xml)
print(transformated)
return str(transformated)

74
Backend-libXML/main.py Normal file
View File

@@ -0,0 +1,74 @@
from flask import Flask
from flask_cors import CORS
from flask import request
from lxml import etree
import json
import time
import Parser
app = Flask(__name__)
CORS(app)
cors = CORS(app, resource={
r"/*":{
"origins":"*"
}
})
def process_xml(request: request, type: str) -> str:
"""Function to process
:param request: Received request
:type request: request
:param type: Type of needed processing: xsd, xslt or xpath
:type type: str
:raises ValueError: is raised when type is different than those provided above
:return: response JSON converted to string and response code
:rtype: str, int
"""
start = time.time_ns()
code = 200
response_json = dict()
try:
request_data = json.loads(request.get_data(as_text=True))
data = request_data['data']
process = request_data['process']
if (type == "xsd"):
response_json['result'] = Parser.xsd(data, process)
elif (type == "xslt"):
response_json['result'] = Parser.xslt(data, process)
elif (type == "xpath"):
response_json['result'] = Parser.xpath(data, process)
else:
raise ValueError("Valid operation types are: xsd, xslt, xpath")
response_json['status'] = "OK"
except KeyError as e:
response_json['result'] = "Missing key: " + str(e)
response_json['status'] = "ERR"
code = 400
except Exception as e:
response_json['result'] = str(e)
response_json['status'] = "ERR"
code = 400
finally:
exec_time = (time.time_ns() - start) / 10**6
response_json['time'] = f"{exec_time:.03f}"
response_json['processor'] = "libxml2 over lxml"
return json.dumps(response_json), code
@app.route("/xpathpost", methods=["POST"])
def xpath():
return process_xml(request, "xpath")
@app.route("/xsdpost", methods=["POST"])
def xsd():
return process_xml(request, "xsd")
@app.route("/xsltpost", methods=["POST"])
def xslt():
return process_xml(request, "xslt")
if __name__ == "__main__":
app.run()

View File

@@ -0,0 +1,3 @@
lxml
flask
flask_cors

View File

@@ -0,0 +1,6 @@
{
"data": "<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']",
"processor": "saxon",
"version": "2.0"
}

View File

@@ -0,0 +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": "/b:books/b:book[b:name = 'The Law of Success']",
"processor": "saxon",
"version": "2.0"
}

View File

@@ -0,0 +1,4 @@
#url = "localhost:8081/xpathpost"
url = "localhost:5000/xpath"
request = "POST"
data = "@data.json"

View File

@@ -0,0 +1,4 @@
#url = "localhost:8081/xpathpost"
url = "localhost:5000/xpath"
request = "POST"
data = "@dataNS.json"

View File

@@ -0,0 +1,4 @@
#url = "http://localhost:8082/xsd"
url = "http://localhost:5000/xsd"
data = "@xsd.json"
request = POST

View File

@@ -0,0 +1,6 @@
{
"data": "<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": "<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

@@ -0,0 +1,3 @@
url = "http://localhost:5000/xslt"
data = "@xslt.json"
request = POST

View File

@@ -0,0 +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": "<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:b='http://www.demo.com'><xsl:template match='b:books'><Library><BookCount><xsl:value-of select='count(b:book)' /></BookCount></Library></xsl:template></xsl:stylesheet>",
"processor": "saxon",
"version": "1.0"
}

View File

@@ -3,12 +3,12 @@
<head>
<title>R11 MockedServices</title>
<meta charset="utf-8">
<link rel="stylesheet" href="http://localhost:8086/assets/css/common/fontello.css" type="text/css">
<link rel="stylesheet" href="http://localhost:8086/assets/css/mock-service/main.css" type="text/css">
<link rel="stylesheet" href="../css/fontello.css" type="text/css">
<link rel="stylesheet" href="../css/main.css" type="text/css">
<!-- <link rel="stylesheet" href="css/common.css" type="text/css"> -->
<link rel="stylesheet" href="http://localhost:8086/assets/css/mock-service/common.css" type="text/css">
<link rel="stylesheet" href="../css/common.css" type="text/css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="../js/dyn_host.js"></script>
<!-- <script src="../js/dyn_host.js"></script> -->
</head>
<body>
<div class="container">
@@ -37,15 +37,15 @@
<!-- status -->
<div class="max-width small-vertical-margin">
<label for="httpStatus">Http Status</label>
<input id="httpStatus" class="bordered-field max-width data-field" type="text" value="200" list="httpStatusSuggestion">
<datalist id="httpStatusSuggestion">
<option value="200">
<option value="300">
<option value="400">
<option value="403">
<option value="404">
<option value="500">
</datalist>
<!-- <input id="httpStatus" class="bordered-field max-width data-field" type="text" value="200" list="httpStatusSuggestion"> -->
<select id="httpStatus" class="bordered-field max-width data-field" value="200">
<option value="200">200</option>
<option value="300">300</option>
<option value="400">400</option>
<option value="403">403</option>
<option value="404">404</option>
<option value="500">500</option>
</select>
</div>
<!-- content type -->
<div class="max-width small-vertical-margin">

View File

@@ -1,11 +0,0 @@
$(document).ready( function() {
console.log("Here")
let links = document.getElementsByTagName("link")
for (let i = 0; i < links.length; i++) {
let oldStr = links[i].href.split("/")
let endpoint = oldStr.slice(3).join("/")
links[i].href = window.location.protocol + "//" + window.location.hostname + ":8086/" + endpoint
}
});

View File

@@ -1,5 +1,6 @@
package com.r11.tools.xslt;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.r11.tools.xslt.processors.Saxon;
@@ -65,8 +66,15 @@ public class SparkInitializer {
Map<String, String> responseMap = new HashMap<>();
try {
requestMap = mapper.readValue(body, Map.class);
} catch (JsonMappingException ex) {
ex.printStackTrace();
} catch (JsonMappingException | JsonParseException ex) {
LOG.error("Request JSON error. " + ex);
responseMap.put("result", ex.getMessage());
responseMap.put("processor", "N/A");
responseMap.put("status", "ERR");
responseMap.put("time", "N/A");
resp.status(400);
resp.body(mapper.writeValueAsString(responseMap));
return resp;
}
String data = requestMap.get("data");
@@ -103,8 +111,15 @@ public class SparkInitializer {
Map<String, String> responseMap = new HashMap<>();
try {
requestMap = mapper.readValue(body, Map.class);
} catch (JsonMappingException ex) {
LOG.error("JSON mapping error. " + ex);
} catch (JsonMappingException | JsonParseException ex) {
LOG.error("Request JSON error. " + ex);
responseMap.put("result", ex.getMessage());
responseMap.put("processor", "N/A");
responseMap.put("status", "ERR");
responseMap.put("time", "N/A");
resp.status(400);
resp.body(mapper.writeValueAsString(responseMap));
return resp;
}
String data = requestMap.get("data");
@@ -158,7 +173,6 @@ public class SparkInitializer {
duration = System.currentTimeMillis() - timeStart;
LOG.info("Request: " + body + " processed in " + duration + " ms.");
responseMap.put("processor", Xalan.getVersion());
responseMap.put("result", tmp);
responseMap.put("time", Long.toString(duration));
resp.body(mapper.writeValueAsString(responseMap));
return resp;
@@ -174,17 +188,24 @@ public class SparkInitializer {
private static final Route xsltHandler = (Request req, Response resp) -> {
String body = req.body();
ObjectMapper mapper = new ObjectMapper();
Map<String, String> jsonMap = new HashMap<>();
Map<String, String> requestMap = new HashMap<>();
Map<String, String> responseMap = new HashMap<>();
try {
jsonMap = mapper.readValue(body, Map.class);
} catch (JsonMappingException ex) {
LOG.error("JSON mapping error. " + ex);
requestMap = mapper.readValue(body, Map.class);
} catch (JsonMappingException | JsonParseException ex) {
LOG.error("Request JSON error. " + ex);
responseMap.put("result", ex.getMessage());
responseMap.put("processor", "N/A");
responseMap.put("status", "ERR");
responseMap.put("time", "N/A");
resp.status(400);
resp.body(mapper.writeValueAsString(responseMap));
return resp;
}
String data = jsonMap.get("data");
String query = jsonMap.get("process");
String processor = jsonMap.get("processor");
String version = jsonMap.get("version");
String data = requestMap.get("data");
String query = requestMap.get("process");
String processor = requestMap.get("processor");
String version = requestMap.get("version");
if (processor == null) {
return "saxon, xalan";

View File

@@ -1,8 +1,12 @@
package com.r11.tools.xslt.processors;
import net.sf.saxon.lib.RawResult;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.xpath.XPathAPI;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.NodeIterator;
import org.xml.sax.InputSource;
import javax.xml.XMLConstants;
@@ -19,8 +23,7 @@ import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.*;
/**
* Handler for Xalan engine
@@ -53,25 +56,55 @@ public class Xalan {
return sw.toString();
}
private static boolean isTextNode(Node n) {
if (n == null)
return false;
short nodeType = n.getNodeType();
return nodeType == Node.CDATA_SECTION_NODE || nodeType == Node.TEXT_NODE;
}
/**
* Process xpath and return either node or wrapped atomic value
* @deprecated
* Xalan needs assumption of the outcome, which is not implemented. Therefore method is deprecated
* @param data xml
* @param transform xpath
* @return xml processed using given xpath
* @throws Exception thrown on node building errors or invalid xpath
*/
public static String processXPath(String data, String transform) throws Exception{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
public static String processXPath(String data, String transform) throws Exception {
XPath xpath = XPathFactory.newInstance().newXPath();
// Set up a DOM tree to query.
InputSource in = new InputSource(new StringReader(data));
DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
dfactory.setNamespaceAware(true);
Document doc = dfactory.newDocumentBuilder().parse(in);
xpath.setNamespaceContext(new XalanNamespaceResolver(builder.parse(new InputSource(new StringReader(data))), true));
XPathExpression exp = xpath.compile(transform);
exp.evaluate(new InputSource(new StringReader(data)), XPathConstants.NODESET);
return exp.evaluate(new InputSource(new StringReader(data)));
// Set up an identity transformer to use as serializer.
Transformer serializer = TransformerFactory.newInstance().newTransformer();
serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
// Use the simple XPath API to select a nodeIterator.
NodeIterator nl = XPathAPI.selectNodeIterator(doc, transform);
// Serialize the found nodes to result object.
StringBuilder result = new StringBuilder();
Node n;
while ((n = nl.nextNode())!= null) {
StringBuilder sb;
if (isTextNode(n)) {
// DOM may have more than one node corresponding to a
// single XPath text node. Coalesce all contiguous text nodes
// at this level
for (Node nn = n.getNextSibling(); isTextNode(nn); nn = nn.getNextSibling()) {
result.append(nn.getNodeValue());
}
} else {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
serializer.transform(new DOMSource(n), new StreamResult(new OutputStreamWriter(outputStream)));
result.append(outputStream);
}
result.append("\n");
}
return result.toString();
}
/**

View File

@@ -1,6 +0,0 @@
@import url('https://necolas.github.io/normalize.css/8.0.1/normalize.css');
@import url('r11addons.css');
@import url('r11tables.css');
@import url('r11tool.css');
@import url('r11tooltip.css');
@import url('r11modal.css');

View File

@@ -1,4 +0,0 @@
.overflowedTableContent {
max-height: 750px;
overflow: scroll;
}

View File

@@ -1,59 +0,0 @@
.modification-button.btn-tile:hover {
color: #ca1111;
}
.modification-button.btn-tile {
width: 10%;
margin: 20% 0 0 0;
font-size: 14px;
color: #00000020
}
.modification-button.btn-addtile {
font-size: 38px;
color: #00000030;
}
.modification-button.btn-addtile:hover {
color: #58ac43;
}
.tile {
width: 100%;
padding-top: 40%;
border: 1px solid gray;
border-radius: 3px;
position: relative;
background: #f0f0f095;
margin-bottom: 10px;
cursor: default;
}
.tile:hover {
filter: brightness(110%);
}
.tile.active {
background: #00000070;
color: white;
filter: none;
}
.tile.active .btn-tile {
opacity: 0;
}
.tile .content {
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
padding: 0 2% 0 7%;
display: flex;
}
.content p {
margin: 0;
padding: 0;
}

View File

@@ -1,104 +0,0 @@
#overlay {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
opacity: 0;
background: rgba(0, 0 , 0, 0.5);
pointer-events: none;
}
#overlay.active {
pointer-events: all;
opacity: 1;
}
.modal {
display: none;
width: 390px;
min-height: 71px;
max-height: 700px;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 5px;
border: 1px solid #f0f0f0;
}
.modal.active {
display: block;
}
.modal div.header {
width: 384px;
height: 24px;
background: #2e3133;
color: white;
font-size: 24px;
font-weight: 700;
padding: 3px;
margin-bottom: 5px;
display: flex;
justify-content: space-between;
align-items: center;
}
.modal div.header button {
font-size: 100%;
font-family: inherit;
border: 0;
padding: 0;
background: 0;
color: inherit;
cursor: pointer;
}
.modal div.header button:hover {
color: white;
font-weight: 700;
}
.modal div.body {
width: 370px;
padding: 10px;
background: #f0f0f0;
color: #2e3133;
min-height: 16px;
text-align: justify;
font-size: 16px;
}
.modal div.function {
width: 385px;
min-height: 30px;
padding-top: 5px;
display: flex;
justify-content: space-evenly;
background: inherit;
}
.modal div.function button {
min-height: 22px;
min-width: 34px;
max-width: 74px;
padding: 3px 20px;
outline: none;
border: 1px solid #f0f0f0;
background: rgba(205,205,205,1);
font-size: 16px;
text-align: center;
cursor: pointer;
}
.modal div.function button:hover {
filter: brightness(110%);
}
.r-exclamation:before {
content: '!';
color: #3bc4f1;
font-style: normal;
}

View File

@@ -1,71 +0,0 @@
.table-map {
width: 60%;
}
.table-map input{
font-size: 16px;
padding: 7px;
border: 1px solid rgba(145, 146, 146, 0.849);
border-radius: 5px;
}
.table-map input.key {
background: #f0f0f0;
}
.modification-button.btn-add {
font-size: 16px;
color: #00000030;
margin: auto 0 auto 0;
}
.modification-button.btn-add:hover {
color:#58ac43;
}
.modification-button.btn-hashmap {
font-size: 16px;
color: #00000030;
margin: auto 0 auto 0;
}
.modification-button.btn-hashmap:hover {
color: #ca1111;
}
.table-default {
width: 80%;
border-collapse: collapse;
border-spacing: 0;
}
.table-default tr {
background: #f0f0f02d;
}
.table-default tr.bottom-border {
border-bottom: 1px solid black;
}
.table-default th {
background: #ffffff;
}
.table-default tr.even {
background: #f0f0f0;
}
.table-doc td, .table-doc th{
border-spacing: 0px;
padding: 0px 10px;
}
.table-doc td {
background-color: rgba(155, 165, 160, 0.342);
}
.table-doc th {
background-color: #3bc4f1;
text-align: left;
color: white;
}

View File

@@ -1,300 +0,0 @@
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;700&display=swap');
.hyperlink, .hyperlink:visited, .hyperlink:active {
color: rgb(47, 125, 146);
cursor: pointer;
}
.hyperlink:hover {
filter: brightness(120%);
}
.bordered-field {
border: 2px solid rgba(93, 99, 96, 0.705);
border-radius: 5px;
padding: 8px;
}
.bordered-field:focus {
outline: none;
box-shadow: 0 0 5px rgba(81, 203, 238);
border: 2px solid #00000070;
}
.bordered-field:disabled {
background: #eeeeeed2;
}
.vertically-resizeable {
resize: vertical;
}
body {
font-family: 'Nunito', sans-serif;
}
.container {
display: flex;
justify-content: left;
width: 100%;
}
.tool {
width: 55%;
display: flex;
justify-content: space-evenly;
}
.tool.extended {
width: 65%;
}
.tool .tool-context {
width: 90%;
}
.tool.extended .tool-context {
width: 75%;
}
.tool.extended .tool-extention {
width: 20%;
padding-top: 2%;
display: block;
}
.tool .tool-extention {
display: none;
}
.tool-extention {
opacity: 0;
pointer-events: none;
}
.tool-extention.active {
opacity: 100%;
pointer-events: all;
}
.clickable-text {
padding: 0;
outline: none;
background: none;
border: none;
font-weight: 300;
cursor: pointer;
}
.clickable-text.highlight:hover {
color: #3bc4f1;
}
.clickable-text.switch {
font-size: 18px;
font-weight: 700;
}
.clickable-text.switch span.toggleIndicator:before {
content: '>';
}
.clickable-text.switch span.toggleIndicator.active:before {
content: 'v';
}
.modification-button {
padding: 0;
outline: none;
background: none;
border: none;
font-weight: 300;
}
.text-aligned-to-right {
text-align: right;
}
.centered-vertically {
margin-top: auto;
margin-bottom: auto;
}
.display-space-between {
width: 100%;
display: flex;
justify-content: space-between;
}
.display-space-evenly {
display: flex;
justify-content: space-evenly;
}
.float-left {
display: flex;
justify-content: left;
width: 100%;
}
.version-span {
font-size: 13px;
font-weight: 400;
color: rgba(85,85,85,0.555);
}
.block-display {
display: block;
}
.block-label {
display: block;
margin: 0 0 0 5px;
}
.tabmenu {
display: flex;
flex-direction: row;
text-align: center;
border-bottom: 1px solid rgba(185, 185, 185, 0.5);
}
.tabitem {
flex-grow: 1;
cursor: pointer;
padding: 5px 0;
}
.tabitem:hover {
font-weight: 700;
}
.tabitem.active {
background: rgba(33, 34, 34, 0.705);
color: white;
font-weight: 700;
cursor:default;
flex-grow: 1;
}
.big-font {
font-size: 20px;
}
.action-button.active {
background: #3bc4f1;
border: 1px solid #7ed0eb;
cursor: pointer;
}
.action-button.active:hover {
filter: brightness(110%);
}
.action-button {
background: rgba(155, 165, 160, 0.507);
border:1px solid rgba(186, 197, 191, 0.507);
color: white;
padding: 10px 20px;
font-weight: 700;
margin: 3px 0;
}
.quater-width {
width: 25%;
}
.half-width {
width: 50%;
}
.tree-fourth-width {
width: 75%;
}
.half-width.with-padding {
width: 45%;
}
.max-width {
width: 100%;
}
.max-width.with-padding {
width: 94%;
}
.max-height {
height: 100%;
}
.height-300 {
height: 300px;
}
.max-height.with-padding {
height: 90%;
}
.small-margins {
margin: 3%;
}
.small-vertical-margin {
margin-top: 10px;
margin-bottom: 10px;
}
.medium-vertical-margin {
margin-top: 30px;
margin-bottom: 30px;
}
.large-vertical-margin {
margin-top: 50px;
margin-bottom: 50px;
}
.textarea-300 {
height: 300px;
}
.centered-content {
display: flex;
justify-content: center;
}
.tabcontent {
display: none;
}
.tabcontent.active {
display: flex;
justify-content: center;
}
.hiddable {
display: none;
}
.hiddable.active {
display: inherit;
}
/* In case of collision with classes that use 'active' */
.hidden {
display: none;
}
/* TODO: Add proper class */
/* textarea {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
} */
/* TODO: Add proper class */
/* code{
line-height: 150%;
} */

View File

@@ -1,77 +0,0 @@
.tooltip-window {
position: fixed;
right: 0;
filter: drop-shadow(-2px 0px 2px darkgray);
background: #e8f3f7;
padding: 15px 30px;
font-family: 'Nunito', sans-serif;
width: 40%;
height: 100%;
overflow: scroll;
}
.tooltip-window.lite {
width: 30%;
}
.tip {
display: none;
}
.tip.active {
display: block;
}
/* TODO: Remove !important. It's bad practice and it can cause errors in future */
.section-button {
width: 100%;
padding: 15px 0;
font-size: 18px;
background: #b4b4b4c5;
cursor: pointer;
border-bottom: darkgray 2px solid !important;
}
.section-button:hover {
backdrop-filter: brightness(110%);
}
.section-button .active {
background: #00000030;
}
.List .collapsibleContent {
border-left: #bdc5c9 2px solid;
overflow: hidden;
background: #ffffff50;
}
/* TODO: .section class is to generic. It should be renamed */
.section{
padding: 10px 0px 20px 0px ;
}
/* TODO: content subclass already in use. Creating content class overrides the subclass.
Make .content a subclass of .content */
/* .content {
padding: 0px 15px 0px 15px ;
text-align: justify;
overflow: hidden;
transition: max-height .2s ease-out;
max-height: 0px;
border-left: #c0c2c3 2px solid;
} */
.collapsibleMini::before{
content: "►";
}
.collapsibleMini.active::before{
content: "▼";
}
/* TODO: Add proper class */
/* button:hover{
filter: brightness(110%);
} */

View File

@@ -105,8 +105,11 @@ function performRequest(text, checkXML, checkTransform){
//Form REST request, send, receive and display in resultArea
async function restRequest(text) {
const escapeChar = "specialEscapeChar";
// const addr = "http://localhost:8081/" + text;
const addr = window.location.protocol + "//" + window.location.hostname + ":8081/" + text;
var port = ":8081/"
if (getProcessor() == "libxml") {
port = ":8082/"
}
const addr = window.location.protocol + "//" + window.location.hostname + port + text;
var xmlData = document.getElementById("xmlArea").value.trim();
var transformData = document.getElementById("transformArea").value.trim();

View File

@@ -24,13 +24,15 @@
<label for="processors">Select XPath processor:</label>
<select name="processors" id="processors">
<option value="saxon">Saxon</option>
<!-- <option value="xalan">Xalan</option> -->
<option value="xalan">Xalan</option>
<option value="libxml">libXML</option>
</select>
<label for="versions">XPath version:</label>
<select name="versions" id="versions">
<option value="2.0">1.0/2.0</option>
<option value="3.0">3.0</option>
<option value="3.1">3.1</option>
<option class="hideable libxml xalan"value="1.0">1.0</option>
<option class="hideable saxon" value="2.0">2.0</option>
<option class="hideable saxon" value="3.0">3.0</option>
<option class="hideable saxon" value="3.1">3.1</option>
</select>
</div>
<button class="action-button active" id="defaultXMLButton" style="padding: 3px 10px;"
@@ -3066,6 +3068,31 @@
<script>
function processVersionSelector() {
var processor = getProcessor();
var hideableOptions = document.getElementsByClassName("hideable");
for (let i = 0; i < hideableOptions.length; i++) {
hideableOptions[i].style = "display: none;";
}
if (processor == "xalan" || processor == "libxml") {
var xalanOptions = document.getElementsByClassName("xalan");
for (let i = 0; i < xalanOptions.length; i++) {
xalanOptions[i].style = "";
}
document.getElementById("versions").selectedIndex = 0;
}
else {
var saxonOptions = document.getElementsByClassName("saxon");
for (let i = 0; i < saxonOptions.length; i++) {
saxonOptions[i].style = "";
}
document.getElementById("versions").selectedIndex = 3;
}
processTooltip();
}
function processTooltip() {
var filter = "collapse" + getVersion();
var collList;
@@ -3086,6 +3113,9 @@
hideList(document.getElementsByName("collapse30"));
hideList(document.getElementsByName("collapse31"));
}
// if (checkDefault(document.getElementById("xmlArea").value.trim()) || document.getElementById("xmlArea").value.trim() == "") {
// document.getElementById("defaultXMLButton").classList.toggle("active", true);
// } else {
@@ -3175,6 +3205,7 @@
setDefaultContent(document.getElementById("transformArea"), 'Insert XPath expression here');
console.log("init");
processTooltip();
processVersionSelector();
tool.addEventListener('change', event => {
//Check if script was called from textarea or selector
var targetID = event.target.getAttribute('id');
@@ -3182,6 +3213,7 @@
return;
}
processTooltip();
processVersionSelector();
})
tool.addEventListener('click', event => {
//Check if script was called from textarea or selector
@@ -3190,6 +3222,7 @@
return;
}
processTooltip();
processVersionSelector();
})
tool.addEventListener('change', event => {
//Check if script was called from textarea or selector
@@ -3198,6 +3231,7 @@
return;
}
processTooltip();
processVersionSelector();
})
}
</script>

View File

@@ -18,8 +18,8 @@
</div>
<label for="processors">Select XSLT processor:</label>
<select name="processors" id="processors">
<!-- <option value="saxon">Saxon</option> -->
<option value="xalan">Xalan</option>
<option value="libxml">libXML</option>
</select>
<!-- <span id="processorTooltipInfo">procInfo</span><br> -->
<br>

View File

@@ -19,6 +19,7 @@
<select name="processors" id="processors">
<option value="saxon">Saxon</option>
<option value="xalan">Xalan</option>
<option value="libxml">libXML</option>
</select>
<span id="processorTooltipInfo">procInfo</span><br>
<br>
@@ -1130,7 +1131,7 @@
console.log("processTooltip");
if (getProcInfo() == "xalan") {
if (getProcInfo() == "xalan" || getProcInfo() == "libxml") {
document.getElementById("tooltipFunctionInfo").innerText = "XSLT 1.0 functions";
document.getElementById("processorTooltipInfo").innerText = "Supports XSLT 1.0";
hideList(document.getElementsByName("collapse30"));

View File

@@ -19,6 +19,13 @@ services:
ports:
- 8081:8081
xmltools-libxml-backend:
build: ./Backend-libXML
container_name: xmltools-libxml-backend
image: xmltools-libxml-backend
ports:
- 8082:80
xmltools-mocked-services:
build:
context: ./Backend/mocked-services

View File

@@ -17,6 +17,11 @@ openapi.yml
Rest API accepts xml documents, given querry and processor version to call requested xml engine to perform given
operation and finally returns outcome in response body.
## Flask Python backend
This is module providing support for processing XMLs using libxml library. It consumes same JSON as Java backend.
## Mocked services
MockedServices is a tool that allows developer to create, in easy and simple way, http server mocked endpoints for integration tests