Search code examples
javascriptnode.jsxmlxml2js

Node.js xml2js http.request tag matching


I am trying to work with XML data from an https.request and display it to a web page in table format. I'm trying to follow this tutorial which describes what I would like to do very well: https://programmerblog.net/parse-xml-using-nodejs/

However, I am having an issue filtering the results of XML.

Here is my code:

// MODULES - INCLUDES
var xml2js = require('xml2js');
var parser = new xml2js.Parser();

module.exports = function (app) {
  // FORM - SUBMIT - CUCMMAPPER
  app.post('/cucmmapper/submit', function (req, res) {

    // FORM - DATA COLLECTION
    var cucmpub = req.body.cucmpub;
    var cucmversion = req.body.cucmversion;
    var username = req.body.username;
    var password = req.body.password;

    // JS - VARIABLE DEFINITION
    var authentication = username + ":" + password;
    var soapreplyx = '';
    var cssx = '';

    // HTTP.REQUEST - BUILD CALL
    var https = require("https");
    var headers = {
      'SoapAction': 'CUCM:DB ver=' + cucmversion + ' listCss',
      'Authorization': 'Basic ' + new Buffer(authentication).toString('base64'),
      'Content-Type': 'text/xml; charset=utf-8'
    };

    // SOAP - AXL CALL
    var soapBody = new Buffer('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns="http://www.cisco.com/AXL/API/11.5">' +
      '<soapenv:Header/>' +
      '<soapenv:Body>' +
      '<ns:listCss sequence="?">' +
      '<searchCriteria>' +
      '<name>%</name>' +
      '</searchCriteria>' +
      '<returnedTags uuid="?">' +
      '<name>?</name>' +
      '<description>?</description>' +
      '<clause>?</clause>' +
      '</returnedTags>' +
      '</ns:listCss>' +
      '</soapenv:Body>' +
      '</soapenv:Envelope>');

    // HTTP.REQUEST - OPTIONS
    var options = {
      host: cucmpub, // IP ADDRESS OF CUCM PUBLISHER
      port: 8443, // DEFAULT CISCO SSL PORT
      path: '/axl/', // AXL URL
      method: 'POST', // AXL REQUIREMENT OF POST
      headers: headers, // HEADER VAR
      rejectUnauthorized: false // REQUIRED TO ACCEPT SELF-SIGNED CERTS
    };

    // HTTP.REQUEST - Doesn't seem to need this line, but it might be useful anyway for pooling?
    options.agent = new https.Agent(options);

    // HTTP.REQUEST - OPEN SESSION
    let soapRequest = https.request(options, soapResponse => {
      soapResponse.setEncoding('utf8');
      soapResponse.on('data', chunk => {
        soapreplyx += chunk
      });
      // HTTP.REQUEST - RESULTS + RENDER
      soapResponse.on('end', () => {
        console.log(soapreplyx);
        parser.parseString(soapreplyx, function (err, result) {
          // console.dir(result);
          var cssx = result['soapenv']['ns']['return']['css'];
          console.log(cssx);
          res.render('cucmmapper-results.html', {
            title: 'CUCM 2.1',
            soapreply: soapreplyx,
            css: cssx,
          });
        });
      });
    });

    // SOAP - SEND AXL CALL
    soapRequest.write(soapBody);
    soapRequest.end();
  });
}

I am specifically getting the following console error.

TypeError: Cannot read property 'ns' of undefined
    at C:\Users\PetersonA16\Desktop\listlineapp\listlineapp\routes\cucmmapper.js:68:39

The result of the following:

console.log(soapreplyx);

Replies back with this (edited) data.

<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:listCssResponse xmlns:ns="http://www.cisco.com/AXL/API/11.0">
<return>
<css uuid="{E85C54E1-5737-7516-FFFC-14E97B1D0504}">
<description>description1</description>
<clause>something1</clause>
<name>name1</name>
</css>
<css uuid="{AFFC55A7-CD16-E250-09E8-9A12ABBE0C9E}">
<description>description2</description>
<clause>something2</clause>
<name>name2</name>
</css>
</return>
</ns:listCssResponse>
</soapenv:Body>
</soapenv:Envelope>

If I un-comment out the line:

console.dir(result);

I do get the following console output:

{ 'soapenv:Envelope':
   { '$': { 'xmlns:soapenv': 'http://schemas.xmlsoap.org/soap/envelope/' },
     'soapenv:Body': [ [Object] ] } }

My theory is that I need to use an xml2js option. After some experimentation though, I haven't been able to make any headway.

I'm still new to JS, so any help, pointer, or suggestions would be greatly appreciated!


Solution

  • if you want to get all css nodes, you can try this

    const transform = require('camaro')
    
    const xml = `
    <?xml version='1.0' encoding='utf-8'?>
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
    <ns:listCssResponse xmlns:ns="http://www.cisco.com/AXL/API/11.0">
    <return>
    <css uuid="{E85C54E1-5737-7516-FFFC-14E97B1D0504}">
    <description>description1</description>
    <clause>something1</clause>
    <name>name1</name>
    </css>
    <css uuid="{AFFC55A7-CD16-E250-09E8-9A12ABBE0C9E}">
    <description>description2</description>
    <clause>something2</clause>
    <name>name2</name>
    </css>
    </return>
    </ns:listCssResponse>
    </soapenv:Body>
    </soapenv:Envelope>
    `
    
    const json = transform(xml, {
        css: ['//css', {
            uuid: '@uuid',
            name: 'name',
            description: 'description',
            clause: 'clause'
        }]
    })
    
    console.log(json.css)
    

    Output:

    [ { clause: 'something1',
        description: 'description1',
        name: 'name1',
        uuid: '{E85C54E1-5737-7516-FFFC-14E97B1D0504}' },
      { clause: 'something2',
        description: 'description2',
        name: 'name2',
        uuid: '{AFFC55A7-CD16-E250-09E8-9A12ABBE0C9E}' } ]