Mark Highton Ridley
Mark Highton Ridley

Reputation: 136

In javascript is there any easier way of mapping inbound rss tags to output rss tags?

I've been going round and round with this Javascript problem for four days and have finally managed to get it working. But I feel sure there must be a much better solution, one involving fewer 'translations', something that puts less strain on the browser.

I feel I should be able to read the xml of the feed, do a little re-mapping of tags in the inbound feed into tags in the outbound one. Can I? Do I have to stick with the solution I've got working:

In a nutshull, I'm taking via an http request an RSS feed that has some media tags. It 'arrives' as the xml of a dom structure that replicates the feed. I then have to reconstruct the feed items (with a little remapping) from that dom so they can be returned to the calling routine (via a global variable).

I've looked into all sorts of potential alternatives: jQuery.get, json and others but all examples I could find online seem to ignore the media items in the inbound feed - at least I couldn't find them when trying to read the feed.

This is an entry in the rss feed being used as the source:

<item>
    <guid isPermaLink="false">https://www.zazzle.com/create_your_own_photostamp_by_stamps_com-172639479866885637?rf=238582202591969585&amp;tc=_041218</guid>
    <pubDate>Mon, 19 Nov 2018 23:49:28 GMT</pubDate>
    <title>
        <![CDATA[Create Your Own PhotoStamp by Stamps.com]]>
    </title>
    <link>https://www.zazzle.com/create_your_own_photostamp_by_stamps_com-172639479866885637?rf=238582202591969585&amp;tc=_041218&amp;pm=</link>
    <author>
        <name>zazzle_templates</name>
    </author>
    <description>
        <![CDATA[]]>
    </description>
    <price>$myItem->price</price>
    <media:title>
        <![CDATA[Create Your Own PhotoStamp by Stamps.com]]>
    </media:title>
    <media:description>
        <![CDATA[Upload your own photo or design to create your set of custom photo postage stamps by Stamps.com!]]>
    </media:description>
    <media:price>$22.95</media:price>
    <media:thumbnail url="https://rlv.zcache.com/create_your_own_photostamp_by_stamps_com-r0453bb627c114b9da57442d3dd284e6a_byxt0_8byvr_152.jpg" />
    <media:content url="https://rlv.zcache.com/create_your_own_photostamp_by_stamps_com-r0453bb627c114b9da57442d3dd284e6a_byxt0_8byvr_500.jpg" />
    <media:keywords>
        <![CDATA[create your own, upload your own, template, postage stamp, mailing stamp, wedding, save the date, anniversary, birthday, occasion]]>
    </media:keywords>
    <media:rating scheme="urn:mpaa">g</media:rating>
</item>

This is the code I'm using (no, I'm not a coder. I mostly code by recognising patterns in examples and understanding equivalence of one thing with another)

(function ($) {
    'use strict';
    $.fn.rssfeed = function (url, options, fn) {
        return this.each(function (i, e) {
            if (!$(e).hasClass('rssFeed')) { $(e).addClass('rssFeed'); }
            if (url === null) { return false; }
            var xmlhttp = new XMLHttpRequest();
            xmlhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        process(this);
        if ($.isFunction(fn)) { fn.call(this, $(e)); }    }
            };
            xmlhttp.open("GET", url , true);
            xmlhttp.send();
        });
    };
    var process = function (xml) {
        var i, xmlDoc, table;
        xmlDoc = xml.responseXML;
        var myItemAsAnObject = [];
        feedLength = xmlDoc.getElementsByTagName("item").length;
        console.log("feed length: " + feedLength);
        if (feedLength == 0) { return false; }
        var x = xmlDoc.getElementsByTagName("item");
        for (var i = 0; i < x.length; i++) {
            myItemAsAnObject[i] = {
    pubDate: x[i].getElementsByTagName("pubDate")[0].firstChild.nodeValue,
    link: x[i].getElementsByTagName("link")[0].firstChild.nodeValue,
    keywords: x[i].getElementsByTagName("media:keywords")[0].childNodes[0].data,
    author: {name: x[i].getElementsByTagName("author")[0].childNodes[0].childNodes[0].nodeValue},
    content: {url: x[i].getElementsByTagName("media:content")[0].attributes[0].nodeValue},
    description: [
        x[i].getElementsByTagName("description")[0].childNodes[0].data,
        x[i].getElementsByTagName("media:description")[0].childNodes[0].data
    ],
    guid: {isPermaLink: "false", content: x[i].getElementsByTagName("guid")[0].childNodes[0].nodeValue},
    price: [
        "$myItem->price",
        x[i].getElementsByTagName("media:price")[0].firstChild.nodeValue
    ],
    thumbnail: {url: x[i].getElementsByTagName("media:thumbnail")[0].attributes[0].nodeValue},
    rating: {
        scheme: x[i].getElementsByTagName("media:rating")[0].attributes[0].nodeValue,
        content: x[i].getElementsByTagName("media:rating")[0].childNodes[0].nodeValue
    },
    title: [
        x[i].getElementsByTagName("title")[0].firstChild.nodeValue,
        x[i].getElementsByTagName("media:title")[0].childNodes[0].data
    ]
            };
        }
        feedContent = myItemAsAnObject;
    };
})(jQuery);

