3

I am new to node.js and need to parse XML. In js, I just use a DOMParser and use getElementsByTagName to get the values I desire. I have just switched to node and am using xml2js (willing to consider alternatives). I have not been able to figure out how to parse through the response to get what I am looking for.

Code below:

function parseBody(body){
    var parseString = require('xml2js').parseString;
    var xml = body
    parseString(xml, function (err, result) {
    console.dir(result);
});

and here is the XML I am passing into the function:

<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:int=\"realURLHere">
   <soapenv:Header/>
   <soapenv:Body>
      <int:readResponse>
         <response>
            <request>?</request>
            <cust>
               <fName>?</fName>
            </cust>
        </response>
      </int:readResponse>
   </soapenv:Body>
</soapenv:Envelope>

Here is the output of my function:

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

I am trying to access the value of <fName> within <cust> but having no luck. Any help would be appreciated. Thanks!

Farhan Yaseen
  • 2,507
  • 2
  • 22
  • 37
rocketlobster
  • 690
  • 7
  • 18

4 Answers4

4

If you set the xplicitArray option to false, when it parses it won't create those arrays where you didn't expect. Like this:

function parseBody(body) {
    var parseString = require('xml2js').parseString;

    const options = {
        explicitArray: false
    };

    var xml = body
    parseString(xml, options, function (err, result) {
        console.log("cust fname: " + result['soapenv:Envelope']['soapenv:Body']['int:readResponse']['response']['cust']['fName']);
    })
}
var input = '<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:int=\"realURLHere"><soapenv:Header/><soapenv:Body><int:readResponse><response><request>?</request><cust><fName>?</fName></cust></response></int:readResponse></soapenv:Body></soapenv:Envelope>';
parseBody(input);

Furthermore if you remove the prefixes it can get even cleaner:

function parseBody(body) {
    var parseString = require('xml2js').parseString;
    var stripNS = require('xml2js').processors.stripPrefix;

    const options = {
        tagNameProcessors: [stripNS],
        explicitArray: false
    };

    var xml = body
    parseString(xml, options, function (err, result) {
        console.log("cust fname: " + result.Envelope.Body.readResponse.response.cust.fName);
    })
}
var input = '<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:int=\"realURLHere"><soapenv:Header/><soapenv:Body><int:readResponse><response><request>?</request><cust><fName>?</fName></cust></response></int:readResponse></soapenv:Body></soapenv:Envelope>';
parseBody(input);```
2

var custFName = result['soapenv:Envelope']['soapenv:Body'][0]['int:realURLHe‌​re'][0]['response'][‌​0]['cust'][0]['fName‌​'];

This solved my problem. My struggles had to do with this response having everything in an array. If there is an easier way to do this or something more dynamic, please let me know. But for now, this worked.

rocketlobster
  • 690
  • 7
  • 18
  • Try the below answer – Tuan Anh Tran Aug 10 '17 at 10:01
  • Thanks rocketlobster. Was having trouble navigating through the XML dom, didn't include the first element with the colon, in your case, the ['soapenv:Envelope'] and also the [0] for every element. Thanks! – StefanBob Jun 08 '18 at 14:44
0

Try this

const transform = require('camaro')

const xml = `
<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:int=\"realURLHere">
   <soapenv:Header/>
   <soapenv:Body>
      <int:readResponse>
         <response>
            <request>?</request>
            <cust>
               <fName>hello world</fName>
            </cust>
        </response>
      </int:readResponse>
   </soapenv:Body>
</soapenv:Envelope>
`

const template = {
    fname: '//cust/fName'
}

const result = transform(xml, template)
console.log(JSON.stringify(result, null, 2))

Which print out

{
  "fname": "hello world"
}

You can access by using result.fname

Tuan Anh Tran
  • 6,807
  • 6
  • 37
  • 54
0

If you're using NodeJS, I highly recommend xml2js & xml2js-xpath. Here is their sample code that really helped me in a pinch.

var xml2js = require("xml2js");
var xpath = require("xml2js-xpath");
 
xml2js.parseString('<root><element id="15">target</element></root>', function(err, json) {

  // find all elements: returns xml2js JSON of the element
  var matches = xpath.find(json, "//element");
 
  // find the first element, and get its id:
  var matches = xpath.evalFirst(json, "//element", "id");
});
dpaul
  • 1
  • 1