node-xml2js icon indicating copy to clipboard operation
node-xml2js copied to clipboard

TypeError: parser.parseStringPromise is not a function

Open paul-uz opened this issue 4 years ago • 14 comments

Following the Promise example from the README, I get the error message "TypeError: parser.parseStringPromise is not a function"

paul-uz avatar Feb 22 '21 17:02 paul-uz

Are you using the version from git master?

Leonidas-from-XIV avatar Feb 22 '21 18:02 Leonidas-from-XIV

Whatever version is installed using npm i xml2js

paul-uz avatar Feb 23 '21 09:02 paul-uz

That might not have the function yet.

Leonidas-from-XIV avatar Feb 23 '21 09:02 Leonidas-from-XIV

Is there a timeline for getting master pushed to npm? Right now the docs confusingly do not match the code when you use it the "normal" way (I would expect the vast majority of people interact with this library via npm, vs some sort of git pull based installation)

cozmo avatar Mar 01 '21 18:03 cozmo

Is there any update on this issue? It's now June and the npm version still does not have this function available.

Zei33 avatar Jun 04 '21 03:06 Zei33

I used the following workaround while waiting for this to be fixed (Typescript):

import { promisify } from 'util';
import { convertableToString, ParserOptions, parseString } from 'xml2js';

(...)

// Workaround for https://github.com/Leonidas-from-XIV/node-xml2js/issues/601
const parseStringPromise = promisify<
  convertableToString,
  ParserOptions,
  unknown
>(parseString);

thodoo avatar Jun 17 '21 10:06 thodoo

the problem is in @types/xml2js

export function parseStringPromise(str: convertableToString, options?: ParserOptions): Promise<any>;

it is missing the entire function block.

It should look something like

export function parseStringPromise(xml: convertableToString, options?:  ParserOptions): Promise<any> {
  return new Promise((resolve, reject) => {
    if (options) parseString(xml, options, (err: Error, result: any) => {
      if (err) reject(err)
      else resolve(result)
    })
    else parseString(xml, (err: Error, result: any) => {
      if (err) reject(err)
      else resolve(result)
    })
  })
}

dbryar avatar Oct 20 '21 23:10 dbryar

but with that I am getting an "Error: Unexpected end" at the end of my XML string(s) from the SaxJS parser :-(

dbryar avatar Oct 20 '21 23:10 dbryar

Hi, I faced the same issue, but in a bit different way. Here is my class code:

class MyClass {
 // ...
  async xmlToJson(string) {
    log.debug(`typeof xml2js: ${typeof xml2jsLib}`);
    log.debug(`typeof xml2js.parseStringPromise: ${typeof xml2js.parseStringPromise}`);
    try {
      const json = await xml2jsLib.parseStringPromise(string);
      log.debug('convert xml to json is done');
      return json;
    } catch (e) {
      log.error(`convert xml to json error: ${e && e.message}`, { stack: e && e.stack });
      return null;
    }
  }
}  

When I run this function inside tests, everything works fine:

[2021-11-11T13:01:36.983Z][  DEBUG  ]:: typeof xml2js: object ::
[2021-11-11T13:01:36.984Z][  DEBUG  ]:: typeof xml2js.parseStringPromise: function ::
[2021-11-11T13:01:36.990Z][  DEBUG  ]:: convert xml to json is done ::

When I added this class as dependency to http server, and call the endpoint (POST method) through Postman, i've got an error:

[2021-11-11T13:00:43.267Z][  DEBUG  ]:: typeof xml2js: object ::
[2021-11-11T13:00:43.267Z][  DEBUG  ]:: typeof xml2js.parseStringPromise: undefined ::
[2021-11-11T13:00:43.268Z][  ERROR  ]:: convert xml to json error: xml2js.parseStringPromise is not a function ::

Aslo I have a couple of other endpoints (GET methods), and they work fine. No such error parseStringPromise is not a function

eugen-klm avatar Nov 11 '21 13:11 eugen-klm

the problem is in @types/xml2js

export function parseStringPromise(str: convertableToString, options?: ParserOptions): Promise<any>;

it is missing the entire function block.

It should look something like

export function parseStringPromise(xml: convertableToString, options?:  ParserOptions): Promise<any> {
  return new Promise((resolve, reject) => {
    if (options) parseString(xml, options, (err: Error, result: any) => {
      if (err) reject(err)
      else resolve(result)
    })
    else parseString(xml, (err: Error, result: any) => {
      if (err) reject(err)
      else resolve(result)
    })
  })
}

This is a typescript definition file - it inherently cannot have an implementation since it's just declaring and exporting types of exported symbols from the javascript module, so if .dts file has a declaration in it it doesn't necessarily mean that an exported symbol of the module declared in the file actually exists in the module.

MadProbe avatar Feb 08 '22 20:02 MadProbe

@MadProbe why would something that doesn't exist be declared in the definition file?!

paul-uz avatar Feb 09 '22 10:02 paul-uz

@MadProbe why would something that doesn't exist be declared in the definition file?! This can be if the value is a const enum for example - it gets stripped after compilation by typescript if a flag is not specified in compiler options. Also some values cannot exist but declared in file because author didn't update package in time and some values can be removed by deprecation policy and the types package didn't update in time.

MadProbe avatar Feb 09 '22 12:02 MadProbe

FYI - I'm still seeing this issue w/ the npm-installed v0.4.23. Can this get fixed in the next release?

mmcfarland-novetta avatar Feb 09 '22 20:02 mmcfarland-novetta

You can write your own parseStringPromise, something like this:

const parseStringPromise = (xml, options) => new Promise((resolve, reject) => {
    xml2js(xml, options, (err, result) => {
        if (err) {
            reject(err);
            return;
        }

        resolve(result);
    });
});

usage:

const parsedContent = await parseStringPromise(xml, parserOptions);

NastyaSmirnova avatar Sep 01 '22 13:09 NastyaSmirnova