tags:

views:

30

answers:

1

hi i'm trying to build an rss reader using javascript. everything is up and running except the hyperlinks. I need to pass a variable that will hold the url for each list item. any advice would be appreciated. thanks.

xml ---------------------------


    <?xml version="1.0"?>
    <rss version="2.0">
      <channel>
            <title>CNN RSS Feed</title>
        <link>http://rss.cnn.com/rss/cnn_world.rss&lt;/link&gt;
        <description>Feeds from Army Public Affairs</description>
        <pubDate>Tue, 11 May 2010 22:04:03 GMT</pubDate>
        <language>en-us</language>

    <item>
            <title>U.S. ambassador to mark Hiroshima</title>
            <link>http://www.cnn.com/2010/WORLD/asiapcf/08/05/japan.us.hiroshima.presence/index.html?eref=rss_world&amp;utm_source=feedburner&amp;utm_medium=feed&amp;utm_campaign=Feed%3A+rss%2Fcnn_world+%28RSS%3A+World%29&lt;/link&gt;
            <pubDate>June 24, 2010</pubDate>
            <source url="http://rss.cnn.com/rss/cnn_world.rss"&gt;CNN&lt;/source&gt;
        </item>
        <item>
            <title>Study: Nearly 1.3 million Mexicans in capital don't have running water</title>

                    <link>http://www.cnn.com/2010/WORLD/americas/08/04/mexico.water.supply/index.html?eref=rss_world&amp;utm_source=feedburner&amp;utm_medium=feed&amp;utm_campaign=Feed%3A+rss%2Fcnn_world+%28RSS%3A+World%29&lt;/link&gt;
            <pubDate>13 July 2010</pubDate>
            <source url="http://rss.cnn.com/rss/cnn_world.rss"&gt;CNN&lt;/source&gt;

        </item> 


      </channel>
    </rss>

