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 :) !!