Base64-decode XML from JSON with a Liquid Stylesheet
Decode base64-encoded XML embedded in JSON messages and render it as readable XML in Nodinite Log Views. This Liquid-based Stylesheet enables operators to preview, inspect, and download XML content directly—no additional tooling required.
Benefits:
- ✅ View embedded XML inline without external tools
- ✅ Decode base64 client-side for fast previews and diagnostics
- ✅ Export rendered XML for sharing or offline analysis
with base64-encoded XML"] --> stylesheet["fa:fa-droplet Liquid Stylesheet
with JavaScript"] stylesheet -->|"Transform"| xml["fa:fa-file-lines Readable XML
in the Log View"] style Json fill:#2678BD,color:#fff style stylesheet fill:#E47528,color:#fff style xml fill:#93d16d,color:#000
The JSON input (blue) passes the Liquid Stylesheet (orange) and appears as readable XML (green). The StylesheetScriptsEnabled System Parameter must be true for the JavaScript to run.
This example demonstrates how to transform a JSON message containing base64-encoded XML into rendered XML output using a Liquid Stylesheet. Use this approach to make data accessible to end-users while optionally removing sensitive information.
1. Input JSON
The following data is an example of a JSON message with a base64 encoded content:
{
"method": "post",
"queries": {
"systemProperties": "Run Details"
},
"path": "/orders/messages",
"host": {
"connection": {
"name": "/subscriptions/ae3da538-3e2b-4490-9feb-7dfe30a6683c/resourceGroups/Default-Storage-NorthEurope/providers/Microsoft.Web/connections/servicebus"
}
},
"body": {
"ContentData": "PG5zMDpPcmRlcnMgeG1sbnM6bnMwPSJTdXBwbHlDaGFpbi5TY2hlbWFzLzEuMCI+CiAgPE9yZGVyPgogICAgPElkPjEzMzc8L0lkPgogICAgPEFtb3VudD4xMzM3PC9BbW91bnQ+CiAgICA8Q2l0eT5Ta2VsbGVmdGXDpTwvQ2l0eT4KICA8L09yZGVyPgo8L25zMDpPcmRlcnM+",
"CorrelationId": "BOWC123",
"Properties": {
"ExtendedProperties/1.0#SystemInterchangeId": "BOWC123"
}
}
}
2. Liquid Stylesheet
Use a Liquid Stylesheet to decode and render the base64-encoded XML content.
Warning
Script Execution Requirement: This stylesheet contains embedded JavaScript code. The StylesheetScriptsEnabled system parameter must be set to
truefor this stylesheet to execute. Only members of the built-in Administrators role can enable this parameter. See StylesheetScriptsEnabled for security considerations.
Important
Configuration Required: Enable "Message Body is Json" in the Stylesheet settings. When enabled, Nodinite parses the JSON message and injects properties as Liquid variables, allowing you to access nested properties like
{{body['ContentData']}}directly in your Liquid template.
<textarea rows="50" cols="50" style="border: none;outline: none;" id="demo"> </textarea>
<pre id="demoprint" style="margin:0; padding:0; border:none; display:none;"></pre>
<script>
var editor;
function codemirroreditor(elem) {
var mime = 'application/xml';
editor = CodeMirror.fromTextArea(elem, {
lineNumbers: true,
mode: mime,
indentWithTabs: true,
smartIndent: true,
lineNumbers: true,
matchBrackets: true,
lineWrapping: true,
autofocus: true,
autoRefresh: true,
extraKeys: { "Ctrl-Space": "autocomplete" }
});
}
function b64DecodeUnicode(str) {
return decodeURIComponent(
atob(str)
.split('')
.map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
})
.join('')
);
}
var content = b64DecodeUnicode("{{body['ContentData']}}");
function displayXml() {
var elem = document.getElementById('demo');
elem.value = content;
codemirroreditor(elem);
};
function htmlEntities(str) {
var htmlString = String(str).replace(/&/g, '&').replace(/</g,'<').replace(/>/g, '>').replace(/"/g, '"');
return htmlString;
}
window.addEventListener('beforeprint', (event) => {
$(editor.getWrapperElement()).hide();
$("#demoprint").html(htmlEntities(content)).show();
});
window.addEventListener('afterprint', (event) => {
$(editor.getWrapperElement()).show();
$("#demoprint").hide();
});
displayXml();
</script>
<style>
html {height:calc(100vh - 200px); min-height:500px;}
body {height:100%;}
.CodeMirror {
min-height: 200px;
height: 100%;
}
</style>
3. XML Output
Applying the Liquid Stylesheet to the Input JSON produces the following XML output:
<ns0:Orders xmlns:ns0="SupplyChain.Schemas/1.0">
<Order>
<Id>1337</Id>
<Amount>1337</Amount>
<City>Skellefteå</City>
</Order>
</ns0:Orders>
Note
This example performs Unicode translation to properly handle special characters like "å" in the City field.
4. Download Button
Add a download button to allow users to save the rendered XML content locally.
Warning
Script Execution Requirement: This enhanced stylesheet contains embedded JavaScript code. The StylesheetScriptsEnabled system parameter must be set to
truefor this stylesheet to execute. See StylesheetScriptsEnabled for security considerations.
Instructions: Adjust the CONTENTTYPE and FILENAME variables in the code below to match your expected file type.
<button class="btn btn-success" id="downloadButton">Download</button>
<style>
.btn {
display: inline-block;
font-weight: 400;
color: #212529;
text-align: center;
vertical-align: middle;
user-select: none;
background-color: transparent;
border: 1px solid transparent;
padding: 0.375rem 0.75rem;
font-size: 1rem;
line-height: 1.5;
border-radius: 0.25rem;
transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
box-sizing: border-box;
margin: 1rem;
}
.btn-success {
color: #fff;
background-color: #68a19b;
border-color: #68a19b;
box-shadow: inset 0 1px 0 rgb(255 255 255 / 15%), 0 1px 1px rgb(0 0 0 / 8%);
}
html {height:calc(100vh - 200px); min-height:400px;}
body {height:100%;}
.CodeMirror {
min-height: 200px;
height: calc(100%-40px);
}
</style>
<textarea rows="50" cols="50" id="demo"></textarea>
<pre id="demoprint" style="margin:0; padding:0; border:none; display:none;"></pre>
<script>
(function() {
///// CHANGE THIS
var CONTENTTYPE = "application/xml";
var FILENAME = "out.xml";
////////////////
var editor;
function codemirroreditor(id) {
var mime = 'application/xml';
editor = CodeMirror.fromTextArea(
document.getElementById(id),
{
lineNumbers: true,
mode: mime,
indentWithTabs: true,
smartIndent: true,
lineNumbers: true,
matchBrackets: true,
lineWrapping: true,
autofocus: true,
autoRefresh: true,
extraKeys: { "Ctrl-Space": "autocomplete" }
}
);
}
function b64DecodeUnicode(str) {
return decodeURIComponent(atob(str).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}
var content = b64DecodeUnicode("{{ body['ContentData'] }}");
function displayXml() {
$("#demo").html(content);
codemirroreditor('demo');
};
function htmlEntities(str) {
var htmlString = String(str).replace(/&/g, '&').replace(/</g,'<').replace(/>/g, '>').replace(/"/g, '"');
return htmlString;
}
window.addEventListener('beforeprint', (event) => {
$(editor.getWrapperElement()).hide();
$("#demoprint").html(htmlEntities(content)).show();
$("#downloadButton").hide();
});
window.addEventListener('afterprint', (event) => {
$(editor.getWrapperElement()).show();
$("#demoprint").hide();
$("#downloadButton").show();
});
displayXml();
function save(filename, data) {
const blob = new Blob([data], {type: CONTENTTYPE});
if(window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveBlob(blob, filename);
}
else{
const elem = window.document.createElement('a');
elem.href = window.URL.createObjectURL(blob);
elem.download = filename;
document.body.appendChild(elem);
elem.click();
document.body.removeChild(elem);
}
}
$("#downloadButton").click(() => { save(FILENAME, content) } )
})();
</script>
Escaped XML
If your content is not base64-encoded and contains quotes ("), extract the content using template literals:
var content = `{{body.content}}`;
Escaped XML Example
{
"body": {
"content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Document Company=\"CONTOSO\\\" ExportType=\"FULL\">\n <ENTITY ACTIVEDATE=\"\"\n BANKACCOUNTID=\"\"\n VENDORGROUPID=\"\"\n VENDORORGANIZATIONNAME=\"\"/>\n</Document>\n"
}
}
Next Steps
- Add or manage Stylesheet – Install the Liquid stylesheet and test it with Preview
- StylesheetScriptsEnabled – Allow the embedded JavaScript to run
Related Topics
- Stylesheets – Manage and customize stylesheets
- Stylesheet Examples – All XSLT and Liquid examples
- Line break an EDIFACT – Another Liquid example with JavaScript
- Alarm Plugin Object – Transform alarm plugin payloads
- Log Views – Create role-specific log views with custom stylesheets
- Message Types – Bind the Stylesheet to the Message Type of your JSON messages
- Character Encoding – How Nodinite decides the body encoding before the Stylesheet runs