4

I'm trying to refactor some node code that is a whole mess of callbacks. I thought that would be nice give promises a try for this purpose. I'm trying to convert some xml string to json with the xml2js node module. The original code was:

"use strict";

var xml2jsParser = require('xml2js').parseString;

var string = "<container><tag3>option3</tag3></container>";

xml2jsParser(string, function(err, result)
{
    console.log(result);
});

and this displays:

{ container: { tag1: [ 'option1' ], tag2: [ 'option2' ], tag3: [ 'option3' ] } }

Following the first answer on this question How do I convert an existing callback API to promises? I tried to wrap the xml2jsParser function using promises in the following way:

"use strict";

var xml2jsParser = require('xml2js').parseString;

function promisesParser(string)
{
    return new Promise(function(resolve, reject)
    {
        xml2jsParser(string, resolve);
    });
}

var string = "<container><tag3>option3</tag3></container>";

promisesParser(string).then(function(err, result){
    console.log(result);
});

This displays undefined through the console instead of the json object as expected. I don't understand why this happens as I was able to successfully do the same with other functions. I know something similar can be achieved with Bluebird promisify functionality but I'd like to do this on plain Javascript without any third party libraries.

Community
  • 1
  • 1
Daniel Siguero
  • 71
  • 1
  • 1
  • 5

4 Answers4

17

Another option is to use native util module's promisify method, available from Node 8.0:

const xml2js = require('xml2js');
const util = require('util');

xml2js.parseStringPromise = util.promisify(xml2js.parseString);

// await xml2js.parseStringPromise(.. your xml ..);
Alex K
  • 6,737
  • 9
  • 41
  • 63
8

You are going to need to wrap it up like this:

return new Promise(function(resolve, reject)
{
    xml2jsParser(string, function(err, result){
         if(err){
             reject(err);
         }
         else {
             resolve(result);
         }
    });
});

Then use it like this:

promisesParser(string).then(function(result){
    console.log(result);
}).catch(function(err){
    //error here
});
MinusFour
  • 13,913
  • 3
  • 30
  • 39
3

There are 2 issues...

  1. You have to resolve with a value if it passes...and reject with an error when it fails

  2. You need to add a catch block to you promise handling chain to catch errors.

var xml2jsParser = require('xml2js').parseString;

function promisesParser(string)
{
    return new Promise(function(resolve, reject)
    {
        xml2jsParser(string, function(err, result) {
            if (err) {
                return reject(err);
             } else {
                return resolve(result);
             }
        });
    });
}

var string = "<container><tag3>option3</tag3></container>";

promisesParser(string)
.then(console.log)
.catch(console.log);
0

I might be too late to this answer, but I thought to share what I have been using

One can use parseStringPromise method of xml2js with await keyword inside an async function.

import { parseStringPromise } from 'xml2js'

export const main = async () => {
    const leadsData = await parseStringPromise(docBody)
    console.log(leadsData)
}
Tyler2P
  • 2,324
  • 26
  • 22
  • 31