Merge pull request 'bema/func/formatter' (#48) from bema/func/formatter into dev

Reviewed-on: R11/release11-tools-web#48
This commit is contained in:
2023-02-21 10:48:16 +01:00
15 changed files with 383 additions and 24 deletions

View File

@@ -1,16 +1,32 @@
from lxml import etree
def prettify(source: str) -> str:
xml = etree.XML(source)
return etree.tostring(xml, pretty_print=True).decode()
def minimize(source: str) -> str:
result = source
to_remove = [" ", " ", "\t", "\n"]
to_substitute = [(" <", "<"), ("> ", ">"), ("</ ", "</"), (" >", ">")]
for chars in to_remove:
result = result.replace(chars, "")
for e in to_substitute:
result = result.replace(e[0], e[1])
return result
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
"""
@@ -34,11 +50,8 @@ 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))
@@ -54,11 +67,8 @@ 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))

View File

@@ -15,16 +15,50 @@ cors = CORS(app, resource={
}
})
def format_xml(request: request, type: str) -> str:
"""Function to format XML
:param request: Received request
:param type: Type of needed processing: xsd, xslt or xpath
:raises ValueError: is raised when type is different than those provided above
:return: response JSON converted to string and response code
"""
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 == "prettify"):
response_json['result'] = Parser.xsd(data, process)
elif (type == "minimize"):
response_json['result'] = Parser.xslt(data, process)
else:
raise ValueError("Valid operation types are: prettify, minimize")
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
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
@@ -39,6 +73,10 @@ def process_xml(request: request, type: str) -> str:
response_json['result'] = Parser.xslt(data, process)
elif (type == "xpath"):
response_json['result'] = Parser.xpath(data, process)
elif (type == "prettify"):
response_json['result'] = Parser.prettify(data)
elif (type == "minimize"):
response_json['result'] = Parser.minimize(data)
else:
raise ValueError("Valid operation types are: xsd, xslt, xpath")
@@ -70,5 +108,13 @@ def xsd():
def xslt():
return process_xml(request, "xslt")
@app.route("/prettifypost", methods=["POST"])
def prettify():
return process_xml(request, "prettify")
@app.route("/minimizepost", methods=["POST"])
def minimize():
return process_xml(request, "minimize")
if __name__ == "__main__":
app.run()

View File

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

View File

@@ -0,0 +1,5 @@
{
"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>",
"processor": "libxml",
"version": "1.0"
}

View File

@@ -0,0 +1,104 @@
<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>

View File

@@ -0,0 +1,3 @@
url = "http://localhost:5000/prettifypost"
data = "@prettify.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": "whatever",
"processor": "libxml",
"version": "1.0"
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -287,6 +287,10 @@
width: 100%;
}
.half-width {
width: 50%;
}
.max-width.with-padding {
width: 94%;
}

View File

@@ -91,7 +91,7 @@ function refreshTooltip() {
document.getElementById("xsltelementsheader").innerText = XSLTheader;
}
function performRequest(text, checkXML, checkTransform){
function performRequest(endpoint, checkXML, checkTransform){
var xmlData = document.getElementById("xmlArea").value.trim();
var transformData = document.getElementById("transformArea").value.trim();
@@ -106,7 +106,7 @@ function performRequest(text, checkXML, checkTransform){
empty = true;
}
if (!empty) {
restRequest(text);
restRequest(endpoint, xmlData, transformData);
}else{
document.getElementById("resultArea").value = "No data provided!";
return false;
@@ -114,17 +114,33 @@ function performRequest(text, checkXML, checkTransform){
}
function performFormatRequest(endpoint, checkXML){
var xmlData = document.getElementById("xmlArea").value.trim();
var empty = false;
if (defaultStrings.includes(xmlData) && checkXML) {
document.getElementById("xmlArea").style.backgroundColor = color_red;
xmlData = "";
empty = true;
}
if (!empty) {
restRequest(endpoint, xmlData, null);
}else{
document.getElementById("resultArea").value = "No data provided!";
return false;
}
}
//Form REST request, send, receive and display in resultArea
async function restRequest(text) {
async function restRequest(endpoint, xmlData, transformData) {
const escapeChar = "specialEscapeChar";
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();
const addr = window.location.protocol + "//" + window.location.hostname + port + endpoint;
if(defaultStrings.includes(xmlData)){
xmlData = "<empty/>";

View File

@@ -25,6 +25,7 @@
<li id="toolListRow"><a href="./tools/xpath.html" target="iframe">XPath</a></li>
<li id="toolListRow"><a href="./tools/xslt.html" target="iframe">XSLT</a></li>
<li id="toolListRow"><a href="./tools/xsd.html" target="iframe">XSD</a></li>
<li id="toolListRow"><a href="./tools/formatter.html" target="iframe">Formatter</a></li>
</ul>
<div id="copyright">Copyright © 2023<br><a href="http://release11.com/">Release11 Sp. z. o. o.</a></div>
</div>

View File

@@ -0,0 +1,161 @@
<!DOCTYPE html>
<html>
<head>
<!-- <link rel="stylesheet" href="styles.css"> -->
<link rel="stylesheet" href="../assets/css/tools/r11form.css">
<script src="../assets/scripts/tools/scripts.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="utf-8" />
</head>
<body onload="init();">
<div class="container">
<div id="tool" class="tool rwd-expandable">
<div class="tool-context">
<div class="headline">
<h1>Online XML Formatter <span class="versionInfo"><span class="version-span">v0.21.37 BETA</span></span>
</h1>
</div>
<select name="processors" id="processors" class="hidden">
<option value="libxml">libXML</option>
</select>
<label for="xmlArea"><b>Insert your XML:</b></label>
<textarea id="xmlArea" name="xmlArea" rows="15"
class="textarea-300 bordered-field vertically-resizeable max-width"
onblur="setDefaultContent(this, 'Insert XML here');"
onfocus="clearDefaultContent(this, 'Insert XML here');"></textarea>
<br><br>
<button id="requestButton" class="max-width block-label action-button active"
onclick="performFormatRequest('prettifypost', true)">Prettify XML</button>
<button id="requestButton" class="max-width block-label action-button active"
onclick="performFormatRequest('minimizepost', true)">Minimize XML</button>
<br><br>
<label for="resultArea"><b>Result:<span id="procinfo"></span></b></label>
<textarea id="resultArea" name="resultArea" rows="2"
class="bordered-field textarea-300 vert2ically-resizeable max-width" style="margin-bottom: 50px;"></textarea>
</div>
</div>
<div class="tooltip-window rwd-hideable">
<h2>What is this?</h2>
<p>This tool has 2 main functions:
<ul>
<li><strong>Prettify XML</strong> to make it human-readable (add indentation etc.)</li>
<li><strong>Minimize XML</strong> to make it more compact (exactly opposite to above)</li>
</ul>
</p>
</div>
</div>
<!-- <script>
function getVersion() {
return document.getElementById("versions").value;
}
</script> -->
<script>
function processTooltip() {
console.log("processTooltip");
if (getProcInfo() == "xalan") {
document.getElementById("tooltipFunctionInfo").innerText = "XSLT 1.0 functions";
document.getElementById("processorTooltipInfo").innerText = "Supports XSLT 1.0";
hideList(document.getElementsByName("collapse30"));
} else {
document.getElementById("tooltipFunctionInfo").innerText = "XSLT 1.0, 2.0 & 3.0 functions";
document.getElementById("processorTooltipInfo").innerText = "Supports XSLT up to 3.0";
showList(document.getElementsByName("collapse30"));
}
}
</script>
<script>
function getProcessor() {
return document.getElementById("processors").value;
}
</script>
<script>
function getVersion() {
if (getProcInfo() == "xalan") {
return "1.0";
} else {
return "3.0";
}
}
</script>
<script>
function getProcInfo() {
var processVariables = document.getElementById("processors").value;// + "&version=" + document.getElementById("versions").value;
return processVariables;
}
</script>
<script>
var triggerList = document.getElementsByClassName("collapseTrigger");
for (i = 0; i < triggerList.length; i++) {
console.log("trigger connected");
triggerList[i].addEventListener("click", function () {
console.log("click");
var collapsible = this.parentElement;
var collapsibleData = this.nextElementSibling;
if (collapsibleData.style.maxHeight > "0px") {
collapsibleData.style.maxHeight = "0px";
this.classList.toggle("active", false);
if (!this.classList.contains("collapsibleMini")) {
collapsible.classList.toggle("active", false);
}
var subLists1 = collapsibleData.getElementsByClassName("content");
var subLists2 = collapsibleData.getElementsByClassName("active");
for (j = 0; j < subLists1.length; j++) {
subLists1[j].style.maxHeight = "0px";
}
for (j = 0; j < subLists2.length; j++) {
subLists2[j].classList.toggle("active", false);
}
} else {
collapsibleData.style.maxHeight = (collapsibleData.scrollHeight) + "px";
this.classList.toggle("active", true);
if (!this.classList.contains("collapsibleMini")) {
collapsible.classList.toggle("active", true);
} else {
var parentContent = this.closest(".content");
parentContent.style.maxHeight = (parentContent.scrollHeight + collapsibleData.scrollHeight) + "px";
}
}
});
}
</script>
<script>
function init() {
//Handle clicks in whole form and set info in tooltip
setDefaultContent(document.getElementById("xmlArea"), 'Insert XML here');
setDefaultContent(document.getElementById("transformArea"), 'Insert XSD here');
console.log("init");
// refreshTooltip();
processTooltip();
tool.addEventListener('click', event => {
//Check if script was called from textarea or selector
var targetID = event.target.getAttribute('id');
if (targetID !== "processors" && targetID !== "xmlArea" && targetID !== "transformArea" && targetID !== "versions") {
return;
}
processTooltip();
// console.log("clock");
})
}
</script>
</body>
</html>