0

Currently, I'm receiving an API request that has the crazy structure to the data, I'm attempting to parse the XML part of the response to an array/JSON so I can handle it.

Here's the exact request I am receiving:

{ 
  username: 'test',
  apiaccesskey: 'aa7a8157-3c17-4b63-806f-7aeff42ae21f',
  action: 'placeimeiorder',
  requestformat: 'JSON',
  parameters:
   '<PARAMETERS><CUSTOMFIELD>bnVsbA==</CUSTOMFIELD><ID>1</ID><SERVICEID>1</SERVICEID><IMEI>12345678910</IMEI><QNT>1</QNT><SERVER>0</SERVER><MODELID></MODELID><PROVIDERID></PROVIDERID><NETWORK></NETWORK><PIN></PIN><KBH></KBH><MEP></MEP><PRD></PRD><TYPE></TYPE><LOCKS></LOCKS><REFERENCE></REFERENCE><SN></SN><SECRO></SECRO></PARAMETERS>\n',
  version: '7.2' 
}

I've tried parsing using this library (xml2js) but it's generating a result like this:

let parseresult = await parser.parseStringPromise(req.body.parameters);
console.log(parseresult);

{ PARAMETERS:
   { CUSTOMFIELD: [ 'bnVsbA==' ],
     ID: [ '1' ],
     SERVICEID: [ '1' ],
     IMEI: [ '12345678910' ],
     QNT: [ '1' ],
     SERVER: [ '0' ],
     MODELID: [ '' ],
     PROVIDERID: [ '' ],
     NETWORK: [ '' ],
     PIN: [ '' ],
     KBH: [ '' ],
     MEP: [ '' ],
     PRD: [ '' ],
     TYPE: [ '' ],
     LOCKS: [ '' ],
     REFERENCE: [ '' ],
     SN: [ '' ],
     SECRO: [ '' ] } }

which is far from ideal when trying to handle, how could I change it so I could simply access individual key/values like parseresult.IMEI or parseresult.CUSTOMFIELD

3 Answers 3

1

Should just be a setting.

Code:

const xml2js = require('xml2js');
const parser = new xml2js.Parser({ explicitArray: false });

const xml = "<PARAMETERS><CUSTOMFIELD>bnVsbA==</CUSTOMFIELD><ID>1</ID><SERVICEID>1</SERVICEID><IMEI>12345678910</IMEI><QNT>1</QNT><SERVER>0</SERVER><MODELID></MODELID><PROVIDERID></PROVIDERID><NETWORK></NETWORK><PIN></PIN><KBH></KBH><MEP></MEP><PRD></PRD><TYPE></TYPE><LOCKS></LOCKS><REFERENCE></REFERENCE><SN></SN><SECRO></SECRO></PARAMETERS>\n";

parser.parseString(xml, (err, result) => {
    console.dir(result);
});

Reference: https://github.com/Leonidas-from-XIV/node-xml2js#options

Output:

{
  PARAMETERS: {
    CUSTOMFIELD: 'bnVsbA==',
    ID: '1',
    SERVICEID: '1',
    IMEI: '12345678910',
    QNT: '1',
    SERVER: '0',
    MODELID: '',
    PROVIDERID: '',
    NETWORK: '',
    PIN: '',
    KBH: '',
    MEP: '',
    PRD: '',
    TYPE: '',
    LOCKS: '',
    REFERENCE: '',
    SN: '',
    SECRO: ''
  }
}

Alternative: Using the async/await like you have above:

const xml2js = require('xml2js');

(async () => {
    const parser = new xml2js.Parser({ explicitArray: false });
    const xml = "<PARAMETERS><CUSTOMFIELD>bnVsbA==</CUSTOMFIELD><ID>1</ID><SERVICEID>1</SERVICEID><IMEI>12345678910</IMEI><QNT>1</QNT><SERVER>0</SERVER><MODELID></MODELID><PROVIDERID></PROVIDERID><NETWORK></NETWORK><PIN></PIN><KBH></KBH><MEP></MEP><PRD></PRD><TYPE></TYPE><LOCKS></LOCKS><REFERENCE></REFERENCE><SN></SN><SECRO></SECRO></PARAMETERS>\n";

    try {
        console.log(await parser.parseStringPromise(xml))
    } catch (error) {
        console.log('ERROR', error);
    }
})();
Sign up to request clarification or add additional context in comments.

Comments

0

If you want complete control over the conversion, try saxon-js (released on Node.js a couple of weeks ago, available from npm).

For example you could do it in XPath 3.1 like this:

const SaxonJS = require("saxon-js");
SaxonJS.getResource({text:xml, type:"xml"})
.then(doc => {
    SaxonJS.serialize(
      SaxonJS.XPath.evaluate(
           "map:merge(/PARAMETERS/* ! map{name(): string()})", doc),
      {method:"json", indent:true}))});

You could extend this, for example to select which fields of the XML to include in the result.

Or for even more flexibility, you could do it in XSLT3.

(Not tested.)

Comments

0

you can also use camaro, a xpath-powered template to transform the value. it looks like this

const { transform } = require('camaro')

const data = {
    username: 'test',
    apiaccesskey: 'aa7a8157-3c17-4b63-806f-7aeff42ae21f',
    action: 'placeimeiorder',
    requestformat: 'JSON',
    parameters:
        '<PARAMETERS><CUSTOMFIELD>bnVsbA==</CUSTOMFIELD><ID>1</ID><SERVICEID>1</SERVICEID><IMEI>12345678910</IMEI><QNT>1</QNT><SERVER>0</SERVER><MODELID></MODELID><PROVIDERID></PROVIDERID><NETWORK></NETWORK><PIN></PIN><KBH></KBH><MEP></MEP><PRD></PRD><TYPE></TYPE><LOCKS></LOCKS><REFERENCE></REFERENCE><SN></SN><SECRO></SECRO></PARAMETERS>\n',
    version: '7.2',
}

async function main() {
    console.log(await transform(data.parameters, {
        customerField: 'PARAMETERS/CUSTOMFIELD',
        customerId: 'PARAMETERS/ID',
        serviceId: 'PARAMETERS/SERVICEID',
    }));
}

main()

output

{ customerField: 'bnVsbA==', customerId: '1', serviceId: '1' }

If you want more fields, you can just edit the template

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.