1 /* 2 * Timemap.js Copyright 2010 Nick Rabinowitz. 3 * Licensed under the MIT License (see LICENSE.txt) 4 */ 5 6 /** 7 * @fileOverview 8 * GeoRSS Loader 9 * 10 * @author Nick Rabinowitz (www.nickrabinowitz.com) 11 */ 12 13 /*globals GXml, TimeMap, TimeMapDataset */ 14 15 /** 16 * @class 17 * GeoRSS loader: Load GeoRSS feeds. 18 * 19 * <p> Parsing is complicated by the 20 * diversity of GeoRSS formats; this parser handles:</p> 21 * <ul> 22 * <li>RSS feeds</li> 23 * <li>Atom feeds</li> 24 * </ul> 25 * <p>and looks for geographic information in the following formats:</p> 26 * <ul> 27 * <li>GeoRSS-Simple</li> 28 * <li>GML </li> 29 * <li>W3C Geo</li> 30 * </ul> 31 * <p>At the moment, this only supports points, polygons, polylines; boxes 32 * may be added at some later point.</p> 33 * 34 * @augments TimeMap.loaders.xml 35 * @requires loaders/xml.js 36 * @requires param.js 37 * @borrows TimeMap.loaders.georss.parse as #parse 38 * 39 * @example 40 TimeMap.init({ 41 datasets: [ 42 { 43 title: "GeoRSS Dataset", 44 type: "georss", // Data to be loaded in GeoRSS 45 options: { 46 url: "mydata.rss" // GeoRSS file to load - must be a local URL 47 } 48 } 49 ], 50 // etc... 51 }); 52 * @see <a href="../../examples/earthquake_georss.html">GeoRSS Example</a> 53 * 54 * @param {Object} options All options for the loader: 55 * @param {String} options.url URL of GeoRSS file to load (NB: must be local address) 56 * @param {mixed} [options[...]] Other options (see {@link TimeMap.loaders.xml}) 57 */ 58 TimeMap.loaders.georss = function(options) { 59 var loader = new TimeMap.loaders.xml(options); 60 loader.parse = TimeMap.loaders.georss.parse; 61 return loader; 62 }; 63 64 /** 65 * Static function to parse GeoRSS 66 * 67 * @param {String} rss GeoRSS string to be parsed 68 * @return {TimeMapItem[]} Array of TimeMapItems 69 */ 70 TimeMap.loaders.georss.parse = function(rss) { 71 var items = [], data, node, placemarks, pm, i; 72 node = GXml.parse(rss); 73 74 // get TimeMap utilty functions 75 // assigning to variables should compress better 76 var util = TimeMap.util, 77 getTagValue = util.getTagValue, 78 getNodeList = util.getNodeList, 79 makePoint = util.makePoint, 80 makePoly = util.makePoly, 81 formatDate = util.formatDate, 82 nsMap = util.nsMap; 83 84 // define namespaces 85 nsMap.georss = 'http://www.georss.org/georss'; 86 nsMap.gml = 'http://www.opengis.net/gml'; 87 nsMap.geo = 'http://www.w3.org/2003/01/geo/wgs84_pos#'; 88 nsMap.kml = 'http://www.opengis.net/kml/2.2'; 89 90 // determine whether this is an Atom feed or an RSS feed 91 var feedType = (node.firstChild.tagName == 'rss') ? 'rss' : 'atom'; 92 93 // look for placemarks 94 var tName = (feedType == 'rss' ? "item" : "entry"); 95 placemarks = getNodeList(node, tName); 96 for (i=0; i<placemarks.length; i++) { 97 pm = placemarks[i]; 98 data = { options: {} }; 99 // get title & description 100 data.title = getTagValue(pm, "title"); 101 tName = (feedType == 'rss' ? "description" : "summary"); 102 data.options.description = getTagValue(pm, tName); 103 // get time information, allowing KML-namespaced time elements 104 var nList = getNodeList(pm, "TimeStamp", "kml"); 105 if (nList.length > 0) { 106 data.start = getTagValue(nList[0], "when", "kml"); 107 } 108 // look for timespan 109 if (!data.start) { 110 nList = getNodeList(pm, "TimeSpan", "kml"); 111 if (nList.length > 0) { 112 data.start = getTagValue(nList[0], "begin", "kml"); 113 data.end = getTagValue(nList[0], "end", "kml") || 114 // unbounded spans end at the present time 115 formatDate(new Date()); 116 } 117 } 118 // otherwise, use pubDate/updated elements 119 if (!data.start) { 120 if (feedType == 'rss') { 121 // RSS needs date conversion 122 var d = new Date(Date.parse(getTagValue(pm, "pubDate"))); 123 // reformat 124 data.start = formatDate(d); 125 } else { 126 // atom uses ISO 8601 127 data.start = getTagValue(pm, "updated"); 128 } 129 } 130 // find placemark - single geometry only for the moment 131 var done = false; 132 PLACEMARK: while (!done) { 133 var coords, geom; 134 // look for point, GeoRSS-Simple 135 coords = getTagValue(pm, "point", 'georss'); 136 if (coords) { 137 data.point = makePoint(coords); 138 break PLACEMARK; 139 } 140 // look for point, GML 141 nList = getNodeList(pm, "Point", 'gml'); 142 if (nList.length > 0) { 143 // GML <pos> 144 coords = getTagValue(nList[0], "pos", 'gml'); 145 // GML <coordinates> 146 if (!coords) { 147 coords = getTagValue(nList[0], "coordinates", 'gml'); 148 } 149 if (coords) { 150 data.point = makePoint(coords); 151 break PLACEMARK; 152 } 153 } 154 // look for point, W3C Geo 155 if (getTagValue(pm, "lat", 'geo')) { 156 coords = [ 157 getTagValue(pm, "lat", 'geo'), 158 getTagValue(pm, "long", 'geo') 159 ]; 160 data.point = makePoint(coords); 161 break PLACEMARK; 162 } 163 // look for polyline, GeoRSS-Simple 164 coords = getTagValue(pm, "line", 'georss'); 165 if (coords) { 166 data.polyline = makePoly(coords); 167 break PLACEMARK; 168 } 169 // look for polygon, GeoRSS-Simple 170 coords = getTagValue(pm, "polygon", 'georss'); 171 if (coords) { 172 data.polygon = makePoly(coords); 173 break PLACEMARK; 174 } 175 // look for polyline, GML 176 nList = getNodeList(pm, "LineString", 'gml'); 177 if (nList.length > 0) { 178 geom = "polyline"; 179 } else { 180 nList = getNodeList(pm, "Polygon", 'gml'); 181 if (nList.length > 0) { 182 geom = "polygon"; 183 } 184 } 185 if (nList.length > 0) { 186 // GML <posList> 187 coords = getTagValue(nList[0], "posList", 'gml'); 188 // GML <coordinates> 189 if (!coords) { 190 coords = getTagValue(nList[0], "coordinates", 'gml'); 191 } 192 if (coords) { 193 data[geom] = makePoly(coords); 194 break PLACEMARK; 195 } 196 } 197 198 // XXX: deal with boxes 199 200 done = true; 201 } 202 // look for any extra tags specified 203 this.parseExtra(data, pm); 204 items.push(data); 205 } 206 207 // clean up 208 node = placemarks = pm = nList = null; 209 return items; 210 }; 211