Salesforce doesn't have direct method to read files. We can do it either by external service written in Java/.Net or using javascript.
We will be discussing to parse data coming in zipped XML over http from 3-party API and populate data in salesforce. Basically, there were three main tasks:
Task 3:
Task 2:
Key points to remember:
We will be discussing to parse data coming in zipped XML over http from 3-party API and populate data in salesforce. Basically, there were three main tasks:
- Collect http reponse from API in form of zipped xml.
- Unzip that response and get xml string out of it.
- Parse xml string to insert data.
Main focus of this blog is to accomplish Task 2 but first let see the key points for tasks 1 & 3:
Task 1:
- You just need to call response.getBodyAsBlob() when ever response is in form of file.
- Then, you need to convert bolb into string using code syntax:
String xmlzippedFile = EncodingUtil.base64Encode(res.getBodyAsBlob());
Task 3:
- If your XML string contains <![CDATA[value]]> tag then make use of XmlStreamReader class.
- If not, then you can either use Document class or XmlStreamReader class.
Task 2:
Main task to unzip xml file, the steps to achieve are mentioned below:
- Add jZip.js file to static resource (download)
- Add inflate.js file to static resource. (download)
- Open notepad, paste below code and save as file.js file and upload to static resource.
var filearr = []; /* Main unzip function */ function unzip(zip){ model.getEntries(zip, function(entries) { entries.forEach(function(entry) { model.getEntryFile(entry, "Blob"); }); }); } //model for zip.js var model = (function() { var URL = window.webkitURL || window.mozURL || window.URL; var acount = 0; var bcount = 0; //compile a list of file extensions and content types var mapping = { "pdf":"application/pdf", "zip":"application/zip", "rar":"application/rar", "json":"application/json", "mid":"audio/mid", "mp3":"audio/mpeg", "bmp":"image/bmp", "gif":"image/gif", "png":"image/png", "jpg":"image/jpeg", "jpeg":"image/jpeg", "svg":"image/svg+xml", "xml":"text/xml" } return { getEntries : function(file, onend) { zip.createReader(new zip.BlobReader(file), function(zipReader) { zipReader.getEntries(onend); }, onerror); }, getEntryFile : function(entry, creationMethod, onend, onprogress) { acount++; var writer, zipFileEntry; function getData() { entry.getData(writer, function(blob) { bcount++; filearr.push(blob); if(acount == bcount){ //your vf page method waitForProcess(); } }, onprogress); } var extension = entry.filename.substring(entry.filename.indexOf(".")+1); var mime = mapping[extension] || 'text/plain'; writer = new zip.BlobWriter(mime); getData(); } }; })();
- Create a VF page and include reference to jZip.js and file.js
- Create a button on VF page to invoke a javascript remoting method which returns a string from Task 1. (Or you can also place a input file element with button if you just want to upload zipped from client machine).
<!-- place after page start--> <meta charset="utf8" /> <apex:includeScript value="{!URLFOR($Resource.jQuery, '')}"/> <apex:includeScript value="{!URLFOR($Resource.zip, '')}"/> <script> $( document ).ready(function() { //Call loading requestFile(); }); function base64toBlob(base64Data, contentType) { contentType = contentType || ''; var sliceSize = 1024; var byteCharacters = atob(base64Data); var bytesLength = byteCharacters.length; var slicesCount = Math.ceil(bytesLength / sliceSize); var byteArrays = new Array(slicesCount); for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) { var begin = sliceIndex * sliceSize; var end = Math.min(begin + sliceSize, bytesLength); var bytes = new Array(end - begin); for (var offset = begin, i = 0 ; offset < end; ++i, ++offset) { bytes[i] = byteCharacters[offset].charCodeAt(0); } byteArrays[sliceIndex] = new Uint8Array(bytes); } return new Blob(byteArrays, { type: contentType }); } function requestFile() { var param = 5; //set your param to pass in method Visualforce.remoting.Manager.invokeAction( '{!$RemoteAction.APEX_PAGE_CONTROLLER_NAME(GLOBAL).methodName}', param, function(result, event){ if (event.status) { //call unzip method unzip(base64toBlob(result, '')); } else if (event.type === 'exception') { console.log(event.message); } }, {escape: true} ); } var xmlStrResult = []; var isExecuted = false; var timerVal; //your vf page method function waitForProcess(){ console.log('call timer'); timerVal = setInterval('prepareXMLString()', 10); } function prepareXMLString() { if(!isExecuted){ $.each(filearr, function(index, file){ var reader = new FileReader(); // Create a FileReader object reader.onload = function() { // Define an event handler try { var xmlDoc = $.parseXML(reader.result); var xmlString = (new XMLSerializer()).serializeToString(xmlDoc); xmlStrResult.push(xmlString); // Display file contents }catch(err) { //TODO } } reader.readAsText(file); isExecuted = true; }); } if(xmlStrResult.length != 0){ clearInterval(timerVal); $('#showData').val(xmlStrResult[0]); console.log('Done'); } } </script> <apex:pageBlock > <apex:pageBlockSection columns="1" title="Your XML string"> <apex:pageBlockSectionItem > <textarea id="showData" name="showData" rows="30" cols="150"> Please wait.... </textarea> </apex:pageBlockSectionItem> </apex:pageBlockSection> </apex:pageBlock> <apex:includeScript value="{!$Resource.file}" loadOnReady="true"/> <!-- place before page ends-->
Key points to remember:
- Remoting is required, when you get file from apex controller as http response or from attachment/static resource.
- In case of input file element, pass file directly to unzip() method.
Happy coding :) !!
Hi,
ReplyDeleteSyntax error is coming while i am using the above code as
Syntax error. Missing '}'
Please clarify me on this one...
Thanks in advance