0

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!

Andrew Petersen
  • 163
  • 1
  • 9
  • what do you want to extract from that xml? – Tuan Anh Tran Oct 21 '17 at 04:10
  • Thanks for taking a look. I'm hoping to see the information in a JSON format like below (example below). { css_name: 'name1', css_partitions: 'something1' css_name: 'name2', css_partitions: 'something2' } – Andrew Petersen Oct 23 '17 at 13:35
  • i'm not sure what `css_partitions` is i'm just get all the attributes, fields inside `css` node. please see the answer below. – Tuan Anh Tran Oct 23 '17 at 14:00

2 Answers2

0

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}' } ]
Tuan Anh Tran
  • 6,807
  • 6
  • 37
  • 54
  • Tuan, that did the trick! Thank you, for your help! I do get this output: [ '': { cssdescription: 'DHHS_13_CalhounBC_MCP Restricted CSS', cssname: 'DHHS_13_CalhounBC_MCP-CSS', csspartitions: 'DHHS_13_CalhounBC_MCP-PT' } ] Do those leading tick marks [ '': make any difference in the output? Just wondering. Thanks again! – Andrew Petersen Oct 24 '17 at 18:21
  • Not sure if I get it. Can you explain again? – Tuan Anh Tran Oct 24 '17 at 23:44
0

As a note, I did get it to work with xml2js. 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 = '';
    var spacer = '-----';
    var rmline1 = '';
    var rmline2 = '';
    var rmline3 = '';
    var rmline4 = '';
    var rmbottomup1 = '';
    var rmbottomup2 = '';
    var rmbottomup3 = '';

    // 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', () => {

        // EDIT - SCRUB XML OUTPUT
        var rmline1 = soapreplyx.replace(/<\?xml\sversion='1\.0'\sencoding='utf-8'\?>/g, '');
        var rmline2 = rmline1.replace(/<soapenv:Envelope\sxmlns:soapenv="http:\/\/schemas.xmlsoap.org\/soap\/envelope\/">/g, '');
        var rmline3 = rmline2.replace(/<soapenv:Body>/g, '');
        var rmline4 = rmline3.replace(/<ns:listCssResponse\sxmlns:ns="http:\/\/www\.cisco\.com\/AXL\/API\/[0-9]*\.[0-9]">/g, '');
        var rmbottomup1 = rmline4.replace(/<\/soapenv:Envelope>/g, '');
        var rmbottomup2 = rmbottomup1.replace(/<\/soapenv:Body>/g, '');
        var xmlscrubbed = rmbottomup2.replace(/<\/ns:listCssResponse>/g, '');
        // console.log(xmlscrubbed);
        // console.log(spacer);

        // XML2JS - TESTING
        parser.parseString(xmlscrubbed, function (err, result) {
          var cssx = result['return']['css'];
        //   console.log(cssx);
        //   console.log(spacer);
          res.render('cucmmapper-results.html', {
            title: 'CUCM 2.0',
            cucmpub: cucmpub,
            cssx: cssx,
            soapreply: soapreplyx,
            xmlscrubbed: xmlscrubbed
          });
        });
      });
    });

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

Here is my HTML table.

<div class="row">
                    <div class="col-md-12" class="pull-left">
                        <table class="table table-hover table-condensed">
                            <thread>
                                <tr>
                                    <th>CSS</th>
                                    <th>DESCRIPTION</th>
                                    <th>PARTITIONS</th>
                                </tr>
                            </thread>
                            <tbody>
                                {{#each cssx}}
                                <tr>
                                    <td>{{this.name}}</td>
                                    <td>{{this.description}}</td>
                                    <td>{{this.clause}}</td>
                                </tr>
                                {{/each}}
                            </tbody>
                        </table>
                    </div>
                </div>
Andrew Petersen
  • 163
  • 1
  • 9