I am working on JavaScript using HTML5 and I am stuck with a certain aspect. I want to do the following:
Create a table using JavaScript (which is fairly easy)
Extract details from a XML file that is available online
Enter the values in the table
For example, the linkhttp://www.tfl.gov.uk/tfl/syndication/feeds/cycle-hire/livecyclehireupdates.xml contains the information for cycle availability at each station
1. I need to create a table with two columns. One for 'Station Name' and the other for 'No of cycles available'
2. I need to write code that only takes in the above link as input and extracts values of 'Name' and 'nbEmptyDocks'.
Ex : <name> ABC,Surrey </name> <nbEmptyDocks> 10 </nbEmptyDocks>, how will I extract the values ABC,Surrey and 10 and place them in respective columns?
<!DOCTYPE html>
<html>
<body>
<script language= "JavaScript">
document.write('<br> <br><table width="50%" border="1">'); document.write('<th> Dock Station');
document.write('<th> Number of Cycles');
document.write('<br> <br><table width="50%" border="1">');
var Connect = new XMLHttpRequest();
Connect.open("GET", "http://www.tfl.gov.uk/tfl/syndication/feeds/cycle-hire/livecyclehireupdates.xml", false);
Connect.setRequestHeader("Content-Type", "text/xml");
Connect.send(null);
var TheDocument = Connect.responseXML;
var station = TheDocument.childNodes[0];
for (var i = 0; i < 5; i++)
{
var stations = station.children[i];
var name = stations.getElementsByTagName("name");
var avail = Customer.getElementsByTagName("nbEmptyDocks");
document.write("<tr><td>");
document.write( name[0].textContent.toString());
document.write("</td><td>");
document.write(avail[0].textContent.toString());
document.write("</td>");
document.write("</tr>");
}
document.write (" </table>");
</script>
</body></html>
On further reading, I understood that the above code might not work for Chrome, and I need one that works with chrome.
<html>
<body>
<script>
var xmlDoc;
var xmlloaded = false;
function initLibrary()
{
importXML("http:///www.somedomain.com/somesubdir/somefile.xml");
}
function importXML(xmlfile)
{
try
{
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", xmlfile, false);
}
catch (Exception)
{
var ie = (typeof window.ActiveXObject != 'undefined');
if (ie)
{
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
while(xmlDoc.readyState != 4) {};
xmlDoc.load(xmlfile);
readXML();
xmlloaded = true;
}
else
{
xmlDoc = document.implementation.createDocument("", "", null);
xmlDoc.onload = readXML;
xmlDoc.load(xmlfile);
xmlloaded = true;
}
}
if (!xmlloaded)
{
xmlhttp.setRequestHeader('Content-Type', 'text/xml')
xmlhttp.send("");
xmlDoc = xmlhttp.responseXML;
readXML();
xmlloaded = true;
}
}
</script>
</body>
</html>
But this doesnt seem to work either
I would suggest using Google API for grabbing RSS and rending it on your page: you can get started here.
As you say they are not tags themselves, for which it would've been fairly trivial to access them via DOM methods.
Instead, you will need to grab the textContent of the <title> and/or <description> nodes in each <item>. Once you have done that, you will need to do a little string processing. However, the strings are quite predictable, so this is easy:
var text = "Max Temp: 8°C (46°F), Min Temp: 5°C (41°F), Wind Direction: SW, Wind Speed: 8mph, Visibility: good, Pressure: 1002mb, Humidity: 92%, Pollution: n/a, Sunrise: 08:13GMT, Sunset: 16:40GMT";
var pairs = text.split(", "),
info = {};
for (var i=0; i<pairs.length; i++) {
var pair = pairs[i].split(": ");
info[pair[0]] = pair[1];
}
console.log(info)
// {"Max Temp":"8°C (46°F)","Min Temp":"5°C (41°F)","Wind Direction":"SW","Wind Speed":"8mph","Visibility":"good","Pressure":"1002mb","Humidity":"92%","Pollution":"n/a","Sunrise":"08:13GMT","Sunset":"16:40GMT"}
console.log(info["Max Temp"], info["Min Temp"])
// "8°C (46°F)", "5°C (41°F)"
Related
I've got a big database with over 30 000 records on my server. I make a request to the server giving me the first 100 records and showing them with Googlevisualisation table paging Api - 10 records per page.
In my code here I added an event listener for the "page" event and tested the page property of the event:if I have reached the last page, I make an AJAX call for more data (another 100 records)
The problem is that if I reach the last page it just loads it for a second and it makes immediately the Ajax call without waiting to click next and for that results it doesn't change my page property! how can i make this way - when I reach the last my next button to be enabled and when i click it only then to load the next 100 records
Here my code that I tried so far:
<html>
<head>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load('visualization', '1', {packages: ['table']});
</script>
<script>
var xmlhttp;
if (window.XMLHttpRequest)
{
xmlhttp = new XMLHttpRequest();
} else
{
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
var intRpp=100;
var intPNum;
var glPNum;
var s;
var options = {'showRowNumber': true, 'pageSize':intPageSize };
var numberOfPages;
var intPageSize=10;
function loadXMLDoc(l)
{
intPNum=l;
s=l;
xmlhttp.onreadystatechange = function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
//alert(xmlhttp.responseText);
var xmlObj = xmlhttp.responseXML;
var textXML = xmlObj.documentElement.firstChild.firstChild.nodeValue;
if (window.DOMParser)
{
parser=new DOMParser();
var xmlDoc=parser.parseFromString(textXML,"text/xml");
}
else // Internet Explorer
{
var xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async=false;
xmlDoc.loadXML(textXML);
}
var rec = new Array();
rec[0]=['Стопански субект', 'Юрид.форма', 'Община', 'Име', 'Роля', 'Страна', 'NACE code', 'NACE text', 'Селище', 'пощ.код','Адрес', 'тел.', 'факс', 'Email', 'web', 'rid','id','activ'];
var rows = xmlDoc.getElementsByTagName("row");
rowsn = rows.length;
for (i=1;i<=rowsn;i++)
{
var cols=rows[i-1].getElementsByTagName("colunm");
colsn=cols.length;
rec[i] = new Array();
for (var j=0; j<colsn; j++)
{
rec[i][j] = cols[j].getAttribute("colvalue");
}
rec[i][j]='<input type="button" onClick="ajaxDBDelete('+rec[i][15]+');"/>';
}
tblTst = google.visualization.arrayToDataTable(rec);
options['page'] = 'event';
options['pageSize'] = intPageSize;
options['pagingSymbols'] = {prev: 'prev', next: 'next'};
options['pagingButtonsConfiguration'] = 'both';
options['allowHtml'] = 'true';
numberOfPages = intRpp/intPageSize;
visual = new google.visualization.Table(document.getElementById('table'));
google.visualization.events.addListener(visual, 'page', function (e){
options.startPage = e.page;
if (s>1)
{
glPNum = (numberOfPages * (s-1)) + (e.page+1);
document.getElementById('txbNumPage').value = glPNum;
options['pagingButtonsConfiguration']='both';
}
else
{
glPNum = e.page+1;
if (glPNum==1) options['pagingButtonsConfiguration']='next';
else options['pagingButtonsConfiguration']='both';
}
document.getElementById('txbNumPage').value = glPNum;
visual.draw(tblTst, options);
if (e.page == numberOfPages-1)
{
loadXMLDoc(s+1);
options.startPage = 0;
}
else
{
if((e.page==0)&&(s>1))
{
loadXMLDoc(s-1);
options.startPage=numberOfPages-1;
}
}
});
visual.draw(tblTst, options);
}
}
//alert (intRpp);
var url = "http://78.130.187.38:8080/axis2/services/bucat2/SelectFromDB?intRpp=" +intRpp + "&pageNum="+intPNum;
//alert (url);
xmlhttp.open("GET", url, true);
xmlhttp.send();
}
</script>
</head>
<body onload= "loadXMLDoc(1);">
<br>
<br>
<div id="table"></div>
<br/>
<button type="button" name="btnFP" onClick="loadXMLDoc(1);">FIRST PAGE</button>
<input type="input" id="txbNumPage" value=1 />
<button type="button" name="btnLP" onClick="ajaxDBLast();">LAST PAGE</button>
<br>
<div id='proba'>
</div>
</body>
</html>
how can i make this way - when I reach the last my next button to be enabled and when i click it only then to load the next 100 records
Put your logic into a generic function
Set loadXMLDoc as a pointer to that function
Pass the page number as part of the query string to the AJAX URL
If the page number is the last one, then reassign loadXMLDoc to an empty function
I have a map that reads an XML file; it's all very simple and copied from here:
http://geochalkboard.wordpress.com/2009/03/30/reading-xml-files-with-the-google-maps-api/
My version is here:
http://www.cloudfund.me/maps/mashup.html and the data file it's reading is here:
converted.xml in the same directory.
I don't get any points at all, when I run it. I put some console logging in to see if I could see anything, but as far as that's concerned, it just runs through without a hitch. The file loads ok, and I can watch the code loop through all the rows (208 in this example) without any problems.
The only warning I'm getting is the 'Resource interpreted as other passed as undefined' one; having had a look at some of the other threads, I can't see anything that helps - no empty src links, etc. As far as I can tell, this shouldn't stop it marking the points, either.
Here's the real kicker - in trying to trace this error, I set up an exact replica of the original code on my own server, and got an error about null fields, which I added some conditional code to to sort; this version works on my server. This is austin.html in the same directory (sorry, can't do more than two links in my first posts!)
So - my code is this:
<title>Test </title>
<script src="http://maps.google.com/maps?file=api&v=2&sensor=false&key=AIzaSyDgybFoyn3i5j_6d7ul7p2dPNQ5b1xOWnk"
type="text/javascript">console.log("Loaded Maps API");</script>
<script src="http://gmaps-utility-library.googlecode.com/svn/trunk/markermanager/release/src/markermanager.js">console.log("MarkerManager");</script>
<script type="text/javascript">
console.log("Into Main Script");
function initialize() {
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("map_canvas"));
map.setCenter(new GLatLng(51.39906378, -2.449545605), 13);
map.setUIToDefault();
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
map.addMapType(G_PHYSICAL_MAP);
map.setMapType(G_PHYSICAL_MAP);
console.log("Reached end of map initialising");
addMarkersFromXML();
console.log("MarkersfromXML")
}
}
function addMarkersFromXML(){
var batch = [];
mgr = new MarkerManager(map);
var request = GXmlHttp.create();
console.log("About to open converted.xml")
request.open('GET', 'converted.xml', true);
console.log("Opened Converted.xml")
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200)
{
var xmlDoc = request.responseXML;
var xmlrows = xmlDoc.documentElement.getElementsByTagName("row");
for (var i = 0; i < xmlrows.length; i++) {
var xmlrow = xmlrows[i];
console.log("Running through row number",i)
var xmlcellLongitude = xmlrow.getElementsByTagName("longitude")[0];
console.log(xmlcellLongitude);
var xmlcellLatitude = xmlrow.getElementsByTagName("latitude")[0];
var point = new GLatLng(parseFloat(xmlcellLatitude.firstChild.data),parseFloat(xmlcellLongitude.firstChild.data));
//get the PAO
var xmlcellAssetName = xmlrow.getElementsByTagName("pao")[0];
console.log(xmlcellAssetName);
var celltextAssetName = xmlcellAssetName.firstChild.data;
//get the area
var xmlcellArea = xmlrow.getElementsByTagName("area")[0];
console.log(xmlcellArea);
var celltextArea = xmlcellArea.firstChild.data;
//get the land type
var xmlcellLandType = xmlrow.getElementsByTagName("landtype")[0];
console.log(xmlcellLandType);
var celltextLandType = xmlcellLandType.firstChild.data;
//get the Planning Permissions
var xmlcellPlanning = xmlrow.getElementsByTagName("planning")[0];
console.log(xmlcellPlanning);
var celltextPlanning = xmlcellPlanning.firstChild.data;
var htmlString = "Asset Name: " + celltextAssetName + "<br>" + "Size: " + celltextArea + "<br>" + "Land Type: " + celltextLandType + "<br>" + "Planning Permissions: " + celltextPlanning;
//var htmlString = 'yes'
var marker = createMarker(point,htmlString);
batch.push(marker);
}
mgr.addMarkers(batch,50);
mgr.refresh();
}
}
request.send(null);
}
function createMarker(point,html) {
var marker = new GMarker(point);
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml(html);
});
return marker;
}
</script>
</head>
<body onload="initialize()" onunload="GUnload()">
<div id="map_canvas" style="width: 1100px; height: 700px"></div>
</body>
</html>
Think you have a typo. In your code, you're pulling an incomplete URL for the API:
<script src="//maps.google.com/maps?file=api&v=2&sensor=false&key=AIzaSyDgybFoyn3i5j_6d7ul7p2dPNQ5b1xOWnk"
That errant // seems to be throwing the code off.
Though, to be perfectly honest, the originating example (and austin.html) doesn't exactly work as one would imagine it should. The points do get rendered, but no effective clustering takes place when you zoom out. Suspect that the 2.0 branch of the API got moved to a newer version and created a bit of an incompatibility.
Recommend that you rewrite this in API version 3. There is a cluster manager that works for it quite well.
See http://tools.voanews2.com/nuclear_reactors/
I am having problem with applying ajax on IE.I am applying innerHtml on select tag but it is not working my ajax code is
function AjaxF(ftype, cid) {
var httpxml;
try {
// Firefox, Opera 8.0+, Safari
httpxml = new XMLHttpRequest();
}
catch (e) {
// Internet Explorer
try {
httpxml = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try {
httpxml = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {
alert("Your browser does not support AJAX!");
return false;
}
}
}
function stateck() {
if (httpxml.readyState == 4) {
var myarray = httpxml.responseText;
if (ftype == 'Files') {
document.getElementById('temp_thumbnail').innerHTML = myarray;
document.getElementById('temp_mainfiles').innerHTML = myarray;
document.getElementById('temp_preview').innerHTML = myarray;
document.getElementById('temp_image').innerHTML = myarray;
}
else {
document.getElementById('temp_thumbnail').innerHTML = myarray;
document.getElementById('temp_main').innerHTML = myarray;
document.getElementById('temp_image').innerHTML = myarray;
}
}
}
var url = "ajax/files_ajax.php";
url = url + "?filetype=" + ftype + "&customerid=" + cid;
url = url + "&sid=" + Math.random();
httpxml.onreadystatechange = stateck;
httpxml.open("GET", url, true);
httpxml.send(null);
}
My php code for creating option is.I am getting the values in filetype and it is working fine on other browsers
$sql="select name ,id from temporary_upload where type ='$filetype' AND customer_id='$customer_id'";
$result=mysql_query($sql);
while($rows=mysql_fetch_array($result))
{
$s.="<option id='' name='' selected='selected' value='". $rows['name'] ."'>". $rows['name'] ."</option>";
}
echo $s;
My html for this code is
<select id="temp_thumbnail" name="temp_thumbnail" style="width:452px">
<option></option>
</select>
I have searched for this error on many forums.They all are saying that innerHtml with select has error in IE can anyone help me to resolve this issue.That I can populate my select option.
Thanks in advance
some years ago, i had a similar problem with IE6. if i remember right, i solved this by replacing the whole select-element instead of just replacing the innerHTML (the option-elements).
to do this, you'll have to change the file called via ajax to output the start- and end-tag of your select-element, too. put the select-elemet on your html-site into another element with an id (if there isn't already one you havn't posted) and replace the innerHTML of that outer element.
EDIT: the link gnur posted describes exactly this workaround, so it seems like i remember right ;)
Not a fan of the solutions where they want you to remove the select and than add it back. Kills all the event handlers. Wrote a little function that tries to set the innerHTML. If setting the innerHTML results in no options being added, it rewrites the function so it will create an element and clone its options.
function addOptionsToSelect( selectId, optStr){
var sel = document.getElementById(selectId)
sel.options.length = 0;
sel.innerHTML = optStr;
if(sel.options.length===0){
(addOptionsToSelect = function( selectId, optStr){
var div = document.createElement("div");
div.innerHTML = "<select>" + optStr + "</select>";
var newSelect = div.getElementsByTagName("select")[0];
var sel = document.getElementById(selectId);
sel.options.length = 0;
for(var i=0;i<newSelect.options.length;i++){
var cpy = newSelect.options[i].cloneNode(true);
sel.appendChild(cpy);
}
div = newSelect = sel = null;
})
( selectId, optStr);
}
}
Running Example
This may work for you in IE and FF, of course a bit of modification depending on how and where you want to place the new options in the select ...
function addmore(){
var select=document.getElementById('myselect');
var theindex=select.options[select.selectedIndex];
var option=document.createElement('option');
option.text='text_4';
option.value='value_4';
try{
select.add(option,theindex);
}
catch(e){
//and for ie
select.add(option,select.selectedIndex);
}
}
This page has an excellent work around:
I've written some code to display my favorites in IE8 but for an unknown reason I have no output on the screen despite the fact that my page is accepted by IE and that the test text 'this is a test' is displayed.
my code :
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso 8859-1" />
<script type="text/javascript">
var i = 0;
var favString = "";
var fso;
function GetFavourites(Folder) {
var FavFolder = fso.GetFolder(Folder);
//Gets Favourite Names & URL's for given folder.
var files = new Enumerator(FavFolder.Files);
for (; !files.atEnd(); files.moveNext()) {
var fil = files.item();
if (fil.Type == "Internet Shortcut") {
var textReader = fso.OpenTextFile(fil.Path, 1, false, -2);
var favtext = textReader.ReadAll();
var start = favtext.indexOf("URL", 16);
var stop = favtext.indexOf("\n", start);
favString += fil.Name.replace(/.url/, "");
favString += ":URL:";
//to separate favourite name & favorite URL
favString += favtext.substring(start + 4, stop - 1);
favorites.innerHTML += favString; // Not working !
favorites.innerHTML += 'test'; // Not working too !
favString += ":NEXT:"; //to separate favorites.
i++;
}
}
//Checks any subfolder exists
var subfolders = new Enumerator(FavFolder.SubFolders);
for (; !subfolders.atEnd(); subfolders.moveNext()) {
var folder = subfolders.item();
GetFavourites(folder.Path);
}
}
function Import() {
try {
fso = new ActiveXObject("Scripting.FileSystemObject");
if (fso !== null) {
//Create windows script shell object to access Favorites folder in user system.
var object = new ActiveXObject("WScript.Shell");
var favfolderName = object.SpecialFolders("Favorites");
if (favString === "") {
GetFavourites(favfolderName);
}
}
}
catch (err) {
alert("Security settings to be modified in your browser ");
}
}
</script>
</head>
<body onload="Import()">
<p>this is a test</p> <!-- Working ! -->
<div id="favorites">
</div>
</body>
</html>
The following works for me:
var fso, favs = [];
function GetFavourites(Folder) {
var FavFolder = fso.GetFolder(Folder);
//Gets Favourite Names & URL's for given folder.
var files = new Enumerator(FavFolder.Files);
for (; !files.atEnd(); files.moveNext()) {
var fil = files.item();
if (fil.Type == "Internet Shortcut") {
var textReader = fso.OpenTextFile(fil.Path, 1, false, -2);
var favtext = textReader.ReadAll();
var start = favtext.indexOf("URL", 16);
var stop = favtext.indexOf("\n", start);
favString = fil.Name.replace(/.url/, "");
favString += ":URL:";
//to separate favourite name & favorite URL
favString += favtext.substring(start + 4, stop - 1);
favs.push(favString);
}
}
//Checks any subfolder exists
var subfolders = new Enumerator(FavFolder.SubFolders);
for (; !subfolders.atEnd(); subfolders.moveNext()) {
var folder = subfolders.item();
GetFavourites(folder.Path);
}
}
function Import() {
try {
fso = new ActiveXObject("Scripting.FileSystemObject");
if (fso !== null) {
//Create windows script shell object to access Favorites folder in user system.
var object = new ActiveXObject("WScript.Shell");
var favfolderName = object.SpecialFolders("Favorites");
if (favString === "") {
GetFavourites(favfolderName);
}
}
}
catch (err) {
alert("Security settings to be modified in your browser ");
}
}
Note that all I changed was the output from an element to an array named favs. I also removed the i variable, because it wasn't used. After running the script, I checked the array in the developer tools console and it contained all my favourites.
If you're getting no output at all, then either fso is null in the Import method or files.AtEnd() always evaluates to false. Since you're focusing on IE here, you might consider placing alert methods in various places with values to debug (such as alert(fso);) throughout your expected code path.
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</link>
<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&utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+rss%2Fcnn_world+%28RSS%3A+World%29</link>
<pubDate>June 24, 2010</pubDate>
<source url="http://rss.cnn.com/rss/cnn_world.rss">CNN</source>
</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&utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+rss%2Fcnn_world+%28RSS%3A+World%29</link>
<pubDate>13 July 2010</pubDate>
<source url="http://rss.cnn.com/rss/cnn_world.rss">CNN</source>
</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>
<div id="chan_description"></div>
<div id="chan_image_link"></div>
<div id="chan_pubDate"></div>
<div id="chan_copyright"></div>
</div>
</body>
</html>
<link>http://www.cnn.com/...?eref=rss_world&utm_source=...</link>
That is not well-formed XML, and hence not RSS. You must escape all literal ampersand symbols to &.
(It's not valid in HTML either. When you put a & in an href="..." attribute you must also escape it to &. 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, '&').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, ''');
}
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);