//JavaScript File 

    /OBJECTS

    //objects inside the RSS2Item object
    function RSS2Enclosure(encElement)
    {
        if (encElement == null)
        {
            this.url = null;
            this.length = null;
            this.type = null;
        }
        else
        {
            this.url = encElement.getAttribute("url");
            this.length = encElement.getAttribute("length");
            this.type = encElement.getAttribute("type");
        }
    }

    function RSS2Guid(guidElement)
    {
        if (guidElement == null)
        {
            this.isPermaLink = null;
            this.value = null;
        }
        else
        {
            this.isPermaLink = guidElement.getAttribute("isPermaLink");
            this.value = guidElement.childNodes[0].nodeValue;
        }
    }

    function RSS2Source(souElement)
    {
        if (souElement == null)
        {
            this.url = null;
            this.value = null;
        }
        else
        {
            this.url = souElement.getAttribute("url");
            this.value = souElement.childNodes[0].nodeValue;
        }
    }

    //object containing the RSS 2.0 item
    function RSS2Item(itemxml)
    {
        //required
        this.title;
        this.link;
        this.description;

        //optional vars
        this.author;
        this.comments;
        this.pubDate;

        //optional objects
        this.category;
        this.enclosure;
        this.guid;
        this.source;

        var properties = new Array("title", "link", "description", "author", "comments", "pubDate");
        var tmpElement = null;
        for (var i=0; i<properties.length; i++)
        {
            tmpElement = itemxml.getElementsByTagName(properties[i])[0];
            if (tmpElement != null)
                eval("this."+properties[i]+"=tmpElement.childNodes[0].nodeValue");
        }

        this.category = new RSS2Category(itemxml.getElementsByTagName("category")[0]);
        this.enclosure = new RSS2Enclosure(itemxml.getElementsByTagName("enclosure")[0]);
        this.guid = new RSS2Guid(itemxml.getElementsByTagName("guid")[0]);
        this.source = new RSS2Source(itemxml.getElementsByTagName("source")[0]);
    }

    //objects inside the RSS2Channel object
    function RSS2Category(catElement)
    {
        if (catElement == null)
        {
            this.domain = null;
            this.value = null;
        }
        else
        {
            this.domain = catElement.getAttribute("domain");
            this.value = catElement.childNodes[0].nodeValue;
        }
    }

    //object containing RSS image tag info
    function RSS2Image(imgElement)
    {
        if (imgElement == null)
        {
        this.url = null;
        this.link = null;
        this.width = null;
        this.height = null;
        this.description = null;
        }
        else
        {
            imgAttribs = new Array("url","title","link","width","height","description");
            for (var i=0; i<imgAttribs.length; i++)
                if (imgElement.getAttribute(imgAttribs[i]) != null)
                    eval("this."+imgAttribs[i]+"=imgElement.getAttribute("+imgAttribs[i]+")");
        }
    }

    //object containing the parsed RSS 2.0 channel
    function RSS2Channel(rssxml)
    {
        //required
        this.title;
        this.link;
        this.description;

        //array of RSS2Item objects
        this.items = new Array();

        //optional vars
        this.language;
        this.copyright;
        this.managingEditor;
        this.webMaster;
        this.pubDate;
        this.lastBuildDate;
        this.generator;
        this.docs;
        this.ttl;
        this.rating;

        //optional objects
        this.category;
        this.image;

        var chanElement = rssxml.getElementsByTagName("channel")[0];
        var itemElements = rssxml.getElementsByTagName("item");

        for (var i=0; i<itemElements.length; i++)
        {
            Item = new RSS2Item(itemElements[i]);
            this.items.push(Item);
            //chanElement.removeChild(itemElements[i]);
        }

        var properties = new Array("title", "link", "description", "language", "copyright", "managingEditor", "webMaster", "pubDate", "lastBuildDate", "generator", "docs", "ttl", "rating");
        var tmpElement = null;
        for (var i=0; i<properties.length; i++)
        {
            tmpElement = chanElement.getElementsByTagName(properties[i])[0];
            if (tmpElement!= null)
                eval("this."+properties[i]+"=tmpElement.childNodes[0].nodeValue");
        }

        this.category = new RSS2Category(chanElement.getElementsByTagName("category")[0]);
        this.image = new RSS2Image(chanElement.getElementsByTagName("image")[0]);
    }

    //PROCESSES

    //uses xmlhttpreq to get the raw rss xml
    function getRSS()
    {
        //call the right constructor for the browser being used
        if (window.ActiveXObject)
            xhr = new ActiveXObject("Microsoft.XMLHTTP");
        else if (window.XMLHttpRequest)
            xhr = new XMLHttpRequest();
        else
            alert("not supported");

        //prepare the xmlhttprequest object
        xhr.open("GET",document.rssform.rssurl.value,true);
        xhr.setRequestHeader("Cache-Control", "no-cache");
        xhr.setRequestHeader("Pragma", "no-cache");
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4)
            {
                if (xhr.status == 200)
                {
                    if (xhr.responseText != null)
                        processRSS(xhr.responseXML);
                    else
                    {
                        alert("Failed to receive RSS file from the server - file not found.");
                        return false;
                    }
                }
                else
                    alert("Error code " + xhr.status + " received: " + xhr.statusText);
            }
        }

        //send the request
        xhr.send(null);
    }

    //processes the received rss xml
    function processRSS(rssxml)
    {
        RSS = new RSS2Channel(rssxml);
        showRSS(RSS);
    }

    //shows the RSS content in the browser
    function showRSS(RSS)
    {
        //default values for html tags used
        var imageTag = "<img id='chan_image'";
        var startItemTag = "<div id='item'>";
        var startTitle = "<div id='item_title'>";
        var startLink = "<div id='item_link'>";
        var startDescription = "<div id='item_description'>";
        var endTag = "</div>";

        //populate channel data
        var properties = new Array("title","link","description","pubDate","copyright");
        for (var i=0; i<properties.length; i++)
        {
            eval("document.getElementById('chan_"+properties[i]+"').innerHTML = ''");
            curProp = eval("RSS."+properties[i]);
            if (curProp != null)
                eval("document.getElementById('chan_"+properties[i]+"').innerHTML = curProp");
        }

        //show the image
        document.getElementById("chan_image_link").innerHTML = "";
        if (RSS.image.src != null)
        {
            document.getElementById("chan_image_link").href = RSS.image.link;
            document.getElementById("chan_image_link").innerHTML = imageTag
                +" alt='"+RSS.image.description
                +"' width='"+RSS.image.width
                +"' height='"+RSS.image.height
                +"' src='"+RSS.image.url
                +"' "+"/>";
        }

        //populate the items
        document.getElementById("chan_items").innerHTML = "";
        for (var i=0; i<RSS.items.length; i++)
        {
            item_html = startItemTag;
            item_html += (RSS.items[i].title == null) ? "" : startTitle + RSS.items[i].title + endTag;
            item_html += (RSS.items[i].link == null) ? "" : startLink + RSS.items[i].link + endTag;
            item_html += (RSS.items[i].description == null) ? "" : startDescription + RSS.items[i].description + endTag;
            item_html += endTag;
            document.getElementById("chan_items").innerHTML += item_html;
        }

        //we're done
        //document.getElementById("chan").style.visibility = "visible";
        return true;
    }

    var xhr;

 <!-- html file -->

    <html>
    <head>
        <script language="javascript" src="rssajax.js"></script>
        <style type="text/css">
            #chan_items { margin: 20px; }
            #chan_items #item { margin-bottom: 10px; }
            #chan_items #item #item_title {
        font-weight: bold;
    }
        </style>
    </head>
    <body onload="getRSS()">

        <form name="rssform">
        <input name="rssurl" type="hidden" value="ChapRSS.xml">
    </form>


    <script language="javascript" src="rssajax.js"></script>

        <div class="rss" id="chan">
            <div id="chan_title"></div>

            <a href="chan_link" target="_blank" id="chan_link"></a>
            <div id="chan_description"></div>
            <div id="chan_image_link"></div>
            <a href="chan_image_link" target="_blank" id="chan_items"></a>
            <div id="chan_pubDate"></div>
            <div id="chan_copyright"></div>
        </div>
    </body>
    </html>
