0

I'm trying to build a Node.js web app with Express.js, that reads values from an external xml file, and store all the data values in a single array. There are multiple xml files to be read so the same process is repeated.

function loadSoftwareRequestXML(filename){
var xmlparser = new xml2js.Parser();
var software_request = new Array();
var filepath = "/project_requests/" + filename;
fs.readFile(filepath, "utf-8", function(error, values){
    xmlparser.parseString(values, function(error, xmlfile){
        var xmldata = xmlfile;
        date_requested = xmldata.ProjectRequest.DateRequested;
        client_org = xmldata.ProjectRequest.ClientOrganization;
        proposed_budget = xmldata.ProjectRequest.ProposedBudget;
        contact_name = xmldata.ProjectRequest.ContactName;
        delivery_date = xmldata.ProjectRequest.DeliveryDate;
        requirements = xmldata.ProjectRequest.UserRequirements;
        //software_request = [date_requested, client_org, proposed_budget, contact_name, delivery_date, requirements];
        software_request.push(date_requested);
        software_request.push(client_org);
    });
});
console.log(software_request);
return software_request;
}

The problem I'm having is that for 'software_request', the array variable that stores the retrieved xml data, it works when it is inside the xmlparser function. But when it is traced with console.log() just before the return statement, it becomes an empty array.

How would you fix this? Please feel free to comment. Any help or advice is appreciated.

1 Answers1

0

In node.js, I/O is asynchronous so functions like readFile and parseString do not complete in the same event loop that they are called. This means that code that is written after them will be called first.

When an asynchronous event completes, there are many ways to signify its completion and react to it. Callbacks are very common in node.js. The function (error value) that you pass as arguments to these functions are called when the asynchronous event is done.

fs.readFile(file, cb);
return software_request; // this gets called before `cb`

To keep this pattern, you can pass a callback to loadSoftwareRequestXML

function loadSoftwareRequestXML(filename, cb){
    const xmlparser = new xml2js.Parser();
    const software_request = [];
    const filepath = "/project_requests/" + filename;
    fs.readFile(filepath, "utf-8", function(error, values){
        xmlparser.parseString(values, function(error, xmlfile){
            /* snip */
            console.log(software_request);
            cb(error, software_request);
        });
    });
}

Essentially, you can't return from callbacks.

You should also handle the errors if they are there.

Explosion Pills
  • 188,624
  • 52
  • 326
  • 405
  • Hello, thank you for your reply. I've added callback to the function as suggested. When i run the code, the console returns error message saying "callback is not a function". How would you fix this? – Andrew Zhao Nov 23 '16 at 18:16