Search code examples
javascriptnode.jsjsonxml-parsingxml2js

Cannot access xml attributes when looping over items of xml2js-parsed json


I'm trying to access the attributes of items within an xml rss feed after the xml has been parsed into json using xml2js. I can access individual attributes using items[0].el.$.attribute. However, if I loop over each item I can't go deeper than the el. Trying to go deeper within the loop (using items.map(item => { item.el.$ })) gives me an error where the el is now undefined...

TypeError: Cannot read property '$' of undefined

Here's a [DEMO] and my code (╭ರ_•́)

const express = require('express');
const { parseString } = require('xml2js');
const axios = require('axios');

const app = express();

app.use(express.static('public'));

app.get('/', async (req, res) => {

  const rss = 'https://www.kijiji.ca/rss-srp-rv-camper-trailer/vancouver/c172l1700287'

  axios.get(rss, { responseType: 'text'})
  .then((res) => {
    parseString(res.data, { explicitArray: false }, (err, res) => {
      const items = res.rss.channel.item;

      // THIS WORKS! (╯°o°)╯
      console.log(items[0].enclosure.$.url)

      // THIS DOES NOT WORK... ಠ_ಠ
      items.map(item => {
        console.log(item.enclosure.$.url);
      })

      // THIS WORKS! (╯°o°)╯
      items.map(item => {
        console.log(item.enclosure);
      })

    })
  })
})

// listen for requests :)
const listener = app.listen(process.env.PORT, function() {
  console.log('Your app is listening on port ' + listener.address().port);
});

In the above example I'm parsing this rss feed on kijiji using xml2js. After parsing I can access element attributes using json.rss.channel.item[0].enclosure.$.url.

However, if I loop over the items (using a for loop, forEach or map) I can't get any deeper than json.rss.channel.item[0].enclosure.

What am I missing here?


Solution

  • Running the example locally, I see the item with title: '1999 safari GMC van with wheelchair lift' does not have an enclosure property. I think this is more of a data problem rather than the JavaScript - other than programming this more defensively to account for this.

    You can confirm this with the following inspection of the XML:

    curl https://www.kijiji.ca/rss-srp-rv-camper-trailer/vancouver/c172l1700287 | grep -C 10 "1999 safari GMC van with wheelchair lift"
    ....
        <item>
          <title>1999 safari GMC van with wheelchair lift</title>
          <link>https://www.kijiji.ca/v-travel-trailer-camper/vancouver/1999-safari-gmc-van-with-wheelchair-lift/1430028981</link>
          <description>GMC van with lift for handycap</description>
          <pubDate>Fri, 26 Apr 2019 23:33:07 GMT</pubDate>
          <guid>https://www.kijiji.ca/v-travel-trailer-camper/vancouver/1999-safari-gmc-van-with-wheelchair-lift/1430028981</guid>
          <dc:date>2019-04-26T23:33:07Z</dc:date>
          <geo:lat>49.2819588</geo:lat>
          <geo:long>-123.09482930000001</geo:long>
        </item>
    ...