Upvotes: 0

Views: 139

Answers (1)

Geuis
Geuis

Reputation: 42267

Well, the parsing is actually pretty easy if you're only doing it in a browser. The following won't directly work in node but you could use js-dom (but honestly there's better xml parsers you should use in that case.)

https://codepen.io/anon/pen/yQdjyo?editors=0010

const rss = `
<item>
    <guid isPermaLink="false">https://www.zazzle.com/create_your_own_photostamp_by_stamps_com-172639479866885637?rf=238582202591969585&amp;tc=_041218</guid>
    <pubDate>Mon, 19 Nov 2018 23:49:28 GMT</pubDate>
    <title>
        <![CDATA[Create Your Own PhotoStamp by Stamps.com]]>
    </title>
    <link>https://www.zazzle.com/create_your_own_photostamp_by_stamps_com-172639479866885637?rf=238582202591969585&amp;tc=_041218&amp;pm=</link>
    <author>
        <name>zazzle_templates</name>
    </author>
    <description>
        <![CDATA[]]>
    </description>
    <price>$myItem->price</price>
    <media:title>
        <![CDATA[Create Your Own PhotoStamp by Stamps.com]]>
    </media:title>
    <media:description>
        <![CDATA[Upload your own photo or design to create your set of custom photo postage stamps by Stamps.com!]]>
    </media:description>
    <media:price>$22.95</media:price>
    <media:thumbnail url="https://rlv.zcache.com/create_your_own_photostamp_by_stamps_com-r0453bb627c114b9da57442d3dd284e6a_byxt0_8byvr_152.jpg" />
    <media:content url="https://rlv.zcache.com/create_your_own_photostamp_by_stamps_com-r0453bb627c114b9da57442d3dd284e6a_byxt0_8byvr_500.jpg" />
    <media:keywords>
        <![CDATA[create your own, upload your own, template, postage stamp, mailing stamp, wedding, save the date, anniversary, birthday, occasion]]>
    </media:keywords>
    <media:rating scheme="urn:mpaa">g</media:rating>
</item>
`;

const doc = document.createDocumentFragment();
const root = document.createElement('div');
root.innerHTML = rss;

doc.appendChild(root);

// const getValue = (selector) => root.querySelectorAll(selector).innerHTML;

// const obj = {
//   pubDate: getValue('pubDate'),
//   link: getValue('link'),
//   keywords: getValue('media:keywords'),
//   author: {name: ''},
//   content: {url: ''},
//   description: [

//   ],
//   guid: '',
//   thumbnail: '',
//   rating: {
//     scheme: '',
//     content: ''
//   },
//   title: [

//   ]
// };

// console.log(obj);

This converts the xml string into a document fragment, and you can then run queries against it. querySelector and querySelectorAll work fine as long as the xml nodes don't contain :. For example, <media:price> isn't parseable by querySelector.

This should at least make part of your code simpler.

Upvotes: 1

Related Questions