- 5 minutes to read

Base64Decode XML from JSON

On this page, you will learn how to use a Liquid-based Stylesheet. The example displays a base64-encoded XML string embedded in a JSON message. The output is XML.

graph LR Json[JSON Message with base64encoded XML content] stylesheet(Liquid Stylesheet)--> |Transform| xml["XML"] Json --> stylesheet

With Nodinite, you can allow end-users to view message payload in other formats using one or more Stylesheets.

You can use this example to style a JSON-based message into another XML message. This can be a helpful feature to help you remove sensitive information from end-users.

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.

	<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, '&amp;').replace(/</g,'&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
			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

If you apply the liquid example on the Input JSON, the following XML output is the result:

<ns0:Orders xmlns:ns0="SupplyChain.Schemas/1.0">
  <Order>
    <Id>1337</Id>
    <Amount>1337</Amount>
    <City>Skellefteå</City>
  </Order>
</ns0:Orders>

Info

The example performs a Unicode translation.

4. Download button

If you want to download the rendered content, you can use the following adjustment to the example on this page to add a download button to the page.

Remember to adjust the CONTENTTYPE and FILENAME variables found in the code to match the 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, '&amp;').replace(/</g,'&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
    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 part is NOT base64 encoded and contains quotes ("), you can try extracting the content in the following way:

var content = `{{body.content}}`;

Escaped XML Example

{
    "body": {
        "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Document Company=\"ACME\" ExportType=\"FULL\">\n   <ENTITY ACTIVEDATE=\"\"\n BANKACCOUNTID=\"\"\n VENDORGROUPID=\"\"\n VENDORORGANIZATIONNAME=\"\"/>\n</Document>\n"
    }
}

Next Step