Leonidas-from-XIV / node-xml2js

XML to JavaScript object converter.
MIT License
4.84k stars 598 forks source link

TypeError: parser.parseStringPromise is not a function #601

Open paul-uz opened 3 years ago

paul-uz commented 3 years ago

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

Leonidas-from-XIV commented 3 years ago

Are you using the version from git master?

paul-uz commented 3 years ago

Whatever version is installed using npm i xml2js

Leonidas-from-XIV commented 3 years ago

That might not have the function yet.

cozmo commented 3 years ago

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)

Zei33 commented 3 years ago

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

thodoo commented 3 years ago

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);
dbryar commented 2 years ago

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 commented 2 years ago

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

eugen-klm commented 2 years ago

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

MadProbe commented 2 years ago

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.

paul-uz commented 2 years ago

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

MadProbe commented 2 years ago

@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.

mmcfarland-novetta commented 2 years ago

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

NastyaSmirnova commented 1 year ago

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);