A: 
<link>http://www.cnn.com/...?eref=rss_world&amp;utm_source=...&lt;/link&gt;

That is not well-formed XML, and hence not RSS. You must escape all literal ampersand symbols to &amp;.

(It's not valid in HTML either. When you put a & in an href="..." attribute you must also escape it to &amp;. The difference is browsers typically correct your mistake for you when they can; XML parsers won't.)

document.rssform.rssurl.value

Adding an ID on the <input> and using document.getElementById is less ambiguous than the old-school form collection access. Either way, that's a rather roundabout way of getting a value into script. Why not lose the form and simple pass the RSS filename as an argument into getRSS()?

this.title;

That doesn't do anything at all. None of the places you refer to a property like this have any effect; you are not creating members by doing this.

var properties = new Array("title", "link", ...

In general avoid the new Array constructor. The array literal syntax (var properties= ['title', 'link, ...]; is easier to read and doesn't have the constructor's unexpected behaviour for a single argument.

eval("this."+properties[i]+"=tmpElement.childNodes[0].nodeValue");

eval is evil. Never use it.

You can use square-bracket notation to access a property with a dynamic name. a.b is the same as a['b'], so:

this[properties[i]]= tmpElement.childNodes[0].nodeValue;

...

imgAttribs = new Array("url","title", ...

You haven't declared var imgAttribs so that's an accidental global. Same with Item in RSS2Channel. (Why the capital letter?)

eval("this."+imgAttribs[i]+"=imgElement.getAttribute("+imgAttribs[i]+")");

That won't work due to lack of quotes on the attribute name. You'll be getting getAttribute(url), and there's no variable called url -> error. Again, use square bracket property access to set the attribute and not eval.

eval("document.getElementById('chan_"+properties[i]+"').innerHTML = ''");

getElementById('chan_'+properties[i]) is fine, there is no point in doing that in an eval.

xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.setRequestHeader("Pragma", "no-cache");

Cache-Control and Pragma are typically HTTP response fields. They will not have the effect you expect in an HTTP request. If you want to ensure no caching occurs from the client side, use a ‘cachebuster’ method such as adding a random number or timestamp to the URL's query string.

innerHTML = curProp

Danger. Values you have fetched are arbitrary text strings and may contain HTML-special characters like < and &. If you write such strings to an element's innerHTML, you are likely to get broken results, and if they include third-party content you have just given yourself a cross-site-scripting security hole.

You can use textContent=... to set the content of an element without having to worry about HTML-escaping, however you then need to detect whether it's supported and fall back to IE's non-standard innerText property if it's not. A way that works on all browsers is to document.createTextNode(curProp) and append that text node to the element.

innerHTML= imageTag+" alt='"+RSS.image.description+ ...

You've got exactly the same problem with HTML-escaping here: if eg. the description contains <script>, you're in trouble. You can write an HTML-encoder, eg.:

function encodeHTML(s) {
    return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
}

innerHTML= imageTag+' alt="'+encodeHTML(RSS.image.description)+ ...

But really, creating HTML from bits of string totally sucks. Use DOM methods instead:

var img= document.createElement('img');
img.src= RSS.image.url;
img.title= RSS.image.description;
img.width= RSS.image.width;
img.height= RSS.image.height;
document.getElementById('chan_image_link').appendChild(img);
bobince