249 Commits

Author SHA1 Message Date
f0dd41a86e 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>
2024-01-04 08:08:16 +01:00
971cc5f36a merge new tools (#244)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Co-authored-by: Adam Bem <bema@noreply.example.com>
Reviewed-on: #244
2023-09-05 11:15:20 +02:00
57a08c3246 Resolved merge conflict in xmlFormatter.html 2023-05-30 15:56:03 +02:00
5a331d9815 Fixed merge conflicts 2023-05-30 15:49:50 +02:00
e9221e2393 Release 11.3 2023-05-30 15:42:09 +02:00
7318708bd2 Disabled persistency in Redis (#214)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #214
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-30 15:27:15 +02:00
66b20f8256 Added tests for JSON Formatter (#212)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #212
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-30 13:17:10 +02:00
b6e6277074 Cleared unused listeners, and optimize uianimation code (#213)
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #213
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-30 13:15:47 +02:00
fb128070dc Removed broken code 2023-05-26 14:12:11 +02:00
d0c19e19df Merged bema/ref/tools_urls to master 2023-05-26 14:11:20 +02:00
c41c3f5abc Merged widlam/refactor/issue#201 to master 2023-05-26 14:04:34 +02:00
9b18a9f42d Simplified history 2023-05-26 13:55:48 +02:00
a8d93fc2a5 Made more elegant solution to tools URLs 2023-05-26 11:57:00 +02:00
6058169818 Solved #180 and one other bug (#210)
I found and fixed bug: When in URL query was put without # at the end the page would start reloading indefinitely

Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #210
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-26 11:39:57 +02:00
d336f5d18e Fixed bug with category not bein remembered 2023-05-26 10:44:54 +02:00
45fab20cc4 Merge branch 'master' of gitea.release11.com:R11/release11-tools into widlam/refactor/issue#201 2023-05-25 14:59:43 +02:00
b733e1e344 Fixed history problem, and improve mock services frontend 2023-05-25 14:49:16 +02:00
97042faaa3 Tools can be selected through URL (solves #161) (#207)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #207
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-24 14:40:07 +02:00
8815f657e0 Clean frontend code 2023-05-24 11:08:15 +02:00
ecafb17f05 revert f9b426bb30
revert Every tool can now be accessed from URL
2023-05-24 11:06:50 +02:00
f9b426bb30 Every tool can now be accessed from URL 2023-05-24 10:33:00 +02:00
02c10b8354 Fixed not working JSON arrays (#206)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #206
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-23 13:48:22 +02:00
5b69fd1de0 Every service meant to be public work now on port 80 (#205)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #205
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-23 08:59:09 +02:00
2aaf993f7a Started to removing changing UUID and many messages system 2023-05-23 08:38:28 +02:00
d5e33381a2 Refactor of History module (#184)
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #184
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-19 13:10:45 +02:00
d231a7476b Fixed timezone (#193)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #193
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-19 13:09:01 +02:00
369256baf2 tests with variable URL (#200)
Co-authored-by: augustyd <kainytsugua.kerad@gmail.com>
Reviewed-on: #200
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-committed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-05-18 13:38:38 +02:00
e697a783ae Solved #195 and cleaned up code (#196)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #196
Reviewed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-05-18 13:36:51 +02:00
1930cde695 Postman tests (#194)
Co-authored-by: augustyd <kainytsugua.kerad@gmail.com>
Reviewed-on: #194
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-committed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-05-17 14:08:16 +02:00
bcbfd34feb Moved scripts from .html files to seperate js .files (#191)
Let's hope everything works as before or better.

Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #191
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-16 09:59:04 +02:00
2d97e39dbe Fixed 404 when no lastPage was stored (solves #189)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #190
2023-05-12 15:03:46 +02:00
c89623c3a8 Dependencies in libXML now have specified versions
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #187
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-12 14:13:47 +02:00
dc3df79fc1 Moved frontend of REST Mock to frontend container (solves #168)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #186
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-12 10:06:19 +02:00
34038a2ce9 Tools java backend now uses interfaces for engine classes (solves #167) (#179)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #179
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-11 15:23:54 +02:00
d8504ee8f8 Changed timezone (solves #164 and #181)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #183
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-11 11:20:36 +02:00
6a1c6aac46 Last opened page is now stored (solves #166) (#178)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #178
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-09 15:12:57 +02:00
72d69f2967 Froze Release11.2 (#177)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Co-authored-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Reviewed-on: #177
2023-05-09 15:02:44 +02:00
7fd6fd3788 Fixed incorrect Content-Type (#174) (#175)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #175
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-09 11:15:26 +02:00
41d3b90fd8 Removed version number from Mock Service (done #172) (#173)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #173
Reviewed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-05-09 10:21:37 +02:00
c55942c24a Added syntax highlighting for XML Tools (#156)
Syntax highlight now should work on all tools apart from Mock Services.

Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #156
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-08 11:11:16 +02:00
21f5911b1c Added sample XSD schema (#163)
Due to some errors with namespaces and XSD schema simplified sample XML for that tool.

Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #163
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-05-08 10:13:10 +02:00
71bbe668f6 augustyd/enchancment/issue#98 (#155)
issue#98
save button when user creates new message and has unsaved data in old message

Co-authored-by: augustyd <kainytsugua.kerad@gmail.com>
Reviewed-on: #155
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-committed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-04-26 13:38:23 +02:00
4a04ac3b70 Added a email address to report a bugs (#154)
![image](/attachments/d3e81b26-ea63-4ed6-8ae6-b8945325be16)

Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #154
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-26 13:32:13 +02:00
b26840ffba Added new JSON field documentation (#153)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #153
2023-04-21 09:43:24 +02:00
1199e06bef Implemented message shown when no data type is returned. (#150)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #152
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-21 09:31:28 +02:00
1b7f6e6f70 Added META tags for SEO and SEM (#149)
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #149
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-21 08:54:21 +02:00
fe6585d509 Merge branch 'master' of gitea.release11.com:R11/release11-tools 2023-04-19 13:36:01 +02:00
093c8756b1 Added XSLTTemplate, functions that add it to transform area and documentation for that function (#144)
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #144
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-19 13:35:40 +02:00
2b8a9c3008 Implemented showing returned type (#112) (#148)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #148
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-19 13:33:39 +02:00
1f10a1d5b5 Resolved conflict 2023-04-19 13:31:58 +02:00
8a852b7a83 Fixed doubled category 2023-04-19 13:30:14 +02:00
38c1215889 Disabled caching for frontend (#146)
Disable caching for frontend

Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #146
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-19 13:27:52 +02:00
1fc1ab76ec Resolved another conflict 2023-04-19 13:27:49 +02:00
2f0541fe3d Resolved another conflict 2023-04-19 13:27:06 +02:00
5c39b7cfe0 Fixed error codes and added logging (#138)
fixed error codes (400 not 500) and added logging for json

Co-authored-by: augustyd <kainytsugua.kerad@gmail.com>
Reviewed-on: #138
Co-authored-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-committed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-04-19 13:26:13 +02:00
db055ef58b Resolved another conflict 2023-04-19 13:26:10 +02:00
420bfaccd9 Resolved merge conflict in xpath.html 2023-04-19 13:18:55 +02:00
3d41447581 Added numeric functions and some string 2023-04-19 13:05:36 +02:00
a773022f0d Added tooltips for XPath 2.0 (#134)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #134
2023-04-19 13:05:36 +02:00
afcd52815f Prepared templates for new XPath tooltips (#133)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #133
2023-04-19 13:05:36 +02:00
59ffeb9363 Fixed xsd in release version (#147)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #147
Reviewed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-04-19 13:02:55 +02:00
b72157377d Disabled caching for frontend (#146)
Disable caching for frontend

Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #146
Reviewed-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-19 10:28:04 +02:00
0946982ab6 Added missing functions (#143)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #143
Reviewed-by: Mikolaj Widla <widlam@noreply.example.com>
Reviewed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-04-18 10:55:45 +02:00
8098aeacd9 Added new tooltips for XPath 3.0 and 3.1
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Reviewed-on: #139
Reviewed-by: Adam Bem <bema@noreply.example.com>
Reviewed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-04-18 10:05:44 +02:00
de94eca0ac Fixed error codes and added logging (#138)
fixed error codes (400 not 500) and added logging for json

Co-authored-by: augustyd <kainytsugua.kerad@gmail.com>
Reviewed-on: #138
Co-authored-by: Dariusz Augustyniak <augustyd@noreply.example.com>
Co-committed-by: Dariusz Augustyniak <augustyd@noreply.example.com>
2023-04-14 10:42:47 +02:00
a7edf934f7 Merged critical XSLT fix 2023-04-12 10:01:27 +02:00
7c0d79612a Added numeric functions and some string 2023-04-12 10:01:10 +02:00
02f1977ff0 Added tooltips for XPath 2.0 (#134)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #134
2023-04-12 10:01:10 +02:00
1816302ba1 Prepared templates for new XPath tooltips (#133)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #133
2023-04-12 10:01:10 +02:00
64ae2d044d Fixed not working XSLT tool (#136)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #136
2023-04-12 09:56:39 +02:00
00f3606da6 Added numeric functions and some string 2023-04-06 14:03:39 +02:00
f77a6f15c2 Added tooltips for XPath 2.0 (#134)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #134
2023-04-06 11:53:53 +02:00
0e9a87bfe7 Prepared templates for new XPath tooltips (#133)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #133
2023-03-29 08:49:43 +02:00
994804b640 Removed unneeded console.logs (#131)
Co-authored-by: mikolaj widla <mikolaj.widla@gmail.com>
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #131
2023-03-24 09:32:22 +01:00
9265c0a051 Removed imput data from logs (#130)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #130
2023-03-24 09:12:32 +01:00
71f9ae9553 widlam/refactoring/issue#120 (#128)
Co-authored-by: mikolaj widla <mikolaj.widla@gmail.com>
Co-authored-by: widlam <mikolaj.widla@gmail.com>
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #128
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-03-23 10:16:47 +01:00
19de505ca4 Added length limit for data in UUID field (#127)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #127
2023-03-22 13:27:49 +01:00
13d51c05d8 Switched fonts to self-hosted (#126)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #126
2023-03-22 11:19:57 +01:00
0bd80b1878 Implemented sending logs to ElasticSearch with Filebeat (#125)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: #125
2023-03-21 09:47:28 +01:00
bd565ffd7d Logging system enhanced (#124)
Co-authored-by: mikolaj widla <mikolaj.widla@gmail.com>
Reviewed-on: #124
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-03-21 09:46:55 +01:00
60922ea3c7 Jenkins pipeline (#123)
Reviewed-on: R11/release11-tools-web#123
2023-03-18 08:31:12 +01:00
02ac7e09d3 Added placeholder files for Terms of Use and Privacy Policy (#119)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: R11/release11-tools-web#119
2023-03-16 09:45:50 +01:00
353d95e377 Added docs in js files and fixed some minor visual bugs (#118)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: R11/release11-tools-web#118
2023-03-15 15:17:31 +01:00
09409dc698 Added category menu (#117)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: R11/release11-tools-web#117
2023-03-15 13:26:37 +01:00
8f6047bb9f Added terms of use and privacy statement links (#116)
Co-authored-by: mikolaj widla <mikolaj.widla@gmail.com>
Reviewed-on: R11/release11-tools-web#116
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-03-15 13:26:22 +01:00
715facf35b #90 Gson implementation. (#106)
Co-authored-by: Artur Kołecki <koleckiartur@icloud.com>
Reviewed-on: R11/release11-tools-web#106
2023-03-08 12:05:19 +01:00
5ef85cb484 Fixed #101 (#111)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: R11/release11-tools-web#111
2023-03-08 09:49:01 +01:00
6874e463fa Resolved merge conflict 2023-03-07 11:52:57 +01:00
0844525f8e Fixed typos 2023-03-07 11:21:07 +01:00
04fc103016 Fixed validation for UUID 2023-03-07 11:02:47 +01:00
599bcf96b2 Fixed bug, that broke UUID changer when user provides spaces in UUID. (#102)
fixed bug

Co-authored-by: mikolaj widla <mikolaj.widla@gmail.com>
Reviewed-on: R11/release11-tools-web#102
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-03-06 15:05:51 +01:00
6d104948cc Fixed bug, that dont refresh data after modal closes by clicking in overlay 2023-03-06 15:03:06 +01:00
9135a9221f Added Numeric and Boolean functions to XPath's tooltips (#103)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: R11/release11-tools-web#103
2023-03-06 14:38:23 +01:00
c440b08bdf Fixed bug, that broke UUID changer when user provides spaces in UUID. 2023-03-06 12:35:29 +01:00
a3d781f477 Added refresh history and headers after changing tile (#100)
Co-authored-by: mikolaj widla <mikolaj.widla@gmail.com>
Reviewed-on: R11/release11-tools-web#100
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-03-06 11:55:05 +01:00
dcad69d43c UUID switching, and add new message button fix (#96)
Co-authored-by: mikolaj widla <mikolaj.widla@gmail.com>
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: R11/release11-tools-web#96
Co-authored-by: Mikolaj Widla <widlam@noreply.example.com>
Co-committed-by: Mikolaj Widla <widlam@noreply.example.com>
2023-03-06 11:54:40 +01:00
02f46169d9 Fixed #94 and done some refactoring (#99)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: R11/release11-tools-web#99
2023-03-03 10:43:32 +01:00
fd95d7e845 Added missing docs and organized sample files (#97)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: R11/release11-tools-web#97
2023-03-02 14:08:39 +01:00
c5190f7b62 Fixed #75 for Xalan (#95)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: R11/release11-tools-web#95
2023-03-02 12:10:34 +01:00
b0b930926c Refactored tools services endpoints system and fixed json formatter. (#91)
Co-authored-by: Artur Kołecki <koleckiartur@icloud.com>
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: R11/release11-tools-web#91
2023-03-02 11:49:21 +01:00
a90cbb938f Partial fix for #75 - fixes problem in libXML (#92)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: R11/release11-tools-web#92
2023-03-02 11:08:00 +01:00
eb8518afab XML Formatter QoL improvements (#88)
- Rewritten backend methods for prettifing and minimizing XMLs
- Added "Clear" and "Insert default XML" buttons in XML Formatter.
- Added place to display error messages in case of any

Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: R11/release11-tools-web#88
2023-03-01 12:40:30 +01:00
dee92f0e3d Created swagger container and swagger documentation from ./Swagger/swagger.json (#87)
Co-authored-by: Artur Kołecki <koleckiartur@icloud.com>
Reviewed-on: R11/release11-tools-web#87
2023-03-01 11:44:21 +01:00
773e2ac17e Fixed bug with field staying red 2023-02-28 15:04:08 +01:00
ff7e7461e9 Resolved merge conflict 2023-02-28 14:57:20 +01:00
50a8082f32 Resolved merge conflict 2023-02-28 14:55:56 +01:00
28e76b2374 Fixed bugs mentioned in comments for #35
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: R11/release11-tools-web#85
2023-02-28 14:18:54 +01:00
d6c2c863eb Little changes in json formatter. (#83)
Co-authored-by: Artur Kołecki <koleckiartur@icloud.com>
Reviewed-on: R11/release11-tools-web#83
2023-02-28 14:08:26 +01:00
4d7c0d6acd Created json formatter and validator. (#82)
Co-authored-by: mikolaj widla <mikolaj.widla@gmail.com>
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Co-authored-by: Adam Bem <bema@noreply.example.com>
Co-authored-by: Artur Kołecki <koleckiartur@icloud.com>
Reviewed-on: R11/release11-tools-web#82
2023-02-28 12:51:11 +01:00
24c9c2fe5a dev (#81)
Co-authored-by: mikolaj widla <mikolaj.widla@gmail.com>
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: R11/release11-tools-web#81
2023-02-28 11:46:54 +01:00
f96f8270ce Automated version generation (ticket #36)
Co-authored-by: Adam Bem <adam.bem@zoho.eu>
Reviewed-on: R11/release11-tools-web#80
2023-02-28 11:45:39 +01:00
3c927f91cf Merge pull request 'bema/func/#35' (#72) from bema/func/#35 into dev
Reviewed-on: R11/release11-tools-web#72
2023-02-23 14:12:34 +01:00
d4c4d38aef Merge pull request 'Added tooltips for add new message, and message list elements' (#71) from widlam/feature/issue#39 into dev
Reviewed-on: R11/release11-tools-web#71
2023-02-23 14:12:00 +01:00
7042959ee3 Added Format XML button in XSLT and XSD tools 2023-02-23 14:11:18 +01:00
15830d7adf Implemented Format XML button 2023-02-23 13:59:08 +01:00
c7d34ed05f Fixed bug with choosing ports 2023-02-23 13:57:57 +01:00
1e56b2885a Simplified formatter 2023-02-23 13:46:30 +01:00
9bc3370f3b Format function now allows to choose source and target IDs 2023-02-23 13:39:57 +01:00
5db10ab1c1 Refactored code used to sending requests to backends 2023-02-23 13:17:50 +01:00
d9a413f88d Added tooltips for add new message, and message list elements 2023-02-23 13:05:44 +01:00
c2095f4bcf Merge pull request 'Formatter now accepts XMLs with prologs' (#70) from bema/fix/#57 into dev
Reviewed-on: R11/release11-tools-web#70
2023-02-23 11:05:20 +01:00
fde28a5880 Merge pull request 'Disabled resultArea for XMLTools' (#69) from widlam/feature/issue#68 into dev
Reviewed-on: R11/release11-tools-web#69
2023-02-23 11:04:58 +01:00
75c31a7c58 Merge pull request 'Added clear button for XPath, XSD and XSLT' (#67) from widlam/feature/issue#38 into dev
Reviewed-on: R11/release11-tools-web#67
2023-02-23 11:04:22 +01:00
a95c745ae2 Formatter now accepts XMLs with prologs 2023-02-23 10:42:10 +01:00
8083d7fa63 Added comments to Parser.py 2023-02-23 09:58:00 +01:00
ac908e49e6 Disabled resultArea for XMLTools 2023-02-23 09:15:47 +01:00
05857a7d7e Added clear button for XPath, XSD and XSLT 2023-02-23 09:02:17 +01:00
28a9a1f670 Merge pull request 'dev' (#58) from dev into master
Reviewed-on: R11/release11-tools-web#58
2023-02-22 14:10:20 +01:00
169ba0d2d1 Fixed various bugs with tooltips 2023-02-22 13:52:32 +01:00
d3c02e164f Fixed various shenanigans with tips filtering depenting on selected XPath 2023-02-22 12:16:01 +01:00
9b212ccb17 Merge pull request 'bema/func/#54' (#56) from bema/func/#52 into dev
Reviewed-on: R11/release11-tools-web#56
2023-02-22 11:14:23 +01:00
f295fcc693 Merge pull request 'Fixed #52' (#55) from bema/fix/#52 into dev
Reviewed-on: R11/release11-tools-web#55
2023-02-22 11:13:16 +01:00
8524ecd6ca HTTP status field is red when its value is invalid 2023-02-22 11:12:05 +01:00
d1d54c82f9 Added suggestions in http status field 2023-02-22 10:57:28 +01:00
eed5454755 Fixed #52 2023-02-22 10:47:38 +01:00
89d70b32d2 Merge pull request 'added validation and posibility to add custom http status' (#51) from widlam/fix/issue#46 into dev
Reviewed-on: R11/release11-tools-web#51
2023-02-21 15:09:11 +01:00
5032985787 Fixed #43 2023-02-21 15:08:25 +01:00
ec5cc7cc0c Merge pull request 'Fixed #37' (#49) from bema/fix/ticket#37 into dev
Reviewed-on: R11/release11-tools-web#49
2023-02-21 15:06:34 +01:00
bd5c615017 added validation and posibility to add custom http status 2023-02-21 15:06:16 +01:00
84203c825c Fixed #37 2023-02-21 11:10:06 +01:00
d7926a64e2 Fixed #42 2023-02-21 11:01:37 +01:00
65a730105d Merge pull request 'bema/func/formatter' (#48) from bema/func/formatter into dev
Reviewed-on: R11/release11-tools-web#48
2023-02-21 10:48:16 +01:00
56a9906c58 Made minimizer even more presize 2023-02-21 10:44:09 +01:00
8f3d1a13de Made minimizer more presize 2023-02-21 10:40:33 +01:00
91dc131fba Some refactor allowing to use same js code as everywhere 2023-02-20 15:18:20 +01:00
d4791a1959 Merge pull request 'bema/func/basic_rwd' (#45) from bema/func/basic_rwd into dev
Reviewed-on: R11/release11-tools-web#45
2023-02-20 15:07:26 +01:00
8381a3e4de Merge pull request 'Added buttons for default XML in XSD and XSLT' (#44) from widlam/feature/issue#34 into dev
Reviewed-on: R11/release11-tools-web#44
2023-02-20 15:06:03 +01:00
e37ce3c678 Fixed bug in minimalizer 2023-02-20 15:04:57 +01:00
cc7664519e Implemented Q&D minimalizer 2023-02-20 15:01:54 +01:00
935b1d01ea Updated sample files 2023-02-20 14:58:50 +01:00
947e5d621e Connected frontend and backend in formatter 2023-02-20 14:57:32 +01:00
f5c8910277 Added endpoints for formatter 2023-02-20 14:25:46 +01:00
b9e2e527fd Added buttons for default XML in XSD and XSLT 2023-02-20 14:03:50 +01:00
153a7313ef Added new sample files 2023-02-20 11:02:30 +01:00
4955a7cc4f Implemented new tool in backend 2023-02-20 11:02:16 +01:00
78cc13a661 Added new tool to frame 2023-02-20 10:00:28 +01:00
e2cf490f9d Removed empty class 2023-02-20 09:59:48 +01:00
8c132d12d3 Added interface for formater rool 2023-02-20 09:58:49 +01:00
df8b7cd007 Added RWD for XPath and XSD tools 2023-02-17 12:40:50 +01:00
19c47d3cd2 Removed empty class in r11form.css 2023-02-17 12:27:33 +01:00
cb48f3017a Implemented basic RWD 2023-02-17 12:25:16 +01:00
db02993bde Added meta tags needed for RWD 2023-02-17 12:11:34 +01:00
3f5aa29a3b Merge pull request 'dev' (#33) from dev into master
Reviewed-on: R11/release11-tools-web#33
2023-02-16 14:58:50 +01:00
d6bacc6b4f Merge pull request 'Added tooltip for button!' (#32) from widlam/bug/issue#12 into dev
Reviewed-on: R11/release11-tools-web#32
2023-02-15 13:19:36 +01:00
8254f9387f Merge pull request 'bema/ref/visual_tools_revamp' (#31) from bema/ref/visual_tools_revamp into dev
Reviewed-on: R11/release11-tools-web#31
2023-02-15 13:16:23 +01:00
9aa6593608 Added tooltip for button! 2023-02-15 13:15:38 +01:00
c76b677f0e Added bottom border on message list buttons 2023-02-15 13:13:22 +01:00
829bdeca81 Fixed typo 2023-02-15 12:48:28 +01:00
8e18fd9964 Fixed width of Content Type field 2023-02-15 12:14:30 +01:00
134696f73c Fixed background of http status list 2023-02-15 11:12:40 +01:00
bb18cb53c6 Revamped Mocked Services 2023-02-15 10:58:12 +01:00
4b3fac59c0 Enlarged tool window 2023-02-15 09:47:34 +01:00
86e46ad205 Revamped tip box 2023-02-15 09:38:46 +01:00
1f4d4056c7 Merge pull request 'bema/ref/frame_visual_overhaul' (#30) from bema/ref/frame_visual_overhaul into dev
Reviewed-on: R11/release11-tools-web#30
2023-02-14 15:33:49 +01:00
1760b89e05 Changed headerbar to white and added title 2023-02-14 15:31:25 +01:00
3c3f2ef8ad Removed unsed code 2023-02-14 14:53:07 +01:00
9ef61086df Change to dark theme 2023-02-14 14:32:00 +01:00
a2b4f28c26 Updated logos, background, added new animations 2023-02-14 13:28:20 +01:00
2907d40a2e Merge pull request 'Added validation for essential headers. And disabled deleting it.' (#29) from widlam/fix/issue#17 into dev
Reviewed-on: R11/release11-tools-web#29
2023-02-14 13:24:20 +01:00
1d648890cc Added validation for essential headers. And disabled deleting it. 2023-02-14 13:21:44 +01:00
65ad318a5c Fixed #27, #14, added some rounded corners 2023-02-14 12:50:18 +01:00
ce02db8f6d Solved issue#19, added default XML 2023-02-14 11:04:43 +01:00
b487c5f0bc Merge pull request 'dev' (#26) from dev into master
Reviewed-on: R11/release11-tools-web#26
2023-02-13 11:04:15 +01:00
e994881ff0 CSSes are no longer fetched from Frontend module 2023-02-13 09:57:10 +01:00
e6e3a704bc Changed text field to option list, resolved #11 2023-02-13 09:41:45 +01:00
84aef5d830 Resolved #22 2023-02-10 14:51:06 +01:00
d35103422b Resolved #25 2023-02-10 14:47:36 +01:00
9a6e8c543e Removed 'here' console log 2023-02-10 14:18:48 +01:00
81cc70b5e7 Merge pull request 'bema/func/xalan_error_handling' (#24) from bema/func/xalan_error_handling into dev
Reviewed-on: R11/release11-tools-web#24
2023-02-10 11:58:19 +01:00
6a0e49546c Improved faulty JSON error handling 2023-02-10 11:55:12 +01:00
c14cfe8a52 Xalan now returns message when something goes wrong 2023-02-10 11:34:09 +01:00
6e53f2f1bf Merge pull request 'bema/fix/xalan_xpath' (#23) from bema/fix/xalan_xpath into dev
Reviewed-on: R11/release11-tools-web#23
2023-02-09 15:33:12 +01:00
fa1a03f6e3 Fixed #21 2023-02-09 15:23:21 +01:00
c537bed4a1 Fixed scripts.js 2023-02-09 13:57:20 +01:00
45e46de8f5 Fixed scripts.js 2023-02-09 13:56:42 +01:00
58ef4dcdc4 Merge pull request 'bema/func/libxml_backend' (#20) from bema/func/libxml_backend into dev
Reviewed-on: R11/release11-tools-web#20
2023-02-09 13:34:42 +01:00
f8d5934998 Resolved merge conflict 2023-02-09 13:33:00 +01:00
4b241978e0 Removed unused code 2023-02-09 13:24:28 +01:00
45a7e60ae4 Replaced xpath handling implementation 2023-02-09 13:22:33 +01:00
5a2164b839 Added Xalan option in XPath tool 2023-02-09 13:21:18 +01:00
d2e5586792 Updated docs 2023-02-08 14:31:49 +01:00
96f80e4589 Implemented 400 response code on error 2023-02-08 14:28:11 +01:00
07f2adcc1f Corrected libxml backend port 2023-02-08 14:03:08 +01:00
0c5a83d3b6 Added libXML backend container to docker-compose.yml 2023-02-08 14:01:19 +01:00
9384011377 Added service selection depending on selected processor 2023-02-08 13:15:02 +01:00
c0a54291ae Added service selection depending on selected processor 2023-02-08 13:14:31 +01:00
e408840f6d Added service selection depending on selected processor 2023-02-08 12:49:36 +01:00
7dbf3add28 Added option for libXML 2023-02-08 12:38:58 +01:00
06458cfd10 Removed unused code 2023-02-08 11:27:15 +01:00
f68217f83a Implemented dynamic host for links in mock.html 2023-02-08 11:27:15 +01:00
07ab4f83a1 Updated .gitignore 2023-02-08 11:27:15 +01:00
b5018dfece Implemented dynamic host finding 2023-02-08 11:27:15 +01:00
7b05343e69 Merge pull request 'Updated accidently outdated on creation' (#10) from master into dev
Reviewed-on: R11/release11-tools-web#10
2023-02-08 11:21:08 +01:00
9bd74d036c Merge branch 'dev' into bema/func/libxml_backend 2023-02-08 11:00:40 +01:00
9ce0e6fcd3 Updated endpoint paths to match Java backend 2023-02-08 10:34:16 +01:00
9409638b5c Merge pull request 'bema/func/dynamic-hosts' (#8) from bema/func/dynamic-hosts into master
Reviewed-on: R11/release11-tools-web#8
2023-02-06 11:51:20 +01:00
dd695a1c2d Removed unused code 2023-02-03 14:57:46 +01:00
74f1f6f1c2 Implemented dynamic host for links in mock.html 2023-02-03 14:45:39 +01:00
c0f117a4af Updated .gitignore 2023-02-03 13:32:36 +01:00
e0f7c48801 Implemented dynamic host finding 2023-02-03 12:12:17 +01:00
e50a9dd95a Merge pull request 'bema/fix/addresses' (#7) from bema/fix/addresses into master
Reviewed-on: R11/release11-tools-web#7
2023-02-03 10:18:12 +01:00
9dad3e6d37 Added main page port 2023-02-03 10:14:14 +01:00
10d23e456c Updated backend addresses 2023-02-03 10:13:02 +01:00
656aeb17dc Updated example requests 2023-01-30 12:42:40 +01:00
ce417f8b94 Removed duplicate code 2023-01-30 12:39:53 +01:00
598f074654 Enchanced error handling 2023-01-30 12:21:39 +01:00
3817b1ac5a API now ignores content-type header (to increase compatibility with Java backend) 2023-01-30 10:53:39 +01:00
a914282a5d Added mention of new backend in readme.md 2023-01-30 10:49:34 +01:00
0b0f0b55d0 Adjusted processing time measuring 2023-01-30 10:19:06 +01:00
228f94569b Merge pull request 'bema/func/log4j_logging' (#6) from bema/func/log4j_logging into master
Reviewed-on: R11/release11-tools-web#6
2023-01-26 14:46:19 +01:00
6683ef688e Housekeeping 2023-01-26 13:41:19 +01:00
e8352dfe3d Housekeeping 2023-01-26 13:33:48 +01:00
e714c34726 Prepared dockerfile 2023-01-26 11:26:41 +01:00
17299a9a94 Added early version of libxml backend 2023-01-26 09:59:27 +01:00
8bac9db2a9 Refactor to reduce warnings 2023-01-20 14:36:45 +01:00
fadd8f468b Implemented proper logging in SparkInitializer.java 2023-01-20 14:09:08 +01:00
c48d139e6b Unified console and file logs 2023-01-20 11:46:42 +01:00
9a1c690e46 Updated SparkJava to 2.9.4 2023-01-20 10:39:24 +01:00
7657691019 Initial log4j support 2023-01-19 14:18:53 +01:00
fb673b100b Merge pull request 'Updated build paths in docker-compose.yml' (#5) from bema/fix/compose_file_paths into master
Reviewed-on: R11/release11-tools-web#5
2023-01-19 09:29:08 +01:00
d328d4718f Updated build paths in docker-compose.yml 2023-01-19 09:28:07 +01:00
64acb901ff Restructured frontend, unified source of csses
Reviewed-on: R11/release11-tools-web#4
2023-01-16 14:06:14 +01:00
8f4e42c533 Changed Homepage to Frontend and fixed typo 2023-01-16 13:59:06 +01:00
5655e46112 Fixed wrong path 2023-01-16 13:49:36 +01:00
37cfacd1e5 New frontend structure; resolved ticket #3 2023-01-16 13:47:45 +01:00
d05a8a5ce2 Fixed dockerfile and updated links in index.html 2023-01-16 09:44:47 +01:00
cf47fb09fe Moved style.css to assets as frame.css 2023-01-16 09:43:27 +01:00
916f4321ea Added readme file 2023-01-16 09:21:51 +01:00
9d7a62c37c Changed project structure, created docker-compose.yml for run all applications in one command. (#2)
Co-authored-by: Artur Kołecki <koleckiartur@icloud.com>
Reviewed-on: R11/release11-tools-web#2
2023-01-13 17:08:09 +01:00
222 changed files with 38267 additions and 8070 deletions

2
.gitignore vendored
View File

@@ -7,3 +7,5 @@
.vscode
nbactions.xml
target/
__pycache__
venv

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/

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

@@ -0,0 +1,124 @@
from lxml import etree, html
from io import BytesIO
def convertHTML(source: str, sourceFrom: str):
htmlParser = html.HTMLParser(remove_comments=True, remove_blank_text=True)
xmlParser = etree.XMLParser(remove_comments=True, remove_blank_text=True)
if sourceFrom == "xml":
xmldoc = etree.parse(BytesIO(source.encode("utf-8")), xmlParser)
return html.tostring(xmldoc, method="html", pretty_print=True, doctype="<!DOCTYPE html>").decode()
elif sourceFrom == "html":
htmldoc = html.parse(BytesIO(source.encode("utf-8")), htmlParser)
return etree.tostring(htmldoc, method="xml", pretty_print=True, doctype="", xml_declaration=True, encoding="utf-8").decode()
else:
return
def formatHTML(source: str, prettify: bool) -> str:
parser = html.HTMLParser(remove_blank_text=True, remove_comments=True, remove_pis=True)
htmlDoc = html.parse(BytesIO(source.encode("utf-8")),parser=parser)
if not prettify:
return html.tostring(htmlDoc).decode().replace("\n", "").replace("> ", ">")
return etree.tostring(htmlDoc, encoding='unicode', pretty_print=True)
def formatXML(source: str, prettify: bool) -> str:
"""Method used to format XML
:param source: XML to format
:param prettify: sets if XML must be prettified
(added indentations etc.) or not
:return: formatted XML
"""
# Prolog is removed when XML is parsed
# so program has to copy it
prolog = ""
prolog_start = source.find("<?")
if prolog_start != -1:
prolog_end = source.find("?>") + 2
prolog = source[prolog_start:prolog_end]
source = source[prolog_end: ]
byte_input = BytesIO(source.encode("utf-8"))
parser = etree.XMLParser(remove_blank_text=True)
xml = etree.parse(byte_input, parser=parser)
if prettify:
prolog += "\n"
return prolog + etree.tostring(xml, pretty_print=prettify).decode()
def xpath(source: str, xpath: str) -> str:
"""
Method used to get nodes from XML string using XPath
:param source: XML string used for selection
:param xpath: XPath query used for selection
:return: Nodes selected using XPath
"""
byte_input = BytesIO(source.encode("utf-8"))
root = etree.parse(byte_input).getroot()
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)
# root.xpath can return 4 types: float, string, bool and list.
# List is the only one that can't be simply converted to str
if type(result) is not list:
return str(result), type(result).__name__
else:
result_string = ""
for e in result:
result_string += etree.tostring(e, pretty_print=True).decode() + "\n"
return result_string, "node"
def xsd(source: str, xsd: str) -> bool:
"""
Method used to validate XML string against XSD schema
:param source: XML string used for validation
:param xsd: XSD schema to validate XML against
:return: Message saying, if the validation was successful or not
"""
schema_input = BytesIO(xsd.encode("utf-8"))
xml_schema = etree.XMLSchema(etree.parse(schema_input).getroot())
document_input = BytesIO(source.encode("utf-8"))
xml = etree.parse(document_input).getroot()
try:
xml_schema.assertValid(xml)
return "XML is valid"
except etree.DocumentInvalid as e:
return str(e)
def xslt(source: str, xslt: str) -> str:
"""
Method used to transform XML string using XSLT
:param source: XML string to transform
:param xslt: XSLT string used to transform XML
:return: Result of transformation
"""
xslt_input = BytesIO(xslt.encode("utf-8"))
xslt_transform = etree.XSLT(etree.parse(xslt_input))
document_input = BytesIO(source.encode("utf-8"))
xml = etree.parse(document_input).getroot()
transformed = str(xslt_transform(xml))
return formatXML(transformed, True)

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

@@ -0,0 +1,101 @@
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
: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']
processorData = request_data['processorData']
if (type == "xsd"):
response_json['result'] = Parser.xsd(data, processorData)
elif (type == "xslt"):
response_json['result'] = Parser.xslt(data, processorData)
elif (type == "xpath"):
response_json['result'], response_json['type'] = Parser.xpath(data, processorData)
elif (type == "prettify"):
response_json['result'] = Parser.formatXML(data, True)
elif (type == "minimize"):
response_json['result'] = Parser.formatXML(data, False)
elif (type == "prettifyHtml"):
response_json['result'] = Parser.formatHTML(data, True)
elif (type == "minimizeHtml"):
response_json['result'] = Parser.formatHTML(data, False)
elif (type == "convertHTML"):
response_json['result'] = Parser.convertHTML(data, processorData)
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['duration'] = f"{exec_time:.03f}"
response_json['processor'] = "libxml2 over lxml"
return json.dumps(response_json), code
@app.route("/xpath", methods=["POST"])
def xpath():
return process_xml(request, "xpath")
@app.route("/xsd", methods=["POST"])
def xsd():
return process_xml(request, "xsd")
@app.route("/xslt", methods=["POST"])
def xslt():
return process_xml(request, "xslt")
@app.route("/prettify", methods=["POST"])
def prettify():
return process_xml(request, "prettify")
@app.route("/minimize", methods=["POST"])
def minimize():
return process_xml(request, "minimize")
@app.route("/html/prettify",methods=["POST"])
def prettifyHtml():
return process_xml(request, "prettifyHtml")
@app.route("/html/minimize",methods=["POST"])
def minimizeHtml():
return process_xml(request, "minimizeHtml")
@app.route("/html/convert",methods=["POST"])
def XMLToHTMLConvertion():
return process_xml(request, "convertHTML")
if __name__ == "__main__":
app.run()

View File

@@ -0,0 +1,3 @@
lxml==4.9.2
flask==2.3.2
flask_cors==3.0.10

View File

@@ -0,0 +1,19 @@
FROM maven:3.6.3-jdk-14 as builder
WORKDIR application
COPY ./ ./
RUN mvn clean install
FROM openjdk:14 as layerBuilder
WORKDIR application
ARG JAR_FILE=application/target/*.jar
COPY --from=builder ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract
FROM openjdk:14
WORKDIR application
COPY --from=layerBuilder application/dependencies/ ./
COPY --from=layerBuilder application/spring-boot-loader/ ./
COPY --from=layerBuilder application/snapshot-dependencies/ ./
COPY --from=layerBuilder application/application/ ./
ENTRYPOINT ["java", "-Djava.security.cgd=file:/dev/./urandom", "-Dspring.profiles.active=DEV", "org.springframework.boot.loader.JarLauncher"]

View File

@@ -0,0 +1,48 @@
# R11-MockedServices
Mockup service for middleware testing.
Available scripts:
### Running the application on a local machine
For Intellij:
Plugins:
settings -> plugins -> install lombok plugin
settings -> annotation processors -> enable annotation processing
A connection to a Redis database is expected to run the application successfully. You need to download and run Redis DB on
your local machine with default values localhost 6379.
You can also run the application via Docker.
#### docker-compose up --build -d
However, you need either to run it with Docker-compose ensuring that all containers are within a network or start application locally.
In order to change environment two properties must be changed.
1) data-access.properties - property redis.host
2) logback.xml - configuration/appender/host element value
If application is to be run locally, both of above should be set to "localhost"
If application is to be run in docker environment, both should be set to name of a redis container (by default "redis")
Docker automaticly translates container name to IP address, considering all containers are within same network.
Try to avoid using any symbols in names of containers, because it may cause that URL exception to be thrown. Instead use letters only.
### Operations on Redis DB
Use Redis CLI or attach to Redis docker image in order to manually operate on DB.
#### docker exec -it mockedservices_redis-server redis-cli
Attach to redis server image and open a redis client.
Useful redis-cli commands:
###### KEYS *
Show all keys in the db.
###### TYPE key
Show key type.
###### LRANGE key start stop
Display elements from the list.
###### LLEN key
Display list length.
###### SMEMBERS key
Display elements from hashSet.
Logs can be found in lists with names logstash_yyyy-mm-dd.

View File

@@ -0,0 +1,20 @@
version: '3'
services:
redis:
image: 'redis'
restart: "no"
klaus:
build:
context: .
dockerfile: Dockerfile
container_name: klaus
restart: "no"
ports:
- "8097:8097"
depends_on:
- redis
environment:
SPRING_PROFILES_ACTIVE: DEV
networks:
default:
name: shared_network_mocked_services

View File

@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.11</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<artifactId>mocked-services</artifactId>
<properties>
<java.version>11</java.version>
<jedis.version>3.3.0</jedis.version>
<logback-redis-appender.version>1.1.6</logback-redis-appender.version>
<assertj.version>3.16.1</assertj.version>
<mapstruct.version>1.5.5.Final</mapstruct.version>
<docker.image.prefix>Release11</docker.image.prefix>
<docker.image.name>${project.artifactId}</docker.image.name>
<lombok.version>1.18.26</lombok.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layers>
<enabled>true</enabled>
<includeLayerTools>true</includeLayerTools>
</layers>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</dependency>
</annotationProcessorPaths>
<compilerArgs>
<compilerArg>-Amapstruct.defaultComponentModel=spring</compilerArg>
</compilerArgs>
<source>13</source>
<target>13</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,18 @@
package com.r11.tools;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* It's generic Spring context starter. Move along...
*
* @author Rafał Żukowicz
*/
@SpringBootApplication
public class KlausApplication {
public static void main(String[] args) {
SpringApplication.run(KlausApplication.class, args);
}
}

View File

@@ -0,0 +1,64 @@
package com.r11.tools.configuration;
import com.r11.tools.repository.MockedResponseRepository;
import com.r11.tools.repository.RequestHistoryRepository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import java.time.LocalDateTime;
/**
* Based on configuration deletes all outdated messages and history records from database.
*
* @author Mikołaj Widła
*/
@EnableScheduling
@EnableAsync
@Configuration
public class RetentionConfiguration {
private final MockedResponseRepository responseRepository;
private final RequestHistoryRepository historyRepository;
private final RetentionConfigurationProperties retentionProperties;
private final Logger log = LogManager.getRootLogger();
public RetentionConfiguration(MockedResponseRepository responseRepository,
RequestHistoryRepository historyRepository,
RetentionConfigurationProperties retentionProperties){
this.historyRepository = historyRepository;
this.responseRepository = responseRepository;
this.retentionProperties = retentionProperties;
}
@Scheduled(fixedDelayString = "#{${retention.retention-cooldown} * 60000 }")
@Async
public void deleteMessagesAndHistoryRecords(){
log.info("OUTDATED MESSAGES AND HISTORY RECORDS DELETED!");
responseRepository
.findAll()
.iterator()
.forEachRemaining( mockedMessage -> {
if (mockedMessage.getCreatedAt().plusMinutes(retentionProperties.getMinutesToDeleteMessage()).isBefore(LocalDateTime.now())){
responseRepository.delete(mockedMessage);
}
} );
historyRepository
.findAll()
.iterator()
.forEachRemaining(
historyRecord -> {
if (historyRecord.getDateTimeStamp().plusMinutes(retentionProperties.getMinutesToDeleteHistoryRecord()).isBefore(LocalDateTime.now())){
historyRepository.delete(historyRecord);
}
}
);
}
}

View File

@@ -0,0 +1,31 @@
package com.r11.tools.configuration;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import javax.validation.constraints.Positive;
/**
* Store all properties needed to change a retention in {@link RetentionConfiguration}
*
* @author Mikołaj Widła
*/
@Configuration
@ConfigurationProperties(prefix = "retention")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class RetentionConfigurationProperties {
@Positive
private Integer minutesToDeleteMessage;
@Positive
private Integer minutesToDeleteHistoryRecord;
@Positive
private Integer retentionCooldown;
}

View File

@@ -0,0 +1,28 @@
package com.r11.tools.configuration;
import com.r11.tools.interceptor.IncomingMockRequestInterceptor;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Configuration for {@link IncomingMockRequestInterceptor}
*
* @author Mikołaj Widła
*/
@Configuration
@AllArgsConstructor
public class WebConfig implements WebMvcConfigurer{
private final IncomingMockRequestInterceptor requestInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor( requestInterceptor )
.addPathPatterns("/api/mock/r/**");
}
}

View File

@@ -0,0 +1,80 @@
package com.r11.tools.controller;
import com.r11.tools.model.MockedMessageDto;
import com.r11.tools.service.KlausService;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.Objects;
import java.util.UUID;
/**
* Returns the homepage and provides the api for javascript async requests.
* @author Gabriel Modzelewski
* @author Mikołaj Widła
*/
@RestController
@RequestMapping(path = "/api/mock")
@AllArgsConstructor
@CrossOrigin(origins = "*")
public class MockController {
private final KlausService klausService;
private final Logger log = LogManager.getRootLogger();
@ExceptionHandler(Exception.class)
public void errorHandler(Exception ex){
log.error(Arrays.toString(ex.getStackTrace()));
}
/**
* Updates queried message with given set of data
* @param message {@link MockedMessageDto} json representation
* @return confirmation and 200 OK
*/
@SneakyThrows
@PutMapping
public ResponseEntity<String> updateMessage(@RequestBody MockedMessageDto message){
return klausService.setMockedResponse(message);
}
/**
* Returns the full list of messages. It's used by javascript on the client side to initialize homepage
* with data from the database.
* @param uuidValue the key-uuid of given set of messages
* @return responds with 200 OK and {@link MockedMessageDto}
*/
@GetMapping({"/", "/{uuidValue}"})
public MockedMessageDto getMessage(@PathVariable(required = false) String uuidValue){
UUID clientUUID;
MockedMessageDto message ;
if(uuidValue == null || uuidValue.equals("")) clientUUID = UUID.randomUUID();
else clientUUID = UUID.fromString(uuidValue);
message = klausService.getMockedResponse(clientUUID.toString());
return message;
}
/**
* It's one of the most important features - the bread and butter of the Mocked Service. It's link that allows
* to receive mocked response from the server and use it to mock!
* @param clientUUID the key-uuid of given set of messages
* @return
*/
@RequestMapping(value = "/r/{clientUUID}")
public ResponseEntity getMockedResponse(
@PathVariable String clientUUID) {
MockedMessageDto mockedMessageDto = klausService.getMockedResponse(clientUUID);
HttpHeaders httpHeaders = new HttpHeaders();
if (mockedMessageDto.getHttpHeaders() != null) mockedMessageDto.getHttpHeaders().forEach(httpHeaders::set);
httpHeaders.add("Content-Type", mockedMessageDto.getContentType());
return new ResponseEntity<>(mockedMessageDto.getMessageBody(), httpHeaders,
Objects.requireNonNull(HttpStatus.valueOf(mockedMessageDto.getHttpStatus())));
}
}

View File

@@ -0,0 +1,49 @@
package com.r11.tools.controller;
import java.util.ArrayList;
import java.util.List;
import javax.validation.ConstraintViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.ExceptionHandler;
/**
* Custom exception handler for {@link ConstraintViolationException}
* @author Rafał Żukowicz
*/
@ControllerAdvice
@CrossOrigin(origins = "*")
public class MvcExceptionHandler {
/**
* Provides handling for {@link ConstraintViolationException}
* @param e exception argument
* @return response with error list and status 400 bad request
*/
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<List> validationErrorHandler(ConstraintViolationException e){
List<String> errors = new ArrayList<>(e.getConstraintViolations().size());
e.getConstraintViolations().forEach(constraintViolation -> {
errors.add(constraintViolation.getPropertyPath() + " : " + constraintViolation.getMessage());
});
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
/**
* Provides handling for {@link BindException}
* @param ex exception argument
* @return response with error list and status 400 bad request
*/
@ExceptionHandler(BindException.class)
public ResponseEntity<List> handleBindException(BindException ex){
return new ResponseEntity(ex.getAllErrors(), HttpStatus.BAD_REQUEST);
}
}

View File

@@ -0,0 +1,42 @@
package com.r11.tools.controller;
import com.r11.tools.mappers.RequestHistoryMapper;
import com.r11.tools.model.RequestHistory;
import com.r11.tools.model.RequestHistoryDTO;
import com.r11.tools.service.RequestHistoryService;
import lombok.AllArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
/**
* It's the REST api for {@link RequestHistory}
* @author Gabriel Modzelewski
* @author Mikołaj Widła
*/
@RestController
@RequestMapping(path = "/api/event")
@AllArgsConstructor
@CrossOrigin(origins = "*")
public class RequestHistoryController {
private final RequestHistoryService service;
private final RequestHistoryMapper mapper;
/**
* Returns the list of Events.
* @param uuid unique id of message list
* @return list of {@link RequestHistory}
*/
@GetMapping(path = "/{uuid}")
public ResponseEntity<List<RequestHistoryDTO>> getLastDay(@PathVariable String uuid){
List<RequestHistoryDTO> requestHistory = service.getHistoryRecordsByUUID(
uuid
).stream()
.map(mapper::requestHistoryToRequestHistoryDTO)
.collect(Collectors.toList());
return ResponseEntity.ok(requestHistory);
}
}

View File

@@ -0,0 +1,78 @@
package com.r11.tools.interceptor;
import com.r11.tools.model.RequestHistoryDTO;
import com.r11.tools.service.RequestHistoryService;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.util.ContentCachingRequestWrapper;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
/**
* Interceptor that gets needed data from HttpRequest, and saves it to history
* @author Mikołaj Widła
*/
@Component
@AllArgsConstructor
public class IncomingMockRequestInterceptor implements HandlerInterceptor {
private final RequestHistoryService historyService;
@Override
public boolean preHandle(HttpServletRequest httpRequest, HttpServletResponse response, Object handler){
Map<String,String> headers = getHeadersFromHttpRequest(httpRequest);
Map<String,String> pathVariable = getPathVariablesFromHttpRequest(httpRequest);
String requestBody = getRequestBodyFromHttpRequest(httpRequest);
RequestHistoryDTO historyDTO = RequestHistoryDTO.builder()
.httpMethod(HttpMethod.valueOf(httpRequest.getMethod()))
.headers( headers )
.clientUUID(UUID.fromString(pathVariable.get("clientUUID")))
.dateTimeStamp(LocalDateTime.now())
.requestBody(requestBody)
.build();
historyService.saveRequest(historyDTO);
return true;
}
private Map<String,String> getHeadersFromHttpRequest( HttpServletRequest httpRequest ){
Set<String> headersName = StreamSupport.stream(
Spliterators.spliteratorUnknownSize(
httpRequest.getHeaderNames().asIterator(),
Spliterator.ORDERED
), false
).collect(Collectors.toSet());
return headersName.stream()
.collect(Collectors.toMap(
value -> value,
httpRequest::getHeader
));
}
private Map<String,String> getPathVariablesFromHttpRequest( HttpServletRequest httpRequest ){
return (Map<String, String>) httpRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
}
private String getRequestBodyFromHttpRequest( HttpServletRequest httpRequest ){
HttpServletRequest wrappedRequest = new ContentCachingRequestWrapper(httpRequest);
try {
return StreamUtils.copyToString(wrappedRequest.getInputStream(), Charset.defaultCharset());
} catch (IOException e) {
return "";
}
}
}

View File

@@ -0,0 +1,26 @@
package com.r11.tools.mappers;
import com.r11.tools.model.MockedMessage;
import com.r11.tools.model.MockedMessageDto;
import org.mapstruct.*;
import java.util.Optional;
/**
* Creates key value for redis entry
* @author Rafał Źukowicz
*/
@Mapper
public interface MockedMessageMapper {
@Mapping( target = "createdAt" , expression = "java(java.time.LocalDateTime.now())")
MockedMessage mockedMessageDtoToMockedMessage(MockedMessageDto mockedMessageDto);
MockedMessageDto mockedMessageToMockedMessageDto(MockedMessage mockedMessage);
default Optional<MockedMessageDto> optionalMockedMessageToOptionalMockedMessageDTO(Optional<MockedMessage> optionalMockedMessage){
return optionalMockedMessage.map(this::mockedMessageToMockedMessageDto);
}
default Optional<MockedMessage> optionalMockedMessageDTOToOptionalMockedMessage(Optional<MockedMessageDto> optionalMockedMessageDto){
return optionalMockedMessageDto.map(this::mockedMessageDtoToMockedMessage);
}
}

View File

@@ -0,0 +1,23 @@
package com.r11.tools.mappers;
import com.r11.tools.model.RequestHistory;
import com.r11.tools.model.RequestHistoryDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
/**
* Map between DTO and Entity
*
* @author Mikołaj Widła
*
*/
@Mapper
public interface RequestHistoryMapper {
@Mapping(target = "clientUUID", expression = "java(requestHistoryDTO.getClientUUID().toString())")
RequestHistory requestHistoryDTOToRequestHistory(RequestHistoryDTO requestHistoryDTO);
@Mapping(target = "clientUUID", expression = "java(java.util.UUID.fromString(requestHistory.getClientUUID()))")
RequestHistoryDTO requestHistoryToRequestHistoryDTO(RequestHistory requestHistory);
}

View File

@@ -0,0 +1,37 @@
package com.r11.tools.model;
import com.r11.tools.model.constraints.HttpCode;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.index.Indexed;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;
/**
* MockedMessage redis entity pojo
* @author Rafał Żukowicz
*/
@Data
@ToString
@RedisHash("mockedMessage")
@NoArgsConstructor
@AllArgsConstructor
public class MockedMessage implements Serializable {
@Indexed
@Id
private String clientUUID;
private String contentType;
private String messageBody;
private Map<String, String> httpHeaders;
@HttpCode
private Integer httpStatus;
private LocalDateTime createdAt;
}

View File

@@ -0,0 +1,28 @@
package com.r11.tools.model;
import com.r11.tools.model.constraints.HttpCode;
import lombok.*;
import java.io.Serializable;
import java.util.Map;
import java.util.UUID;
/**
* Alternative version of {@link MockedMessage} used in http body
* @author Rafał Żukowicz
* @author Gabriel Modzelewski
*/
@Data
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class MockedMessageDto implements Serializable{
private String clientUUID;
private String contentType;
private String messageBody;
private Map<String, String> httpHeaders;
@HttpCode
private Integer httpStatus;
}

View File

@@ -0,0 +1,42 @@
package com.r11.tools.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.index.Indexed;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpMethod;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Map;
/**
* Pojo class for Event entity
* @author Rafał Żukowicz
* @author Mikołaj Widła
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@RedisHash("mockHistory")
public class RequestHistory implements Comparable<RequestHistory>, Serializable {
@Id
private String id;
@DateTimeFormat(pattern = "yyyy-MM-ddTHH:mm:ss")
private LocalDateTime dateTimeStamp;
@Indexed
private String clientUUID;
private Map<String,String> headers;
private HttpMethod httpMethod;
private String requestBody;
@Override
public int compareTo(RequestHistory o) {
return this.getDateTimeStamp().compareTo(o.getDateTimeStamp()) * -1;
}
}

View File

@@ -0,0 +1,32 @@
package com.r11.tools.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpMethod;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;
/**
* Pojo for history query request. Contains information necessary to obtain {@link RequestHistory} list
* @author Rafał Żukowicz
* @author Mikołaj Widła
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RequestHistoryDTO {
private UUID clientUUID;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDateTime dateTimeStamp;
private Map<String,String> headers;
private HttpMethod httpMethod;
private String requestBody;
}

View File

@@ -0,0 +1,23 @@
package com.r11.tools.model.constraints;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
/**
* Annotation interface that is used to annotate Integer fields that contain http status values.
* It provides validation and throws an error when trying to send response with incorrect status.
* @author Rafał Żukowicz
*/
@Target({ ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = HttpCodeValidation.class )
public @interface HttpCode {
String message() default "must be a valid http code";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}

View File

@@ -0,0 +1,39 @@
package com.r11.tools.model.constraints;
import com.r11.tools.model.MockedMessage;
import com.r11.tools.model.MockedMessageDto;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.springframework.http.HttpStatus;
/**
* It's validator class. It checks if status value of {@link MockedMessageDto} is within bonds of http status values map.
* @author Rafał Żukowicz
*/
public class HttpCodeValidation implements ConstraintValidator<HttpCode, Integer> {
private Set<Integer> allowedValues;
/**
* Initializes {@link #allowedValues} with possible http status values.
* @param targetEnum HttpCode context
*/
@Override
public void initialize(HttpCode targetEnum) {
allowedValues = Stream.of(HttpStatus.values())
.map(HttpStatus::value)
.collect(Collectors.toSet());
}
/**
* @param integer value of {@link MockedMessageDto#getHttpStatus()} or {@link MockedMessage#getHttpStatus()}
* @param context context for validation
* @return true if valid
*/
@Override
public boolean isValid(Integer integer, ConstraintValidatorContext context) {
return allowedValues.contains(integer);
}
}

View File

@@ -0,0 +1,16 @@
package com.r11.tools.repository;
import com.r11.tools.model.MockedMessage;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
/**
* Spring repository that allows to retrieve message list by key-uuid from redis database
* @author Rafał Żukowicz
*/
@Repository
@Transactional
public interface MockedResponseRepository extends CrudRepository<MockedMessage, String> {}

View File

@@ -0,0 +1,18 @@
package com.r11.tools.repository;
import com.r11.tools.model.RequestHistory;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* History Record entity dao interface
* @author Rafał Żukowicz
*/
@Repository
@Transactional
public interface RequestHistoryRepository extends CrudRepository<RequestHistory,String> {
List<RequestHistory> findAllByClientUUID(String clientUUID);
}

View File

@@ -0,0 +1,18 @@
package com.r11.tools.service;
import com.r11.tools.model.MockedMessageDto;
import java.util.Optional;
import java.util.UUID;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
/**
* Service interface for {@link com.r11.tools.controller.KlausController} and {@link com.r11.tools.controller.MockController}
* @author Rafał Żukowicz
*/
@Service
public interface KlausService {
MockedMessageDto getMockedResponse(String clientUUID);
ResponseEntity<String> setMockedResponse(MockedMessageDto mockedMessageDto);
}

View File

@@ -0,0 +1,100 @@
package com.r11.tools.service;
import com.r11.tools.mappers.MockedMessageMapper;
import com.r11.tools.model.MockedMessage;
import com.r11.tools.model.MockedMessageDto;
import com.r11.tools.repository.MockedResponseRepository;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/**
* Service for {@link com.r11.tools.controller.MockController} and {@link com.r11.tools.controller.MockController}
* Allows for performing CRUD operations on {@link MockedMessageDto}
* @author Rafał Żukowicz
* @author Gabriel Modzelewski
* @author Mikołaj Widła
*/
@Service
@AllArgsConstructor
public class KlausServiceImpl implements KlausService {
private final MockedMessageMapper mockedMessageMapper;
private final Logger log = LogManager.getRootLogger();
private final MockedResponseRepository mockedResponseRepository;
/**
* Returns {@link MockedMessageDto} of given id and key-uuid. If message doesn't then empty message is returned
* @param clientUUID the key-uuid of given set of messages
* @return {@link MockedMessageDto} object
*/
@SneakyThrows
@Override
public MockedMessageDto getMockedResponse(String clientUUID){
Optional<MockedMessage> optionalMockedMessage = mockedResponseRepository.findById(clientUUID);
MockedMessageDto mockedMessageDto;
if (optionalMockedMessage.isPresent()) {
mockedMessageDto = mockedMessageMapper.mockedMessageToMockedMessageDto(optionalMockedMessage.get());
return mockedMessageDto;
} else {
MockedMessageDto defaultMessage = buildDefaultMessage(clientUUID);
setMockedResponse(defaultMessage);
return defaultMessage;
}
}
/**
* Constructs message with default set of data
* @param uuid the key-uuid of given set of messages
* @return message with default dataset
*/
private MockedMessageDto buildDefaultMessage(String uuid){
Map<String, String> headers = new HashMap<>();
headers.put("Keep-Alive", "timeout=60");
headers.put("Connection", "keep-alive");
headers.put("Date", LocalDateTime.now().toString());
return MockedMessageDto.builder()
.clientUUID(uuid)
.contentType(MediaType.APPLICATION_XML_VALUE)
.messageBody("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<note>\n" +
" <to>Tove</to>\n" +
" <from>Jani</from>\n" +
" <heading>Reminder</heading>\n" +
" <body>Don't forget me this weekend!</body>\n" +
"</note>")
.httpHeaders(headers)
.httpStatus(200)
.build();
}
/**
* Allows to modify mocked message. If message of given id and key-uuid doesn't exist a new entry is created
* @param mockedMessageDto message to be saved
* @return Confirmation and status 200 OK
*/
@SneakyThrows
@Override
public ResponseEntity<String> setMockedResponse(MockedMessageDto mockedMessageDto) {
MockedMessage message = mockedMessageMapper.mockedMessageDtoToMockedMessage(mockedMessageDto);
message.setCreatedAt(LocalDateTime.now());
log.info("SAVE:"+message.toString().replace("\n"," "));
mockedResponseRepository.save(message);
return new ResponseEntity<>("MockedResponse has been setup successfully!", new HttpHeaders(),
HttpStatus.ACCEPTED);
}
}

View File

@@ -0,0 +1,23 @@
package com.r11.tools.service;
import com.r11.tools.controller.RequestHistoryController;
import com.r11.tools.model.RequestHistory;
import com.r11.tools.model.RequestHistoryDTO;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* Spring service interface for {@link RequestHistoryController}
* @author Rafał Żukowicz
*/
@Service
public interface RequestHistoryService {
/**
* Searches for {@link RequestHistory} objects between date brackets
* @param uuid user uuid
* @return list of {@link RequestHistory}
*/
List<RequestHistory> getHistoryRecordsByUUID(String uuid);
void saveRequest(RequestHistoryDTO requestDTO);
}

View File

@@ -0,0 +1,38 @@
package com.r11.tools.service;
import com.r11.tools.controller.RequestHistoryController;
import com.r11.tools.mappers.RequestHistoryMapper;
import com.r11.tools.model.RequestHistory;
import com.r11.tools.model.RequestHistoryDTO;
import com.r11.tools.repository.RequestHistoryRepository;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
/**
* Spring Service for {@link RequestHistoryController}. Contains logic required for quering
* the database for {@link RequestHistory} objects
* @author Rafał Żukowicz
* @author Mikołaj Widła
*/
@Service
@AllArgsConstructor
public class RequestHistoryServiceImpl implements RequestHistoryService {
private final RequestHistoryRepository repository;
private final RequestHistoryMapper requestMapper;
@Override
public List<RequestHistory> getHistoryRecordsByUUID(String uuid) {
List<RequestHistory> history = repository.findAllByClientUUID(uuid);
Collections.sort(history);
return history;
}
@Override
public void saveRequest(RequestHistoryDTO requestDTO) {
repository.save(requestMapper.requestHistoryDTOToRequestHistory(requestDTO));
}
}

View File

@@ -0,0 +1,16 @@
#environment:
server.port = 8097
spring.application.name = klaus
spring.mvc.view.suffix=.html
logging.level.root=INFO
logging.level.org.springframework.web=INFO
logging.level.com.release11=INFO
#database:
spring.redis.host=redis
spring.redis.port=6379
#retention
retention.minutes-to-delete-message=1440
retention.minutes-to-delete-history-record=1440
retention.retention-cooldown=1440

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<property name="HOME_LOG" value="/log/mockServices.log"/>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${HOME_LOG}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/mockServices.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>10MB</maxFileSize>
<totalSizeCap>20GB</totalSizeCap>
<maxHistory>60</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
</configuration>

25
Backend/pom.xml Normal file
View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.r11.tools</groupId>
<artifactId>release11-tools</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jackson.version>2.14.1</jackson.version>
<slf4j.version>2.0.6</slf4j.version>
</properties>
<packaging>pom</packaging>
<modules>
<module>tools-services</module>
<module>mocked-services</module>
</modules>
</project>

View File

@@ -1,10 +1,10 @@
# Using maven image, based on java 8
FROM maven:3.6.3-jdk-8 as target
WORKDIR /build
COPY pom.xml .
COPY src/ /build/src/
WORKDIR build
COPY ./ ./
RUN mvn -ntp package
# Go to working directory in docker image
# WORKDIR /usr/app/

View File

@@ -0,0 +1,128 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.r11.tools</groupId>
<artifactId>tools-services</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jackson.version>2.14.1</jackson.version>
<slf4j.version>2.0.6</slf4j.version>
<log4j.version>2.19.0</log4j.version>
<gson.version>2.10.1</gson.version>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.r11.tools.SparkInitializer</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Spark -->
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>2.9.4</version>
</dependency>
<!-- JSON -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
<!-- XSLT -->
<dependency>
<groupId>net.sf.saxon</groupId>
<artifactId>Saxon-HE</artifactId>
<version>11.4</version>
</dependency>
<dependency>
<groupId>xalan</groupId>
<artifactId>xalan</artifactId>
<version>2.7.2</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,52 @@
package com.r11.tools;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.r11.tools.controller.*;
import com.r11.tools.controller.internal.RestControllerRegistry;
import com.r11.tools.xml.Saxon;
import com.r11.tools.xml.Xalan;
import com.r11.tools.xml.XmlEngine;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import spark.Spark;
public class SparkApplication {
public static void run() {
// TODO: read port from config
Spark.port(8081);
Spark.after((request, response) -> {
response.header("Access-Control-Allow-Origin", "*");
response.header("access-control-allow-headers", "*");
response.header("access-control-expose-headers", "*");
response.header("Access-Control-Allow-Methods", "POST");
});
Logger logger = LogManager.getLogger(SparkApplication.class);
Gson gson = new GsonBuilder()
.disableHtmlEscaping()
.setPrettyPrinting()
.create();
Gson jsongson = new GsonBuilder()
.disableHtmlEscaping()
.create();
XmlEngine saxon = new Saxon();
XmlEngine xalan = new Xalan();
RestControllerRegistry registry = new RestControllerRegistry();
registry.registerController(new ProcessorInfoController(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.register();
logger.info("Server is online at port: " + Spark.port());
}
}

View File

@@ -0,0 +1,7 @@
package com.r11.tools;
public class SparkInitializer {
public static void main(String[] args) {
SparkApplication.run();
}
}

View File

@@ -0,0 +1,85 @@
package com.r11.tools.controller;
import com.google.gson.*;
//import com.google.gson.GsonBuilder;
import com.r11.tools.controller.internal.GlobalControllerManifest;
import com.r11.tools.controller.internal.HandlerType;
import com.r11.tools.controller.internal.RestController;
import com.r11.tools.controller.internal.ScopedControllerManifest;
import spark.Request;
import spark.Response;
import org.apache.logging.log4j.Logger;
import java.util.List;
import java.util.Map;
@GlobalControllerManifest(path = "/json")
public class JsonController implements RestController {
private final Logger logger;
private final Gson prettyGson;
private final Gson gson;
public JsonController(Gson prettyGson, Gson jsongson,Logger logger) {
this.logger = logger;
this.prettyGson = prettyGson;
this.gson = jsongson;
}
@ScopedControllerManifest(method = HandlerType.POST, path = "/formatting")
public void formatting(Request request, Response response) {
long startProcess = System.currentTimeMillis();
JsonObject responseJson = new JsonObject();
try {
Object requestJson = this.gson.fromJson(request.body(), Object.class);
responseJson.addProperty("result", this.prettyGson.toJson(requestJson));
responseJson.addProperty("time", System.currentTimeMillis() - startProcess);
} catch (Exception e) {
this.logger.error("Error on formatting Json " + e);
Throwable cause = e.getCause();
response.status(400);
responseJson.addProperty("result", cause == null ? e.getMessage() : cause.getMessage());
responseJson.addProperty("time", System.currentTimeMillis() - startProcess);
}
this.logger.info("Json processed in " + responseJson.get("time").toString() + " ms.");
response.body(this.prettyGson.toJson(responseJson));
}
@ScopedControllerManifest(method = HandlerType.POST, path = "/minimize")
public void minimize(Request request, Response response) {
long startProcess = System.currentTimeMillis();
JsonObject responseJson = new JsonObject();
try {
Object requestJson = this.prettyGson.fromJson(request.body(), Object.class);
response.status(200);
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 minimizing Json " + e);
Throwable cause = e.getCause();
response.status(400);
responseJson.addProperty("result", cause == null ? e.getMessage() : cause.getMessage());
responseJson.addProperty("time", System.currentTimeMillis() - startProcess);
response.body(this.prettyGson.toJson(responseJson));
}
this.logger.info("Json processed in " + responseJson.get("time").toString() + " ms.");
}
}

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

@@ -0,0 +1,39 @@
package com.r11.tools.controller;
import com.r11.tools.controller.internal.GlobalControllerManifest;
import com.r11.tools.controller.internal.HandlerType;
import com.r11.tools.controller.internal.RestController;
import com.r11.tools.controller.internal.ScopedControllerManifest;
import com.r11.tools.xml.Saxon;
import com.r11.tools.xml.XmlEngine;
import org.apache.logging.log4j.Logger;
import spark.Request;
import spark.Response;
@GlobalControllerManifest
public class ProcessorInfoController implements RestController {
private final Logger logger;
private final XmlEngine saxon;
private final XmlEngine xalan;
public ProcessorInfoController(Logger logger, XmlEngine saxon, XmlEngine xalan) {
this.logger = logger;
this.saxon = saxon;
this.xalan = xalan;
}
/**
* Handler that returns processor version
*/
@ScopedControllerManifest(method = HandlerType.GET, path = "/procinfo")
public void processorInfo(Request request, Response response) {
try {
response.header("processor", "Saxon " + saxon.getVersion() + " over s9api");
response.body(saxon.getVersion());
} catch (Exception ex) {
this.logger.error("Error on retrieving engine version. " + ex);
response.body(ex.getMessage());
}
}
}

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

@@ -0,0 +1,14 @@
package com.r11.tools.controller.internal;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface GlobalControllerManifest {
String path() default "";
}

View File

@@ -0,0 +1,7 @@
package com.r11.tools.controller.internal;
public enum HandlerType {
GET, POST, PUT, DELETE
}

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,5 @@
package com.r11.tools.controller.internal;
public interface RestController {
}

View File

@@ -0,0 +1,59 @@
package com.r11.tools.controller.internal;
import com.r11.tools.controller.internal.path.PathBuilder;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import spark.Spark;
public class RestControllerRegistry {
private final Set<RestController> registeredControllers;
public RestControllerRegistry() {
this.registeredControllers = new HashSet<>();
}
public void registerController(RestController restController) {
this.registeredControllers.add(restController);
}
public void register() {
this.registeredControllers.forEach(controller -> {
if (controller.getClass().isAnnotationPresent(GlobalControllerManifest.class)) {
for (Method method : controller.getClass().getMethods()) {
this.registerAssignableHandlers(controller.getClass(), controller, method);
}
}
});
}
private void registerAssignableHandlers(Class<? extends RestController> parent, RestController parentValue, Method method) {
if (
(parent.isAnnotationPresent(GlobalControllerManifest.class)) &&
(method.isAnnotationPresent(ScopedControllerManifest.class))
) {
HandlerType handlerType = method.getAnnotation(ScopedControllerManifest.class).method();
String path = PathBuilder.resolvePathOf(
parent.getAnnotation(GlobalControllerManifest.class).path(),
method.getAnnotation(ScopedControllerManifest.class).path()
);
switch (handlerType) {
case GET:
Spark.get(path, (request, response) -> method.invoke(parentValue, request, response));
break;
case PUT:
Spark.put(path, (request, response) -> method.invoke(parentValue, request, response));
break;
case POST:
Spark.post(path, (request, response) -> method.invoke(parentValue, request, response));
break;
case DELETE:
Spark.delete(path, (request, response) -> method.invoke(parentValue, request, response));
break;
}
}
}
}

View File

@@ -0,0 +1,15 @@
package com.r11.tools.controller.internal;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ScopedControllerManifest {
HandlerType method();
String path();
}

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,30 @@
package com.r11.tools.controller.internal.path;
public final class PathBuilder {
private static final String PATH_SEPARATOR = "/";
private PathBuilder() {
}
public static String resolvePathOf(String globalPath, String scopedPath) {
String resolvedPath =
PathBuilder.removeTrailingPathSeparator(globalPath) +
PathBuilder.removeTrailingPathSeparator(scopedPath);
if (resolvedPath.endsWith(PATH_SEPARATOR)) {
resolvedPath = resolvedPath.substring(0, resolvedPath.length() - 1);
}
return PATH_SEPARATOR + resolvedPath;
}
private static String removeTrailingPathSeparator(String path) {
if (path.endsWith(PATH_SEPARATOR)) {
return path.substring(0, path.length() - 1);
}
return path;
}
}

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

@@ -0,0 +1,34 @@
package com.r11.tools.model;
import com.google.gson.annotations.SerializedName;
/**
* POJO class used to contain body of XML related requests
* @author Adam Bem
*/
public class XMLRequestBody {
@SerializedName("data")
private String data;
@SerializedName("processorData")
private String processorData;
@SerializedName("processor")
private String processor;
@SerializedName("version")
private String version;
public String getData() {
return data;
}
public String getProcessorData() {
return processorData;
}
public String getProcessor() {
return processor;
}
public String getVersion() {
return version;
}
}

View File

@@ -0,0 +1,71 @@
package com.r11.tools.model;
public class XMLResponseBody {
private String result;
private String status;
private String processor;
private long duration;
// Optional
private String type;
public XMLResponseBody(String result, String status, String processor) {
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;
this.processor = processor;
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;
}
public void setResult(String result) {
this.result = result;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getProcessor() {
return processor;
}
public void setProcessor(String processor) {
this.processor = processor;
}
public long getDuration() {
return duration;
}
public void setDuration(long duration) {
this.duration = duration;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}

View File

@@ -0,0 +1,22 @@
package com.r11.tools.model;
/**
* Class used to store data received from parser and type of that data (node, string, etc.)
*/
public class XPathQueryResult {
private String data;
private String type;
public XPathQueryResult(String data, String type) {
this.data = data;
this.type = type;
}
public String getData() {
return data;
}
public String getType() {
return type;
}
}

View File

@@ -1,11 +1,10 @@
package r11.mltx.restxslt.processors;
package com.r11.tools.xml;
import net.sf.saxon.om.NamespaceBinding;
import net.sf.saxon.om.NamespaceMap;
import net.sf.saxon.s9api.XPathCompiler;
import net.sf.saxon.s9api.XdmNode;
import java.util.Iterator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Handler for saxon namespace scan engine.
@@ -13,6 +12,7 @@ import java.util.Iterator;
* @author Wojciech Czop
*/
public class NewNamespaceResolver {
private static final Logger LOG = LogManager.getLogger("NewNamespaceResolver");
private NamespaceMap namespaceMap;
@@ -21,12 +21,13 @@ public class NewNamespaceResolver {
* @param doc dom structure object
* @return map of namespaces
*/
// TODO: Closer inspection. Return value is never used according to IntelliJ
//
public NamespaceMap process(XdmNode doc) {
namespaceMap = NamespaceMap.emptyMap();
Iterator<XdmNode> it = doc.children().iterator();
// TODO: remove
while (it.hasNext()) {
XdmNode tmp = it.next();
// TODO: remove
for (XdmNode tmp : doc.children()) {
extractNamespace(tmp);
}
// end
@@ -38,12 +39,6 @@ public class NewNamespaceResolver {
* @param compiler compiler used to compile xpath statements
*/
public void exportNamespaces(XPathCompiler compiler){
Iterator<NamespaceBinding> it = namespaceMap.iterator();
// TODO: remove
while(it.hasNext()){
System.out.println(it.next());
}
// end
namespaceMap.forEach(namespaceBinding -> compiler.declareNamespace(namespaceBinding.getPrefix(), namespaceBinding.getURI()));
}
@@ -58,17 +53,11 @@ public class NewNamespaceResolver {
}
if (node.children().iterator().hasNext()) {
Iterator<XdmNode> it = node.children().iterator();
while (it.hasNext()) {
XdmNode rNode = it.next();
// TODO: remove
if(rNode.getUnderlyingNode().getPrefix().isEmpty() && !rNode.getParent().getUnderlyingNode().getPrefix().isEmpty()){
System.out.println("prefix missing, parent has "+rNode.getParent().getUnderlyingNode().getPrefix() + ", but child has none");
System.out.println();
for (XdmNode rNode : node.children()) {
if (rNode.getUnderlyingNode().getPrefix().isEmpty() && !rNode.getParent().getUnderlyingNode().getPrefix().isEmpty()) {
LOG.warn("Missing prefix. Parent has " + rNode.getParent().getUnderlyingNode().getPrefix() + ", but child has none");
}
// end
extractNamespace(rNode);
}
}

View File

@@ -0,0 +1,167 @@
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.*;
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
* @author Wojciech Czop
*/
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
* @param transform xslt
* @return transformed xml
* @throws SaxonApiException thrown on stylesheet or transformation errors
*/
public String processXSLT(String data, String transform) throws SaxonApiException {
Processor processor = new Processor(false);
XsltCompiler compiler = processor.newXsltCompiler();
XsltExecutable stylesheet = compiler.compile(new StreamSource(new StringReader(transform)));
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 StringReader(data)), out);
return sw.toString();
}
@Override
public String validate(String data, String xsd) {
throw new UnsupportedOperationException();
}
/**
* This method evaluates XQuery expression on given xml
* @param data xml
* @param xquery expression
* @return
* @throws Exception
*/
@Override
public String executeXQuery(String data, String xquery, String version) throws Exception {
Processor processor = new Processor(false);
XQueryCompiler compiler = processor.newXQueryCompiler();
compiler.setLanguageVersion(version);
XQueryExecutable executable = compiler.compile(xquery);
XQueryEvaluator evaluator = executable.load();
evaluator.setSource(new StreamSource(new StringReader(data)));
XdmValue result = evaluator.evaluate();
return result.toString();
}
/**
* Process xpath and return either node or wrapped atomic value
* @param data xml to be 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
*/
public XPathQueryResult processXPath(String data, String query, String version) throws Exception {
Processor p = new Processor(false);
XPathCompiler compiler = p.newXPathCompiler();
DocumentBuilder builder = p.newDocumentBuilder();
XdmNode doc = builder.build(new StreamSource(new StringReader(data)));
compiler.setLanguageVersion(version);
NewNamespaceResolver resolver = new NewNamespaceResolver();
resolver.process(doc);
resolver.exportNamespaces(compiler);
XdmValue result = compiler.evaluate(query, doc);
StringBuilder sb = new StringBuilder();
for (XdmItem xdmItem : result) {
sb.append(xdmItem);
sb.append('\n');
}
return new XPathQueryResult(sb.toString(), "N/A");
}
/**
* Returns version of the processor
* @return version of the processor
*/
public String getVersion() {
return "Saxon " + new Processor(false).getSaxonProductVersion();
}
}

View File

@@ -0,0 +1,149 @@
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;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.NodeIterator;
import org.xml.sax.InputSource;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.StringWriter;
/**
* Handler for Xalan engine
* @author Wojciech Czop
*/
public class Xalan implements XmlEngine{
/**
* Transforms string containing xml document via xslt
* @param data xml to be transformed
* @param transform xslt
* @return transformed xml
* @throws Exception thrown on stylesheet or transformation errors
*/
public String processXSLT(String data, String transform) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new InputSource(new StringReader(data)));
StreamSource stylesource = new StreamSource(new StringReader(transform));
Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource);
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
Source source = new DOMSource(document);
StringWriter sw = new StringWriter();
Result outputTarget = new StreamResult(sw);
transformer.transform(source, outputTarget);
return sw.toString();
}
private boolean isTextNode(Node n) {
if (n == null)
return false;
short nodeType = n.getNodeType();
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
* @param transform xpath
* @return xml processed using given xpath
* @throws Exception thrown on node building errors or invalid xpath
*/
public XPathQueryResult processXPath(String data, String transform, String version) throws Exception {
// 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);
// 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.
try {
NodeIterator nl = XPathAPI.selectNodeIterator(doc, transform);
// Serialize the found nodes to result object.
StringBuilder resultString = 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()) {
resultString.append(nn.getNodeValue());
}
} else {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
serializer.transform(new DOMSource(n), new StreamResult(new OutputStreamWriter(outputStream)));
resultString.append(outputStream);
}
resultString.append("\n");
}
return new XPathQueryResult(resultString.toString(), "node");
} catch (TransformerException e) {
String returnData = XPathAPI.eval(doc, transform).toString();
return new XPathQueryResult(returnData, "string");
}
}
/**
* Returns version of the processor
* @return version of the processor
*/
public String getVersion(){
return org.apache.xalan.Version.getVersion();
}
/**
* Validates string representation of the xml document against xsd schema
* @param data xml document
* @param xsd xsd schema
* @return statement of validity
* @throws Exception thrown on invalid xsd schema or xml
*/
public String validate(String data, String xsd) throws Exception {
Source dataSource = new StreamSource(new StringReader(data));
Source xsdSource = new StreamSource(new StringReader(xsd));
SchemaFactory schemaFactory = SchemaFactory
.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(xsdSource);
Validator validator = schema.newValidator();
validator.validate(dataSource);
return "XML file is valid";
}
@Override
public String executeXQuery(String data, String xquery, String version) throws Exception {
throw new UnsupportedOperationException("Xalan doesn't support XQuery evaluation");
}
}

View File

@@ -1,4 +1,4 @@
package r11.mltx.restxslt.processors;
package com.r11.tools.xml;
import org.w3c.dom.*;

View File

@@ -0,0 +1,17 @@
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;
String executeXQuery(String data, String xquery, String version) throws Exception;
public String getVersion();
}

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%c] %-5level - %msg%n"/>
</Console>
<File name="File" fileName="/tmp/xml_tools_java_backend.log" append="true">
<PatternLayout>
<Pattern>%d{HH:mm:ss.SSS} [%c] %-5level - %msg%n</Pattern>
</PatternLayout>
</File>
</Appenders>
<Loggers>
<Logger name="com.r11.tools.SparkApplication" level="info" additivity="true">
<AppenderRef ref="Console"/>
</Logger>
<Root level="info">
<AppenderRef ref="File"/>
</Root>
</Loggers>
</Configuration>

2
Filebeat/Dockerfile Normal file
View File

@@ -0,0 +1,2 @@
FROM docker.elastic.co/beats/filebeat:8.6.2
COPY --chown=root:filebeat filebeat.docker.yml /usr/share/filebeat/filebeat.yml

View File

@@ -0,0 +1,21 @@
filebeat.config:
modules:
path: ${path.config}/modules.d/*.yml
reload.enabled: false
filebeat.autodiscover:
providers:
- type: docker
hints.enabled: true
processors:
- add_cloud_metadata: ~
output.elasticsearch:
hosts: '${ELASTICSEARCH_HOSTS:elc-0.zipper.release11.com:9200}'
index: 'xmltools-${ENV_TYPE:dev}-%{+YYYY.MM}'
setup.template:
name: "xmltools"
pattern: "xmltools-*"

28
Frontend/.dockerignore Normal file
View File

@@ -0,0 +1,28 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

15
Frontend/.eslintrc.cjs Normal file
View File

@@ -0,0 +1,15 @@
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true,
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier/skip-formatting'
],
parserOptions: {
ecmaVersion: 'latest'
}
}

28
Frontend/.gitignore vendored Normal file
View File

@@ -0,0 +1,28 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -0,0 +1,8 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"tabWidth": 2,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "none"
}

30
Frontend/Dockerfile Normal file
View File

@@ -0,0 +1,30 @@
FROM node:20.9.0-bullseye-slim as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY ./ .
RUN npm run build
FROM nginx:stable-alpine3.17-slim as production-stage
RUN mkdir /app
RUN apk add --no-cache tzdata
ENV TZ Europe/Warsaw
COPY --from=build-stage /app/dist /usr/share/nginx/html
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
EXPOSE 443
FROM node:20.9.0-bullseye-slim as dev
WORKDIR /app
COPY package*.json ./
RUN npm install
ENV HOST=0.0.0.0
COPY . .
EXPOSE 8080
CMD ["npm", "run", "dev"]

46
Frontend/README.md Normal file
View File

@@ -0,0 +1,46 @@
# new-frontend
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
1. Disable the built-in TypeScript Extension
1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
## Customize configuration
See [Vite Configuration Reference](https://vitejs.dev/config/).
## Project Setup
```sh
npm install
```
### Compile and Hot-Reload for Development
```sh
npm run dev
```
### Type-Check, Compile and Minify for Production
```sh
npm run build
```
### Lint with [ESLint](https://eslint.org/)
```sh
npm run lint
```

1
Frontend/env.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
/// <reference types="vite/client" />

13
Frontend/index.html Normal file
View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Release11 Tools</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

48
Frontend/nginx.conf Normal file
View File

@@ -0,0 +1,48 @@
server {
listen 80;
listen [::]:80;
server_name localhost;
#access_log /var/log/nginx/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
expires -1;
add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
}
location /java/ {
proxy_pass http://xmltools-backend:8081/;
proxy_set_header Host $host;
}
location /api/mock {
proxy_pass http://xmltools-mocked-services:8097/api/mock;
proxy_set_header Host $host;
}
location /libxml/ {
proxy_pass http://xmltools-libxml-backend/;
proxy_set_header Host $host;
}
location /mock/ {
proxy_pass http://xmltools-mocked-services:8097/;
proxy_set_header Host $host;
proxy_set_header Content-Type $http_content_type;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

8072
Frontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

44
Frontend/package.json Normal file
View File

@@ -0,0 +1,44 @@
{
"name": "new-frontend",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "vite --host",
"build": "run-p type-check build-only",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --noEmit -p tsconfig.app.json --composite false",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
"format": "prettier --write src/"
},
"dependencies": {
"@codemirror/lang-html": "^6.4.5",
"@codemirror/lang-json": "^6.0.1",
"@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"
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.2.0",
"@tsconfig/node18": "^2.0.1",
"@types/node": "^18.16.17",
"@vitejs/plugin-vue": "^4.2.3",
"@vue/eslint-config-prettier": "^7.1.0",
"@vue/eslint-config-typescript": "^11.0.3",
"@vue/tsconfig": "^0.4.0",
"autoprefixer": "^10.4.14",
"eslint": "^8.39.0",
"eslint-plugin-vue": "^9.11.0",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.24",
"prettier": "^2.8.8",
"tailwindcss": "^3.3.2",
"typescript": "~5.0.4",
"vite": "^4.3.9",
"vue-tsc": "^1.6.5"
}
}

View File

@@ -0,0 +1,7 @@
/* eslint-disable no-undef */
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

57
Frontend/src/App.vue Normal file
View File

@@ -0,0 +1,57 @@
<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="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>
</template>
<style scoped></style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
version="1.1"
id="Release11_xA0_Image_1_"
x="0px"
y="0px"
viewBox="0 0 1010.2 146"
style="enable-background:new 0 0 1010.2 146;"
xml:space="preserve"
sodipodi:docname="logo.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs31" /><sodipodi:namedview
id="namedview29"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="1.3155811"
inkscape:cx="375.11942"
inkscape:cy="72.971558"
inkscape:window-width="1920"
inkscape:window-height="1135"
inkscape:window-x="1920"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="Release11_xA0_Image_1_" />
<style
type="text/css"
id="style2">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#2A93B0;}
.st1{fill:#2A93B0;}
.st2{fill:#1A161A;}
</style>
<path
class="st0"
d="M41.8,58.5L3,143.7h145.5V4.8L41.8,58.5z"
id="path4" />
<g
id="g10">
<path
class="st1"
d="M961.1,79.2h-16.9V25.3l-16.6,4.9V17.4l32-11.1h1.6V79.2z"
id="path6" />
<path
class="st1"
d="M1010.2,79.2h-16.9V25.3l-16.6,4.9V17.4l32-11.1h1.6V79.2z"
id="path8" />
</g>
<g
id="g26"
style="fill:#ffffff">
<path
class="st2"
d="M290.7,71.3c5-7.3,7.5-15.5,7.5-24.4c0-15-4.8-26.4-14.5-34.1C275,5.9,263,2.4,247.9,2.4h-41.6v138.1h25.5V87 l36.2,53.5h31.9l-37.5-50.9C275,86.8,284.4,80.7,290.7,71.3z M231.8,68V27.2h13.8c8,0,14.2,1.2,18.6,3.7c5.6,3.1,8.4,8.2,8.4,15.2 c0,7.5-2.2,13-6.6,16.6c-4.4,3.6-10.3,5.3-17.8,5.3H231.8z"
id="path12"
style="fill:#ffffff" />
<path
class="st2"
d="M397.5,48.4c-10.4-9.7-22.6-14.5-36.5-14.5c-16.9,0-30.6,6.4-41,19.2c-8.6,10.6-12.9,22.1-12.9,34.7v4.7 c0,13.4,5.4,25.3,16.3,35.7c10.9,10.4,24,15.6,39.2,15.6c11.5,0,21.5-3.1,30-9.2c8.5-6.2,14.6-14.1,18.3-24h-27.4 c-6.1,6.1-13.5,9.1-22.2,9.1c-6.6,0-12.5-1.8-17.8-5.4c-5.3-3.6-8.7-8.5-10.2-14.5h80.1c0.6-4.3,0.9-8.2,0.9-11.6 C414.5,72.2,408.9,59,397.5,48.4z M333.1,77.9c1.7-5.2,4.8-9.6,9.1-13.2c5.3-4.5,11.7-6.7,19.1-6.7c7.3,0,13.7,2.2,19.1,6.7 c4.5,3.7,7.6,8.1,9.3,13.2H333.1z"
id="path14"
style="fill:#ffffff" />
<rect
x="431.5"
y="2.6"
class="st2"
width="24.8"
height="137.9"
id="rect16"
style="fill:#ffffff" />
<path
class="st2"
d="M561.8,48.4c-10.4-9.7-22.6-14.5-36.5-14.5c-16.9,0-30.6,6.4-41,19.2c-8.6,10.6-12.9,22.1-12.9,34.7v4.7 c0,13.4,5.4,25.3,16.3,35.7c10.9,10.4,24,15.6,39.2,15.6c11.5,0,21.5-3.1,30-9.2c8.5-6.2,14.6-14.1,18.3-24h-27.4 c-6.1,6.1-13.5,9.1-22.2,9.1c-6.6,0-12.5-1.8-17.8-5.4c-5.3-3.6-8.7-8.5-10.2-14.5h80.1c0.6-4.3,0.9-8.2,0.9-11.6 C578.7,72.2,573.1,59,561.8,48.4z M497.3,77.9c1.7-5.2,4.8-9.6,9.1-13.2c5.3-4.5,11.7-6.7,19.1-6.7c7.3,0,13.7,2.2,19.1,6.7 c4.5,3.7,7.6,8.1,9.3,13.2H497.3z"
id="path18"
style="fill:#ffffff" />
<path
class="st2"
d="M773.6,81.7c-7-2.2-13.9-4.5-20.9-6.7c-2.5-1-4.3-2.2-5.5-3.6c-1.2-1.4-1.9-2.9-2.1-4.4c0-2.4,1-4.4,3.1-6.1 c2-1.7,4.3-2.5,6.8-2.5c2.4,0,4.4,0.6,6.2,1.8c1.8,1.2,3.2,3,4.2,5.5h23.7c0-9.2-3.4-16.8-10.3-22.7c-6.9-6-14.8-8.9-23.8-8.9 c-6.7,0-13.1,1.8-19,5.4c-11.4,7-15.5,16.8-15.7,26.7c-0.1,5,1.4,9.8,4.2,14.5c2.8,4.7,7.1,8.4,13,11.3c6.3,2.6,12.8,5.3,19.5,7.9 c6.6,2.7,10,5.8,10,9.2c0,3.2-1.2,5.9-3.4,7.9c-2.3,2.1-5.1,3.1-8.5,3.1c-2.9,0-5.5-1-7.9-3c-2.4-2-4.1-5-4.9-8.9h-25 c0,9.2,2.6,17.1,7.8,23.4c4.8,6,10.9,9.7,18.3,11.1c3.7,0.7,7.4,1.1,11,1.1c12.2,0,21.7-4.1,28.5-12.3c6-7.1,9.5-16.1,8.9-27.1 C791.2,94,784.6,86.8,773.6,81.7z"
id="path20"
style="fill:#ffffff" />
<path
class="st2"
d="M912,88.1c0-15.9-5.7-29.1-17-39.7c-10.4-9.7-22.6-14.5-36.5-14.5c-16.9,0-30.6,6.4-41,19.2 c-8.6,10.6-12.9,22.1-12.9,34.7v4.7c0,13.4,5.4,25.3,16.3,35.7c10.9,10.4,24,15.6,39.2,15.6c11.5,0,21.5-3.1,30-9.2 c8.5-6.2,14.6-14.1,18.3-24h-27.4c-6.1,6.1-13.5,9.1-22.2,9.1c-6.6,0-12.5-1.8-17.8-5.4c-5.3-3.6-8.7-8.5-10.2-14.5h80.1 C911.7,95.3,912,91.5,912,88.1z M830.6,77.9c1.7-5.2,4.8-9.6,9.1-13.2c5.3-4.5,11.7-6.7,19.1-6.7c7.3,0,13.7,2.2,19.1,6.7 c4.5,3.7,7.6,8.1,9.3,13.2H830.6z"
id="path22"
style="fill:#ffffff" />
<path
class="st2"
d="M680.5,44.4c-9.6-8-20.5-12-32.8-12c-7,0-14,1.5-21,4.5c-7,3-13.7,7.6-19.9,13.8c-5,6.2-8.6,12.2-10.7,18.2 c-2.1,6-3.2,12.2-3.2,18.8c0,15.6,5.3,28.8,15.9,39.7c10.6,10.9,23.5,16.3,38.6,16.3c12.6,0,23.7-3.9,33.2-11.8v8.5h22.3V37h-22.3 V44.4z M667.8,110.5c-5.4,5.8-12.5,8.8-21.2,8.8c-8.2,0-15.1-3-20.8-9.1s-8.5-13.3-8.5-21.8c0-4,0.7-7.9,2.2-11.6 c1.5-3.7,3.4-7.1,5.7-10.3c5.7-6.3,12.8-9.4,21.1-9.4c8.6,0,15.7,3,21.3,9c5.6,6,8.4,13.4,8.4,22.2 C675.9,97.3,673.2,104.7,667.8,110.5z"
id="path24"
style="fill:#ffffff" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 22.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Release11_xA0_Image_1_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" viewBox="0 0 1010.2 146" style="enable-background:new 0 0 1010.2 146;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#2A93B0;}
.st1{fill:#2A93B0;}
.st2{fill:#1A161A;}
</style>
<path class="st0" d="M41.8,58.5L3,143.7h145.5V4.8L41.8,58.5z"/>
<g>
<path class="st1" d="M961.1,79.2h-16.9V25.3l-16.6,4.9V17.4l32-11.1h1.6V79.2z"/>
<path class="st1" d="M1010.2,79.2h-16.9V25.3l-16.6,4.9V17.4l32-11.1h1.6V79.2z"/>
</g>
<g>
<path class="st2" d="M290.7,71.3c5-7.3,7.5-15.5,7.5-24.4c0-15-4.8-26.4-14.5-34.1C275,5.9,263,2.4,247.9,2.4h-41.6v138.1h25.5V87
l36.2,53.5h31.9l-37.5-50.9C275,86.8,284.4,80.7,290.7,71.3z M231.8,68V27.2h13.8c8,0,14.2,1.2,18.6,3.7c5.6,3.1,8.4,8.2,8.4,15.2
c0,7.5-2.2,13-6.6,16.6c-4.4,3.6-10.3,5.3-17.8,5.3H231.8z"/>
<path class="st2" d="M397.5,48.4c-10.4-9.7-22.6-14.5-36.5-14.5c-16.9,0-30.6,6.4-41,19.2c-8.6,10.6-12.9,22.1-12.9,34.7v4.7
c0,13.4,5.4,25.3,16.3,35.7c10.9,10.4,24,15.6,39.2,15.6c11.5,0,21.5-3.1,30-9.2c8.5-6.2,14.6-14.1,18.3-24h-27.4
c-6.1,6.1-13.5,9.1-22.2,9.1c-6.6,0-12.5-1.8-17.8-5.4c-5.3-3.6-8.7-8.5-10.2-14.5h80.1c0.6-4.3,0.9-8.2,0.9-11.6
C414.5,72.2,408.9,59,397.5,48.4z M333.1,77.9c1.7-5.2,4.8-9.6,9.1-13.2c5.3-4.5,11.7-6.7,19.1-6.7c7.3,0,13.7,2.2,19.1,6.7
c4.5,3.7,7.6,8.1,9.3,13.2H333.1z"/>
<rect x="431.5" y="2.6" class="st2" width="24.8" height="137.9"/>
<path class="st2" d="M561.8,48.4c-10.4-9.7-22.6-14.5-36.5-14.5c-16.9,0-30.6,6.4-41,19.2c-8.6,10.6-12.9,22.1-12.9,34.7v4.7
c0,13.4,5.4,25.3,16.3,35.7c10.9,10.4,24,15.6,39.2,15.6c11.5,0,21.5-3.1,30-9.2c8.5-6.2,14.6-14.1,18.3-24h-27.4
c-6.1,6.1-13.5,9.1-22.2,9.1c-6.6,0-12.5-1.8-17.8-5.4c-5.3-3.6-8.7-8.5-10.2-14.5h80.1c0.6-4.3,0.9-8.2,0.9-11.6
C578.7,72.2,573.1,59,561.8,48.4z M497.3,77.9c1.7-5.2,4.8-9.6,9.1-13.2c5.3-4.5,11.7-6.7,19.1-6.7c7.3,0,13.7,2.2,19.1,6.7
c4.5,3.7,7.6,8.1,9.3,13.2H497.3z"/>
<path class="st2" d="M773.6,81.7c-7-2.2-13.9-4.5-20.9-6.7c-2.5-1-4.3-2.2-5.5-3.6c-1.2-1.4-1.9-2.9-2.1-4.4c0-2.4,1-4.4,3.1-6.1
c2-1.7,4.3-2.5,6.8-2.5c2.4,0,4.4,0.6,6.2,1.8c1.8,1.2,3.2,3,4.2,5.5h23.7c0-9.2-3.4-16.8-10.3-22.7c-6.9-6-14.8-8.9-23.8-8.9
c-6.7,0-13.1,1.8-19,5.4c-11.4,7-15.5,16.8-15.7,26.7c-0.1,5,1.4,9.8,4.2,14.5c2.8,4.7,7.1,8.4,13,11.3c6.3,2.6,12.8,5.3,19.5,7.9
c6.6,2.7,10,5.8,10,9.2c0,3.2-1.2,5.9-3.4,7.9c-2.3,2.1-5.1,3.1-8.5,3.1c-2.9,0-5.5-1-7.9-3c-2.4-2-4.1-5-4.9-8.9h-25
c0,9.2,2.6,17.1,7.8,23.4c4.8,6,10.9,9.7,18.3,11.1c3.7,0.7,7.4,1.1,11,1.1c12.2,0,21.7-4.1,28.5-12.3c6-7.1,9.5-16.1,8.9-27.1
C791.2,94,784.6,86.8,773.6,81.7z"/>
<path class="st2" d="M912,88.1c0-15.9-5.7-29.1-17-39.7c-10.4-9.7-22.6-14.5-36.5-14.5c-16.9,0-30.6,6.4-41,19.2
c-8.6,10.6-12.9,22.1-12.9,34.7v4.7c0,13.4,5.4,25.3,16.3,35.7c10.9,10.4,24,15.6,39.2,15.6c11.5,0,21.5-3.1,30-9.2
c8.5-6.2,14.6-14.1,18.3-24h-27.4c-6.1,6.1-13.5,9.1-22.2,9.1c-6.6,0-12.5-1.8-17.8-5.4c-5.3-3.6-8.7-8.5-10.2-14.5h80.1
C911.7,95.3,912,91.5,912,88.1z M830.6,77.9c1.7-5.2,4.8-9.6,9.1-13.2c5.3-4.5,11.7-6.7,19.1-6.7c7.3,0,13.7,2.2,19.1,6.7
c4.5,3.7,7.6,8.1,9.3,13.2H830.6z"/>
<path class="st2" d="M680.5,44.4c-9.6-8-20.5-12-32.8-12c-7,0-14,1.5-21,4.5c-7,3-13.7,7.6-19.9,13.8c-5,6.2-8.6,12.2-10.7,18.2
c-2.1,6-3.2,12.2-3.2,18.8c0,15.6,5.3,28.8,15.9,39.7c10.6,10.9,23.5,16.3,38.6,16.3c12.6,0,23.7-3.9,33.2-11.8v8.5h22.3V37h-22.3
V44.4z M667.8,110.5c-5.4,5.8-12.5,8.8-21.2,8.8c-8.2,0-15.1-3-20.8-9.1s-8.5-13.3-8.5-21.8c0-4,0.7-7.9,2.2-11.6
c1.5-3.7,3.4-7.1,5.7-10.3c5.7-6.3,12.8-9.4,21.1-9.4c8.6,0,15.7,3,21.3,9c5.6,6,8.4,13.4,8.4,22.2
C675.9,97.3,673.2,104.7,667.8,110.5z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

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

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Example Page</title>
</head>
<body>
<h1>Hello World!</h1>
<p>That's paragraph</p>
<br>
</body>
</html>

View File

@@ -0,0 +1,5 @@
declare default element namespace "http://www.release11.com/schemas/Sample.xsd";
declare namespace u = "http://www.release11.com/schemas/Sample.xsd";
for $x in /u:root/u:UserList[@Id = 'a']/u:User
return string($x/u:Name)

View File

@@ -0,0 +1,62 @@
<?xml version = "1.0" encoding = "UTF-8"?>
<u:root xmlns:u = "http://www.release11.com/schemas/Sample.xsd" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://www.tibco.com/schemas/Shemy4tools/Folder/Schema.xsd Schema4tools.xsd">
<u:UserList Id = "a">
<u:User Id = "1">
<u:Name>John</u:Name>
<u:Surname>Wick</u:Surname>
<u:DateOfDeath>2023-10-10</u:DateOfDeath>
</u:User>
<u:User Id = "2">
<u:Name>Martha</u:Name>
<u:Surname>Whane</u:Surname>
<u:DateOfDeath>1970-06-13</u:DateOfDeath>
</u:User>
<u:User Id = "3">
<u:Name>Bruce</u:Name>
<u:Surname>Lee</u:Surname>
<u:DateOfDeath>1985-01-24</u:DateOfDeath>
</u:User>
<u:User Id = "4">
<u:Name>John</u:Name>
<u:Surname>Rambo</u:Surname>
<u:DateOfDeath>2024-06-19</u:DateOfDeath>
</u:User>
<u:NameList>FirstList</u:NameList>
</u:UserList>
<u:UserList Id = "b">
<u:User Id = "1">
<u:Name>Jack</u:Name>
<u:Surname>Wicker</u:Surname>
<u:DateOfDeath>2023-10-10</u:DateOfDeath>
</u:User>
<u:NameList>SecondList</u:NameList>
</u:UserList>
<u:UserList Id = "c">
<u:User Id = "1">
<u:Name>New</u:Name>
<u:Surname>Folder</u:Surname>
<u:DateOfDeath>2023-11-10</u:DateOfDeath>
</u:User>
<u:User Id = "2">
<u:Name>Newer</u:Name>
<u:Surname>Folder</u:Surname>
<u:DateOfDeath>2023-11-11</u:DateOfDeath>
</u:User>
<u:User Id = "3">
<u:Name>Newest</u:Name>
<u:Surname>Folder</u:Surname>
<u:DateOfDeath>2023-11-12</u:DateOfDeath>
</u:User>
<u:User Id = "4">
<u:Name>New</u:Name>
<u:Surname>Folder2</u:Surname>
<u:DateOfDeath>2023-11-13</u:DateOfDeath>
</u:User>
<u:User Id = "5">
<u:Name>New</u:Name>
<u:Surname>Folder-Final</u:Surname>
<u:DateOfDeath>2023-11-14</u:DateOfDeath>
</u:User>
<u:NameList>ThirdList</u:NameList>
</u:UserList>
</u:root>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:u="http://www.release11.com/schemas/Sample.xsd"
targetNamespace="http://www.release11.com/schemas/Sample.xsd"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element ref="u:UserList" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="UserList">
<xs:complexType mixed="true">
<xs:sequence>
<xs:element ref="u:User" maxOccurs="unbounded"/>
<xs:element ref="u:NameList"/>
</xs:sequence>
<xs:attribute name="Id" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
<xs:simpleType name="User">
<xs:restriction base="xs:string"/>
</xs:simpleType>
<xs:element name="User">
<xs:complexType>
<xs:sequence>
<xs:element ref="u:Name"/>
<xs:element ref="u:Surname"/>
<xs:element ref="u:DateOfDeath"/>
</xs:sequence>
<xs:attribute name="Id" type="xs:int" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="Name" type="xs:string"/>
<xs:element name="Surname" type="xs:string"/>
<xs:element name="DateOfDeath" type="xs:date"/>
<xs:element name="NameList" type="xs:string"/>
</xs:schema>

View File

@@ -0,0 +1,17 @@
<?xml version = "1.0" encoding = "UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:u = "http://www.release11.com/schemas/Sample.xsd"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<UserLists>
<UserListCount>
<xsl:value-of select="count(/u:root/u:UserList)" />
</UserListCount>
<xsl:for-each select="/u:root/u:UserList">
<UserListStats>
<Name><xsl:value-of select="u:NameList" /></Name>
<UserCount><xsl:value-of select="count(u:User)" /></UserCount>
</UserListStats>
</xsl:for-each>
</UserLists>
</xsl:template>
</xsl:stylesheet>

View File

@@ -0,0 +1,537 @@
[
{
"entries": [
{
"arguments": [
{
"type": "object",
"description": "The object to convert to a boolean"
}
],
"description": "The boolean function converts its argument to a boolean",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Boolean-Functions",
"examples": [
{
"command": "boolean('Release11')",
"output": "true"
},
{
"command": "boolean('')",
"output": "false"
},
{
"command": "boolean(2334)",
"output": "true"
}
],
"name": "boolean()",
"output": "boolean"
},
{
"arguments": [],
"description": "The true function returns false.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Boolean-Functions",
"examples": [
{
"output": "false",
"command": "false()"
}
],
"name": "false()",
"output": "boolean"
},
{
"arguments": [],
"description": "The not function returns true if its argument is false, and false otherwise.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Boolean-Functions",
"examples": [
{
"output": "false",
"command": "not('text')"
},
{
"command": "not('')",
"output": "true"
}
],
"name": "not()",
"output": "boolean"
},
{
"arguments": [],
"description": "The true function returns true.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Boolean-Functions",
"examples": [
{
"output": "true",
"command": "true()"
}
],
"name": "true()",
"output": "boolean"
}
],
"name": "Boolean"
},
{
"entries": [
{
"arguments": [
{
"type": "node-set",
"description": "Node-set to count nodes in"
}
],
"description": "Returns the number of nodes in the node-set",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Node-Set-Functions",
"examples": [
{
"output": "10",
"command": "count(/u:root/u:UserList/u:User)"
},
{
"output": "1",
"command": "count(/u:root/u:UserList[@Id = 'b']/u:User)"
}
],
"name": "count()",
"output": "number"
},
{
"arguments": [],
"description": "Returns the element specified by it's unique id, requires DTD",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Node-Set-Functions",
"examples": [],
"name": "id()",
"output": "node-set"
},
{
"arguments": [
{
"description": "Language that will be looked for in context node",
"type": "string"
}
],
"description": "The lang function returns true or false depending on whether the language of the context node as specified by xml:lang attributes is the same as or is a sublanguage of the language specified by the argument string.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Boolean-Functions",
"examples": [],
"name": "lang()",
"output": "boolean"
},
{
"arguments": [],
"description": "The position function returns a number equal to the context position from the expression evaluation context.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Node-Set-Functions",
"examples": [],
"name": "last()",
"output": "number"
},
{
"arguments": [
{
"description": "Extract first node and return its local name",
"type": "node-set"
}
],
"description": "Returns the number of nodes in the node-set",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Node-Set-Functions",
"examples": [
{
"command": "local-name(/u:root)",
"output": "root"
},
{
"command": "local-name(/u:root/u:UserList)",
"output": "UserList"
}
],
"name": "local-name()",
"output": "string"
},
{
"arguments": [
{
"description": "Extract first node and return QName",
"type": "node-set? (Optional)"
}
],
"description": "Returns the number of nodes in the node-set",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Node-Set-Functions",
"examples": [
{
"command": "name(/u:root)",
"output": "u:root"
},
{
"command": "name(/u:root/u:UserList)",
"output": "u:UserList"
}
],
"name": "name()",
"output": "string"
},
{
"arguments": [
{
"description": "Extract first node and return the namespace URI",
"type": "node-set"
}
],
"description": "Returns the namespace-uri for the first node in the node-set",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Node-Set-Functions",
"examples": [
{
"output": "http://www.release11.com/schemas/Sample.xsd",
"command": "namespace-uri(/u:root)"
}
],
"name": "namespace-uri()",
"output": "string"
},
{
"arguments": [],
"description": "Returns the position of the current context node.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Node-Set-Functions",
"examples": [
{
"output": "3",
"command": "position()"
}
],
"name": "position()",
"output": "number"
}
],
"name": "Node-Set"
},
{
"entries": [
{
"arguments": [
{
"type": "number",
"description": "Number to round"
}
],
"description": "The floor function returns the largest (closest to positive infinity) number that is not greater than the argument and that is an integer.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Number-Functions",
"examples": [
{
"output": "3",
"command": "floor(3.1)"
},
{
"output": "3",
"command": "floor(3.9)"
},
{
"output": "3",
"command": "floor(3.5)"
}
],
"name": "floor()",
"output": "number"
},
{
"arguments": [
{
"type": "object",
"description": "The object to convert to a number"
}
],
"description": "The number function converts its argument to a number",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Number-Functions",
"examples": [
{
"output": "10",
"command": "number(10)"
},
{
"output": "NaN",
"command": "number('')"
}
],
"name": "number()",
"output": "number"
},
{
"arguments": [
{
"type": "number",
"description": "Number to round"
}
],
"description": "The round function returns the number that is closest to the argument and that is an integer. If there are two such numbers, then the one that is closest to positive infinity is returned. If the argument is NaN, then NaN is returned. If the argument is positive infinity, then positive infinity is returned. If the argument is negative infinity, then negative infinity is returned. If the argument is positive zero, then positive zero is returned. If the argument is negative zero, then negative zero is returned. If the argument is less than zero, but greater than or equal to -0.5, then negative zero is returned.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Number-Functions",
"examples": [
{
"output": "3",
"command": "round(3.1)"
},
{
"output": "4",
"command": "round(3.9)"
},
{
"output": "4",
"command": "round(3.5)"
}
],
"name": "round()",
"output": "number"
},
{
"arguments": [
{
"description": "Node set to sum",
"type": "node-set"
}
],
"description": "The sum function returns the sum, for each node in the argument node-set, of the result of converting the string-values of the node to a number.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-Number-Functions",
"examples": [
{
"output": "78",
"command": "sum(/someNode/value)"
}
],
"name": "sum()",
"output": "number"
}
],
"name": "Number"
},
{
"entries": [
{
"arguments": [
{
"type": "string* (One or More)",
"description": "Strings to concatenate"
}
],
"description": "The concat function returns the concatenation of its arguments.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-String-Functions",
"examples": [
{
"command": "concat('Release', 11)",
"output": "Release11"
}
],
"name": "concat()",
"output": "string"
},
{
"arguments": [
{
"type": "string",
"description": "String to test"
},
{
"type": "string",
"description": "String that first string has to contain"
}
],
"description": "The contains function returns true if the first argument string contains the second argument string, and otherwise returns false.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-String-Functions",
"examples": [
{
"command": "contains('Release11', 'eas')",
"output": "true"
}
],
"name": "contains()",
"output": "boolean"
},
{
"arguments": [
{
"description": "String to normalize",
"type": "string? (Optional)"
}
],
"description": "The normalize-space function returns the argument string with whitespace normalized by stripping leading and trailing whitespace and replacing sequences of whitespace characters by a single space.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-String-Functions",
"examples": [
{
"output": "abc def",
"command": "normalize-space(' abc def ')"
}
],
"name": "normalize-space(()",
"output": "string"
},
{
"arguments": [
{
"type": "string",
"description": "String to test"
},
{
"type": "string",
"description": "String that first string has to start from"
}
],
"description": "Returns true if the first argument string starts with the second argument string, and otherwise returns false.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-String-Functions",
"examples": [
{
"command": "starts-with('Release11', 'Rel'))",
"output": "true"
},
{
"output": "false",
"command": "starts-with('Release11', 'ease'))"
}
],
"name": "starts-with()",
"output": "boolean"
},
{
"arguments": [
{
"type": "object",
"description": "The object to convert to a string"
}
],
"description": "The string function converts an object to a string",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-String-Functions",
"examples": [
{
"output": "10",
"command": "string(10)"
},
{
"output": "Release11",
"command": "string('Release11')"
}
],
"name": "string()",
"output": "string"
},
{
"arguments": [
{
"description": "String to test",
"type": "string? (Optional)"
}
],
"description": "The string-length returns the number of characters in the string.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-String-Functions",
"examples": [
{
"output": "6",
"command": "string-length('abcdef')"
}
],
"name": "string-length()",
"output": "number"
},
{
"arguments": [
{
"type": "string",
"description": "String to split"
},
{
"type": "number",
"description": "Starting index"
},
{
"description": "Length of target substring",
"type": "number? (Optional)"
}
],
"description": "The substring function returns the substring of the first argument starting at the position specified in the second argument with length specified in the third argument.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-String-Functions",
"examples": [
{
"output": "2345",
"command": "substring('12345',2)"
},
{
"output": "234",
"command": "substring('12345',2,3)"
}
],
"name": "substring()",
"output": "string"
},
{
"arguments": [
{
"type": "string",
"description": "String to split"
},
{
"type": "string",
"description": "String that splits first string"
}
],
"description": "The substring-after function returns the substring of the first argument string that follows the first occurrence of the second argument string in the first argument string, or the empty string if the first argument string does not contain the second argument string.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-String-Functions",
"examples": [
{
"output": "ase11",
"command": "substring-after('Release11', 'le')"
}
],
"name": "substring-after()",
"output": "string"
},
{
"arguments": [
{
"type": "string",
"description": "String to split"
},
{
"type": "string",
"description": "String that splits first string"
}
],
"description": "The substring-before function returns the substring of the first argument string that precedes the first occurrence of the second argument string in the first argument string, or the empty string if the first argument string does not contain the second argument string.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-String-Functions",
"examples": [
{
"output": "Release",
"command": "substring-before('Release11', '11')"
}
],
"name": "substring-before()",
"output": "string"
},
{
"arguments": [
{
"type": "string",
"description": "String to process"
},
{
"description": "Characters to remove",
"type": "string"
},
{
"type": "string",
"description": "String to insert characters from second argument"
}
],
"description": "The translate function returns the first argument string with occurrences of characters in the second argument string replaced by the character at the corresponding position in the third argument string. If there is a character in the second argument string with no character at a corresponding position in the third argument string (because the second argument string is longer than the third argument string), then occurrences of that character in the first argument string are removed.",
"documentationReferenceURL": "https://www.w3.org/TR/1999/REC-xpath-19991116/#section-String-Functions",
"examples": [
{
"output": "BAr",
"command": "translate('bar','abc','ABC')"
},
{
"output": "AAA",
"command": "translate('--aaa--','abc-','ABC')"
}
],
"name": "translate()",
"output": "string"
}
],
"name": "String"
}
]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
{
"universalInfo":
[
{
"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"
}
],
"VersionDiffs":
[
{
"version":"2.0",
"diffs":
[
"Added support for all XML simple types",
"Many new functions (tripled instruction count)",
"All expressions evaluate to sequence",
"Introduces conditional expressions and for-loops"
]
},
{
"version":"3.0",
"diffs":
[
"Dynamic function calls (function may be called without being referenced by name (find function in collection and call)",
"Inline functions",
"Namespace literals - Namespace may be embedded into function name",
"Support for union types - collections containing elements of different types",
"Mapping operator - '!' performs evaluation for each element in sequence and concatenates results",
"Introduced maps"
]
},
{
"version":"3.1",
"diffs":
[
"New operator for function chaining '=>'",
"Introduced maps that store data in pair 'key:value' - 'map{ key : value, key : value }'",
"Introduced arrays - they differ from sequences in that they can be nested 'array{1, 5, 7, (10 to 20)}'"
]
}
]
}

View File

@@ -0,0 +1,845 @@
[
{
"name": "Templates",
"entries": [
{
"name": "<xsl:template>",
"description": "Defines an output producing template. This element must have either the match attribute or the name attribute set.",
"attributes":
[
{
"type":"optional",
"name":"match",
"description":"Specifies a pattern that determines the elements for which this template should be used. It is a required attribute if there is no name attribute."
},
{
"type":"optional",
"name":"name",
"description":"Specifies a name for this template"
},
{
"type":"optional",
"name":"mode",
"description":"Specifies a particular mode for this template, which can be matched by an attribute of the <xsl:apply-templates> element"
},
{
"type":"optional",
"name":"priority",
"description":"Specifies a numeric priority for this template."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/template",
"output": "XML Tree"
},{
"name": "<xsl:apply-templates>",
"description": "Selects a set of nodes in the input tree and instructs the processor to apply the proper templates to them.",
"attributes":
[
{
"type":"optional",
"name":"mode",
"description":"Specifies a particular mode for this template, which can be matched by an attribute of the <xsl:apply-templates> element"
},
{
"type":"optional",
"name":"select",
"description":"XPath expression that specifies the nodes to be processed. If this attribute is not set, all child nodes of the current node are selected."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/apply-templates",
"output": "XML Nodes"
},{
"name": "<xsl:apply-imports/>",
"description": "Import precedence requires that template rules in main stylesheets have higher precedence than template rules in imported stylesheets",
"attributes":
[
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/apply-imports",
"output": "Imported output from another XSLT"
},{
"name": "<xsl:call-template>",
"description": "Invokes a named template",
"attributes":
[
{
"type":"required",
"name":"name",
"description":"Specifies the name of the template you wish to invoke."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/call-template",
"output": "Called template XML"
}
]
},
{
"name":"Loops and conditional processing",
"entries":
[
{
"name": "<xsl:for-each>",
"description": "Selects a set of nodes and processes each of them in the same way",
"attributes":
[
{
"type":"required",
"name":"select",
"description":"XPath expression that specifies the nodes to be processed."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/for-each",
"output": "Processed set of nodes"
},
{
"name": "<xsl:if>",
"description": "Element contains a test attribute and a template. If the test evaluates to true, the template is processed.",
"attributes":
[
{
"type":"required",
"name":"test",
"description":"Contains an XPath expression that can be evaluated to a Boolean value."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/if",
"output": "Depending on test processed template or not."
},
{
"name": "<xsl:choose>",
"description": "Element defines a choice among a number of alternatives. It behaves like a switch statement in procedural languages.",
"attributes":
[
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/choose",
"output": "Choosed XML template"
},
{
"name": "<xsl:when>",
"description": "Element always appears within an <xsl:choose> element, acting like a case statement.",
"attributes":
[
{
"type":"required",
"name":"test",
"description":"Boolean expression to be evaluated. If true, the contents of the element are processed; if false, they are ignored."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/when",
"output": "Processed or not XML Template"
},
{
"name": "<xsl:otherwise>",
"description": "Element is used to define the action that should be taken when none of the <xsl:when> conditions apply.",
"attributes":
[
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/otherwise",
"output": "processed XML Template"
}
]
},
{
"name":"Creating Result Tree",
"entries":
[
{
"name": "<xsl:attribute>",
"description": "Creates an attribute in the output document, using any values that can be accessed from the stylesheet. The element must be defined before any other output document element inside the output document element for which it establishes attribute values",
"attributes":
[
{
"type":"required",
"name":"name",
"description":"Specifies the name of the attribute to be created in the output document."
} ,
{
"type":"optional",
"name":"namespace",
"description":"Defines the namespace URI for this attribute in the output document."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/attribute",
"output": "XML Element with provided attribute"
},{
"name": "<xsl:attribute-set>",
"description": "Creates a named set of attributes, which can then be applied as whole to the output document, in a manner similar to named styles in CSS",
"attributes":
[
{
"type":"required",
"name":"name",
"description":"Specifies the name of the attribute set."
} ,
{
"type":"optional",
"name":"use-attribute-sets",
"description":"Builds an attribute set from other attribute sets. The names of the contributing sets must be separated with whitespace characters"
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/attribute-set",
"output": "Named set of attributes"
},{
"name": "<xsl:copy>",
"description": "Transfers a shallow copy (the node and any associated namespace node) of the current node to the output document.",
"attributes":
[
{
"type":"optional",
"name":"use-attribute-sets",
"description":"Lists attribute sets that should be applied to the output node, if it is an element"
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/copy",
"output": "Copy of XML node"
},{
"name": "<xsl:number>",
"description": "Counts things sequentially. It can also be used to quickly format a number.",
"attributes":
[
{
"type":"optional",
"name":"count",
"description":"Specifies what in the source tree should be numbered sequentially. It uses an XPath expression."
},
{
"type":"optional",
"name":"level",
"description":"Defines how levels of the source tree should be considered in generating sequential numbers. It has three valid values: single, multiple, and any."
},
{
"type":"optional",
"name":"from",
"description":"Specifies where the numbering should start or start over."
},
{
"type":"optional",
"name":"value",
"description":"Applies a given format to a number."
},
{
"type":"optional",
"name":"format",
"description":"Defines the format of the generated number."
},
{
"type":"optional",
"name":"lang",
"description":"Specifies which language's alphabet should be used in letter-based numbering formats."
},
{
"type":"optional",
"name":"letter-value",
"description":"Disambiguates between numbering sequences that use letters. Some languages have more than one numbering system that use letters."
},
{
"type":"optional",
"name":"grouping-separator",
"description":"Specifies what character should be used as the group (e.g. thousands) separator."
},
{
"type":"optional",
"name":"grouping-size",
"description":"Indicates the number of digits that make up a numeric group."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/number",
"output": "Formatted number"
},{
"name": "<xsl:value-of>",
"description": "Evaluates an XPath expression, converts it to a string, and writes that string to the result tree.",
"attributes":
[
{
"type":"required",
"name":"select",
"description":"Specifies the XPath expression to be evaluated and written to the output tree."
},
{
"type":"optional",
"name":"disable-output-escaping",
"description":"Specifies whether special characters are escaped when written to the output."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/value-of",
"output": "Value from XML nodes"
},{
"name": "<xsl:text>",
"description": "Writes literal text to the output tree.",
"attributes":
[
{
"type":"optional",
"name":"disable-output-escaping",
"description":"Specifies whether special characters are escaped when written to the output."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/text",
"output": "XML Node with writed text"
},{
"name": "<xsl:comment>",
"description": "Writes a comment to the output document. It must include only text.",
"attributes":
[
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/comment",
"output": "XML Node with writed comment"
},
{
"name": "<xsl:processing-instruction>",
"description": "Writes a processing instruction to the output document.",
"attributes":
[
{
"type":"required",
"name":"name",
"description":"Specifies the name of this processing instruction."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/processing-instruction",
"output": "XML Node with output of processed instruction"
},
{
"name": "<xsl:key>",
"description": "Declares a named key which can be used elsewhere in the stylesheet with the key( ) function.",
"attributes":
[
{
"type":"required",
"name":"name",
"description":"Specifies a name for this key. Must be a QName."
},
{
"type":"required",
"name":"match",
"description":"Defines the nodes for which this key is applicable."
},
{
"type":"required",
"name":"use",
"description":"Specifies an XPath expression that will be used to determine the value of the key for each of the applicable nodes."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/key",
"output": "key to use in stylesheet"
},
{
"name": "<xsl:decimal-format>",
"description": "Declares a named key which can be used elsewhere in the stylesheet with the key( ) function.",
"attributes":
[
{
"type":"optional",
"name":"name",
"description":"Specifies a name for this format."
},
{
"type":"optional",
"name":"decimal-separator",
"description":"Specifies the decimal point character."
},
{
"type":"optional",
"name":"grouping-separator",
"description":"Specifies the thousands separator character."
},
{
"type":"optional",
"name":"infinity",
"description":"Specifies the string used to represent infinity."
},
{
"type":"optional",
"name":"minus-sign",
"description":"Specifies the minus sign character."
},
{
"type":"optional",
"name":"NaN",
"description":"Specifies the string used when the value is not a number."
},
{
"type":"optional",
"name":"percent",
"description":"Specifies the percentage sign character."
},
{
"type":"optional",
"name":"per-mille",
"description":"Specifies the per thousand character."
},
{
"type":"optional",
"name":"zero-digit",
"description":"Specifies the digit zero character."
},
{
"type":"optional",
"name":"digit",
"description":"Specifies the character used in the format pattern to stand for a digit."
},
{
"type":"optional",
"name":"pattern-separator",
"description":"Specifies the character separating positive and negative subpatterns in a format pattern."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/decimal-format",
"output": "decimal format"
},
{
"name": "<xsl:preserve-space>",
"description": "Defines the elements in the source document for which whitespace should be preserved.",
"attributes":
[
{
"type":"required",
"name":"elements",
"description":"Specifies the elements for which whitespace should be preserved."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/preserve-space",
"output": "preserved space"
},
{
"name": "<xsl:strip-space>",
"description": "Defines the elements in the source document for which whitespace should be removed.",
"attributes":
[
{
"type":"required",
"name":"elements",
"description":"Specifies the elements for which whitespace should be preserved."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/strip-space",
"output": "elements with removed whitespace"
},
{
"name": "<xsl:sort>",
"description": "Defines a sort key for nodes selected by <xsl:apply-templates> or <xsl:for-each> and determines the order in which they are processed.",
"attributes":
[
{
"type":"optional",
"name":"select",
"description":"Uses an XPath expression to specify the nodes to be sorted."
},
{
"type":"optional",
"name":"order",
"description":"Specifies whether the nodes should be processed in \"ascending\" or \"descending\" order."
},
{
"type":"optional",
"name":"case-order",
"description":"Indicates whether upper- or lowercase letters are to be ordered first."
},
{
"type":"optional",
"name":"lang",
"description":"Specifies which language is to be used by the sort."
},
{
"type":"optional",
"name":"data-type",
"description":"Defines whether items are to be ordered alphabetically or numerically."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/sort",
"output": "sorted elements"
},
{
"name": "<xsl:output>",
"description": "Controls the characteristics of the output document.",
"attributes":
[
{
"type":"optional",
"name":"method",
"description":"Specifies output format."
},
{
"type":"optional",
"name":"version",
"description":"Specifies the value of the version attribute of the XML or HTML declaration in the output document."
},
{
"type":"optional",
"name":"encoding",
"description":"Specifies the value of the encoding attribute in the output document."
},
{
"type":"optional",
"name":"omit-xml-declaration",
"description":"Indicates whether or not to include an XML declaration in the output."
},
{
"type":"optional",
"name":"doctype-public",
"description":"Specifies the value of the PUBLIC attribute of the DOCTYPE declaration in the output document."
},
{
"type":"optional",
"name":"doctype-system",
"description":"Specifies the value of the SYSTEM attribute of the DOCTYPE declaration in the output document."
},
{
"type":"optional",
"name":"cdata-section-elements",
"description":"Lists elements whose text contents should be written as CDATA sections."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/output",
"output": "changed document prefix"
}
]
},
{
"name":"Stylesheet structure",
"entries":
[
{
"name": "<xsl:stylesheet>",
"description": "Is the outermost element of a stylesheet.",
"attributes":
[
{
"type":"required",
"name":"version",
"description":"Specifies the version of XSLT required by this stylesheet."
},
{
"type":"optional",
"name":"exclude-result-prefixes",
"description":"Specifies any namespace used in this document that should not be sent to the output document."
},
{
"type":"optional",
"name":"extension-element-prefixes",
"description":"Specifies a space-separated list of any namespace prefixes for extension elements in this document."
},
{
"type":"optional",
"name":"default-collation",
"description":"Specifies the default collation used by all XPath expressions appearing in attributes or text value templates that have the element as an ancestor"
},
{
"type":"optional",
"name":"default-mode",
"description":"Defines the default value for the mode attribute of all <xsl:template> and <xsl:apply-templates> elements within its scope."
},
{
"type":"optional",
"name":"default-validation",
"description":"Defines the default value of the validation attribute of all relevant instructions appearing within its scope."
},
{
"type":"optional",
"name":"expand-text",
"description":"Determines whether descendant text nodes of the element are treated as text value templates."
},
{
"type":"optional",
"name":"id",
"description":"Specifies an id for this stylesheet. This is most often used when the stylesheet is embedded in another XML document."
},
{
"type":"optional",
"name":"input-type-annotations",
"description":"Specifies whether type annotations are stripped from the element so the same results are produced whether the source documents have been validated against a schema or not."
},
{
"type":"optional",
"name":"use-when",
"description":"Determines whether the element and all the nodes that have it as ancestor are excluded from the stylesheet."
},
{
"type":"optional",
"name":"xpath-default-namespace",
"description":"Specifies the namespace that will be used if the element name is unprefixed or an unprefixed type name within an XPath expression."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/stylesheet",
"output": "XSLT Stylesheet"
},
{
"name": "<xsl:tranform>",
"description": "Exactly equivalent to the <xsl:stylesheet> element.",
"attributes":
[
{
"type":"required",
"name":"version",
"description":"Specifies the version of XSLT required by this stylesheet."
},
{
"type":"optional",
"name":"exclude-result-prefixes",
"description":"Specifies any namespace used in this document that should not be sent to the output document."
},
{
"type":"optional",
"name":"extension-element-prefixes",
"description":"Specifies a space-separated list of any namespace prefixes for extension elements in this document."
},
{
"type":"optional",
"name":"default-collation",
"description":"Specifies the default collation used by all XPath expressions appearing in attributes or text value templates that have the element as an ancestor"
},
{
"type":"optional",
"name":"default-mode",
"description":"Defines the default value for the mode attribute of all <xsl:template> and <xsl:apply-templates> elements within its scope."
},
{
"type":"optional",
"name":"default-validation",
"description":"Defines the default value of the validation attribute of all relevant instructions appearing within its scope."
},
{
"type":"optional",
"name":"expand-text",
"description":"Determines whether descendant text nodes of the element are treated as text value templates."
},
{
"type":"optional",
"name":"id",
"description":"Specifies an id for this stylesheet. This is most often used when the stylesheet is embedded in another XML document."
},
{
"type":"optional",
"name":"input-type-annotations",
"description":"Specifies whether type annotations are stripped from the element so the same results are produced whether the source documents have been validated against a schema or not."
},
{
"type":"optional",
"name":"use-when",
"description":"Determines whether the element and all the nodes that have it as ancestor are excluded from the stylesheet."
},
{
"type":"optional",
"name":"xpath-default-namespace",
"description":"Specifies the namespace that will be used if the element name is unprefixed or an unprefixed type name within an XPath expression."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/transform",
"output": "XSLT Stylesheet"
},
{
"name": "<xsl:import>",
"description": "Top-level element that serves to import the contents of one stylesheet into another stylesheet.",
"attributes":
[
{
"type":"required",
"name":"href",
"description":"Specifies the URI of the stylesheet to import."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/import",
"output": "XSLT Stylesheet from another file"
},
{
"name": "<xsl:include>",
"description": "Merges the contents of one stylesheet with another. Unlike the case of <xsl:import>, the contents of an included stylesheet have exactly the same precedence as the contents of the including stylesheet.",
"attributes":
[
{
"type":"required",
"name":"href",
"description":"Specifies the URI of the stylesheet to import."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/include",
"output": "XSLT Stylesheet with XSLT from another file."
},
{
"name": "<xsl:namespace-alias>",
"description": "Maps a namespace in the stylesheet to a different namespace in the output tree. The most common use for this element is in generating a stylesheet from another stylesheet.",
"attributes":
[
{
"type":"required",
"name":"stylesheet-prefix",
"description":"Specifies the temporary namespace."
},
{
"type":"required",
"name":"result-prefix",
"description":"Specifies the desired namespace for the output tree."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/namespace-alias",
"output": "XML Tree with changed namespaces"
},
{
"name": "<xsl:element>",
"description": "Creates an element in the output document.",
"attributes":
[
{
"type":"required",
"name":"name",
"description":"Specifies the desired name of the output element. The name must be a valid QName."
},
{
"type":"optional",
"name":"namespace",
"description":"Specifies the namespace of the output element."
},
{
"type":"optional",
"name":"use-attribute-sets",
"description":"A whitespace-separated list of attribute-set element names to be applied to the element element's output element."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/namespace-alias",
"output": "XML with provided element"
}
]
},
{
"name":"Variables and parameters",
"entries":
[
{
"name": "<xsl:param>",
"description": "Establishes a parameter by name and, optionally, a default value for that parameter. When used as a top-level element, the parameter is global. When used inside an <xsl:template> element, the parameter is local to that template.",
"attributes":
[
{
"type":"required",
"name":"name",
"description":"Names the parameter. This must be a QName."
},
{
"type":"optional",
"name":"select",
"description":"Uses an XPath expression to provide a default value if none is specified."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/param",
"output": "XML parameter"
},
{
"name": "<xsl:variable>",
"description": "Declares a global or local variable in a stylesheet and gives it a value.",
"attributes":
[
{
"type":"required",
"name":"name",
"description":"Gives the variable a name."
},
{
"type":"optional",
"name":"select",
"description":"Defines the value of the variable through an XPath expression. If the element contains a template, this attribute is ignored."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/variable",
"output": "XML Variable"
},
{
"name": "<xsl:with-param>",
"description": "Sets the value of a parameter to be passed into a template.",
"attributes":
[
{
"type":"required",
"name":"name",
"description":"Gives this parameter a name."
},
{
"type":"optional",
"name":"select",
"description":"Defines the value of the parameter through an XPath expression. If the element contains a template, this attribute is ignored."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/with-param",
"output": "XML Parameter"
},
{
"name": "<xsl:copy-of>",
"description": "Makes a deep copy (including descendant nodes) of whatever the select attribute specifies to the output document.",
"attributes":
[
{
"type":"required",
"name":"select",
"description":"Uses an XPath expression that specifies what is to be copied."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/copy-of",
"output": "Copy of Selected node"
}
]
},
{
"name":"Misc",
"entries":
[
{
"name": "<xsl:message>",
"description": "Outputs a message (to the JavaScript Console in NS) and optionally terminates execution of the stylesheet.",
"attributes":
[
{
"type":"optional",
"name":"terminate",
"description":"Set to \"yes\", indicates that execution should be terminated. The default value is \"no\", in which case the message is output and execution continues."
}
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/message",
"output": "Message in console"
},
{
"name": "<xsl:fallback>",
"description": "specifies what template to use if a given extension (or, eventually, newer version) element is not supported.",
"attributes":
[
],
"examples": [],
"documentationReferenceURL": "https://developer.mozilla.org/en-US/docs/Web/XSLT/Element/fallback",
"output": "Fallbacks"
}
]
}
]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,52 @@
{
"universalInfo":
[
{
"category":"What is XSLT",
"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":"Differences between XSLT versions"
}
],
"VersionDiffs":
[
{
"version":"2.0",
"diffs":
[
"Introduced a richer data model with support for various data types and sequences, allowing more flexible handling of data.",
"Added native support for regular expressions, making text processing and pattern matching more powerful.",
"Introduced the concept of higher-order functions, enabling functions to be used as arguments and returned as results, enhancing the language's functional capabilities.",
"Expanded the set of built-in string functions, making string manipulation and formatting more versatile.",
"Introduced the concept of sequences, where nodes could be processed without relying solely on their order in the source document.",
"Provided improved error handling and reporting mechanisms, making it easier to diagnose and fix issues in transformations.",
"Allowed variable and function parameters to have type annotations, enhancing clarity and enabling better optimization.",
"Refined the handling of namespaces and introduced features for dealing with namespaces more effectively.",
"Introduced more advanced grouping capabilities, allowing grouping based on multiple criteria.",
"Expanded sorting options, making it possible to sort data based on multiple keys and in different directions."
]
},
{
"version":"3.0",
"diffs":
[
"Extended the support for higher-order functions by introducing new functions like map and filter, enabling more functional programming patterns.",
"Introduced streaming capabilities, allowing processing of large documents without loading the entire document into memory, which improves performance and memory usage.",
"Introduced functions to parse and serialize JSON data, enabling transformations between XML and JSON formats.",
"Enhanced type annotations, allowing for more precise typing of variables and parameters, aiding both readability and optimization.",
"Introduced new standard functions, expanding the range of operations and calculations that can be performed within transformations.",
"Introduced a new data structure called maps, allowing for efficient key-value pair storage and manipulation.",
"Introduced tunnel parameters, which can pass data through templates without explicitly listing them in the template's parameter list",
"Introduced a try-catch construct for better error handling, allowing you to catch and handle errors more gracefully.",
"Introduced the ability to execute multiple templates concurrently, improving performance in multi-core environments.",
"Integrated new features from XPath 3.1, including support for higher-order functions and enhanced string manipulation functions.",
"Enhanced grouping capabilities, making it more powerful and flexible for complex grouping scenarios.",
"Allowed dynamic function calls using the xsl:evaluate element, enabling more dynamic transformations."
]
}
]
}

Some files were not shown because too many files have changed in this diff Show More