2

All,

I am trying to parse an HTTP response XML via xml2js and am running into an error. I am trying to follow these instructions: https://programmerblog.net/parse-xml-using-nodejs/

I do have the module installed and seems to be operating correctly.

The error that I'm getting.

    parser.parseString(soapreplyx, function (err, result) {
    ^
ReferenceError: parser is not defined

My app code looks like this.

// APP - INCLUDE
const express = require('express')
const path = require("path")
const bodyParser = require("body-parser")
const hbs = require('hbs')
var xml2js = require('xml2js');
var parser = new xml2js.Parser();

// APP - DEFINITION
const app = express()

// APP - BUILD
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.engine('html', require('hbs').__express);
app.set('view engine', 'html');

// EXPRESS ROUTE - INDEX
app.get('/', function (req, res) {
  res.render(path.join(__dirname+ '/views/index.html'), {
    'title': 'CUCM 2.0'
  });
})

// EXPRESS ROUTING - INCLUDE - CUCM MAPPER
var routingextensions = require(__dirname+ '/routes/cucmmapper.js')(app);

// APP - START
app.listen(3000, function () {
  console.log('CUCM 2.0 listening on port 3000!')
})

Extra Express Route code.

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 = '';
    //var parser = new xml2js.parser();

    // 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', () => {
        parser.parseString(soapreplyx, function (err, result) {
          var cssx = result['return']['css'];
          res.render('cucmmapper-results.html', {
            title: 'CUCM 2.1',
            soapreply: soapreplyx,
            css: cssx,
        })
        });
      });
    });

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

Here is also an example of the XML that I am getting back from the HTTPRequest.

<?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>description</description>
<clause>blablabla</clause>
<name>name</name>
</css>
<css uuid="{AFFC55A7-CD16-E250-09E8-9A12ABBE0C9E}">
<description>description</description>
<clause>blablabla</clause>
<name>name</name>
</css>

I am really hoping I setup everything correctly, but am new to all things JS. Any advice or help is very welcome. Thanks for taking the time to look and help me out!

Andrew Petersen
  • 163
  • 1
  • 9
  • 1
    Variables are scoped to their respective files. You need to create the parser in the router file. – skirtle Oct 19 '17 at 14:41

1 Answers1

0

In node.js every file is its own module. This means that variables defined in one module are not global and are not automatically available in other files unless you explicitly export them.

So in your code when you define:

var xml2js = require('xml2js');
var parser = new xml2js.Parser();

in your app module, you won't be able to access it in your extra routes module, which is what the error is trying to say. The solution is to simply place the definitions in the other files:

var xml2js = require('xml2js');
var parser = new xml2js.Parser();

module.exports = function (app) {
  // FORM - SUBMIT - CUCMMAPPER
  app.post('/cucmmapper/submit', function (req, res) {
  // etc...
}
Mark
  • 90,562
  • 7
  • 108
  • 148