1 /* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
2 * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
3 * full text of the license. */
6 * @requires OpenLayers/Format/XML.js
7 * @requires OpenLayers/Feature/Vector.js
8 * @requires OpenLayers/Geometry/Point.js
9 * @requires OpenLayers/Geometry/LineString.js
10 * @requires OpenLayers/Geometry/Polygon.js
14 * Class: OpenLayers.Format.GeoRSS
15 * Read/write GeoRSS parser. Create a new instance with the
16 * <OpenLayers.Format.GeoRSS> constructor.
19 * - <OpenLayers.Format.XML>
21 OpenLayers.Format.GeoRSS = OpenLayers.Class(OpenLayers.Format.XML, {
25 * {String} RSS namespace to use. Defaults to
26 * "http://backend.userland.com/rss2"
28 rssns: "http://backend.userland.com/rss2",
31 * APIProperty: featurens
32 * {String} Feature Attributes namespace. Defaults to
33 * "http://mapserver.gis.umn.edu/mapserver"
35 featureNS: "http://mapserver.gis.umn.edu/mapserver",
38 * APIProperty: georssns
39 * {String} GeoRSS namespace to use. Defaults to
40 * "http://www.georss.org/georss"
42 georssns: "http://www.georss.org/georss",
46 * {String} W3C Geo namespace to use. Defaults to
47 * "http://www.w3.org/2003/01/geo/wgs84_pos#"
49 geons: "http://www.w3.org/2003/01/geo/wgs84_pos#",
52 * APIProperty: featureTitle
53 * {String} Default title for features. Defaults to "Untitled"
55 featureTitle: "Untitled",
58 * APIProperty: featureDescription
59 * {String} Default description for features. Defaults to "No Description"
61 featureDescription: "No Description",
65 * {Object} GML Format object for parsing features
66 * Non-API and only created if necessary
72 * {Boolean} Order of the GML coordinate: true:(x,y) or false:(y,x)
73 * For GeoRSS the default is (y,x), therefore: false
78 * Constructor: OpenLayers.Format.GeoRSS
79 * Create a new parser for GeoRSS.
82 * options - {Object} An optional object whose properties will be set on
85 initialize: function(options) {
86 OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
90 * Method: createGeometryFromItem
91 * Return a geometry from a GeoRSS Item.
94 * item - {DOMElement} A GeoRSS item node.
97 * {<OpenLayers.Geometry>} A geometry representing the node.
99 createGeometryFromItem: function(item) {
100 var point = this.getElementsByTagNameNS(item, this.georssns, "point");
101 var lat = this.getElementsByTagNameNS(item, this.geons, 'lat');
102 var lon = this.getElementsByTagNameNS(item, this.geons, 'long');
104 var line = this.getElementsByTagNameNS(item,
107 var polygon = this.getElementsByTagNameNS(item,
110 var where = this.getElementsByTagNameNS(item,
113 var box = this.getElementsByTagNameNS(item,
117 if (point.length > 0 || (lat.length > 0 && lon.length > 0)) {
119 if (point.length > 0) {
120 location = OpenLayers.String.trim(
121 point[0].firstChild.nodeValue).split(/\s+/);
122 if (location.length !=2) {
123 location = OpenLayers.String.trim(
124 point[0].firstChild.nodeValue).split(/\s*,\s*/);
127 location = [parseFloat(lat[0].firstChild.nodeValue),
128 parseFloat(lon[0].firstChild.nodeValue)];
131 var geometry = new OpenLayers.Geometry.Point(parseFloat(location[1]),
132 parseFloat(location[0]));
134 } else if (line.length > 0) {
135 var coords = OpenLayers.String.trim(this.concatChildValues(line[0])).split(/\s+/);
138 for (var i=0, len=coords.length; i<len; i+=2) {
139 point = new OpenLayers.Geometry.Point(parseFloat(coords[i+1]),
140 parseFloat(coords[i]));
141 components.push(point);
143 geometry = new OpenLayers.Geometry.LineString(components);
144 } else if (polygon.length > 0) {
145 var coords = OpenLayers.String.trim(this.concatChildValues(polygon[0])).split(/\s+/);
148 for (var i=0, len=coords.length; i<len; i+=2) {
149 point = new OpenLayers.Geometry.Point(parseFloat(coords[i+1]),
150 parseFloat(coords[i]));
151 components.push(point);
153 geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]);
154 } else if (where.length > 0) {
155 if (!this.gmlParser) {
156 this.gmlParser = new OpenLayers.Format.GML({'xy': this.xy});
158 var feature = this.gmlParser.parseFeature(where[0]);
159 geometry = feature.geometry;
160 } else if (box.length > 0) {
161 var coords = OpenLayers.String.trim(box[0].firstChild.nodeValue).split(/\s+/);
164 if (coords.length > 3) {
165 point = new OpenLayers.Geometry.Point(parseFloat(coords[1]),
166 parseFloat(coords[0]));
167 components.push(point);
168 point = new OpenLayers.Geometry.Point(parseFloat(coords[1]),
169 parseFloat(coords[2]));
170 components.push(point);
171 point = new OpenLayers.Geometry.Point(parseFloat(coords[3]),
172 parseFloat(coords[2]));
173 components.push(point);
174 point = new OpenLayers.Geometry.Point(parseFloat(coords[3]),
175 parseFloat(coords[0]));
176 components.push(point);
177 point = new OpenLayers.Geometry.Point(parseFloat(coords[1]),
178 parseFloat(coords[0]));
179 components.push(point);
181 geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]);
184 if (geometry && this.internalProjection && this.externalProjection) {
185 geometry.transform(this.externalProjection,
186 this.internalProjection);
193 * Method: createFeatureFromItem
194 * Return a feature from a GeoRSS Item.
197 * item - {DOMElement} A GeoRSS item node.
200 * {<OpenLayers.Feature.Vector>} A feature representing the item.
202 createFeatureFromItem: function(item) {
203 var geometry = this.createGeometryFromItem(item);
205 /* Provide defaults for title and description */
206 var title = this.getChildValue(item, "*", "title", this.featureTitle);
208 /* First try RSS descriptions, then Atom summaries */
209 var description = this.getChildValue(
210 item, "*", "description",
211 this.getChildValue(item, "*", "content",
212 this.getChildValue(item, "*", "summary", this.featureDescription)));
214 /* If no link URL is found in the first child node, try the
216 var link = this.getChildValue(item, "*", "link");
219 link = this.getElementsByTagNameNS(item, "*", "link")[0].getAttribute("href");
225 var id = this.getChildValue(item, "*", "id", null);
229 "description": description,
232 var feature = new OpenLayers.Feature.Vector(geometry, data);
238 * Method: getChildValue
241 * node - {DOMElement}
242 * nsuri - {String} Child node namespace uri ("*" for any).
243 * name - {String} Child node name.
244 * def - {String} Optional string default to return if no child found.
247 * {String} The value of the first child with the given tag name. Returns
248 * default value or empty string if none found.
250 getChildValue: function(node, nsuri, name, def) {
252 var eles = this.getElementsByTagNameNS(node, nsuri, name);
253 if(eles && eles[0] && eles[0].firstChild
254 && eles[0].firstChild.nodeValue) {
255 value = eles[0].firstChild.nodeValue;
257 value = (def == undefined) ? "" : def;
264 * Return a list of features from a GeoRSS doc
270 * An Array of <OpenLayers.Feature.Vector>s
272 read: function(doc) {
273 if (typeof doc == "string") {
274 doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]);
277 /* Try RSS items first, then Atom entries */
279 itemlist = this.getElementsByTagNameNS(doc, '*', 'item');
280 if (itemlist.length == 0) {
281 itemlist = this.getElementsByTagNameNS(doc, '*', 'entry');
284 var numItems = itemlist.length;
285 var features = new Array(numItems);
286 for(var i=0; i<numItems; i++) {
287 features[i] = this.createFeatureFromItem(itemlist[i]);
295 * Accept Feature Collection, and return a string.
298 * features - {Array(<OpenLayers.Feature.Vector>)} List of features to serialize into a string.
300 write: function(features) {
302 if(features instanceof Array) {
303 georss = this.createElementNS(this.rssns, "rss");
304 for(var i=0, len=features.length; i<len; i++) {
305 georss.appendChild(this.createFeatureXML(features[i]));
308 georss = this.createFeatureXML(features);
310 return OpenLayers.Format.XML.prototype.write.apply(this, [georss]);
314 * Method: createFeatureXML
315 * Accept an <OpenLayers.Feature.Vector>, and build a geometry for it.
318 * feature - {<OpenLayers.Feature.Vector>}
323 createFeatureXML: function(feature) {
324 var geometryNode = this.buildGeometryNode(feature.geometry);
325 var featureNode = this.createElementNS(this.rssns, "item");
326 var titleNode = this.createElementNS(this.rssns, "title");
327 titleNode.appendChild(this.createTextNode(feature.attributes.title ? feature.attributes.title : ""));
328 var descNode = this.createElementNS(this.rssns, "description");
329 descNode.appendChild(this.createTextNode(feature.attributes.description ? feature.attributes.description : ""));
330 featureNode.appendChild(titleNode);
331 featureNode.appendChild(descNode);
332 if (feature.attributes.link) {
333 var linkNode = this.createElementNS(this.rssns, "link");
334 linkNode.appendChild(this.createTextNode(feature.attributes.link));
335 featureNode.appendChild(linkNode);
337 for(var attr in feature.attributes) {
338 if (attr == "link" || attr == "title" || attr == "description") { continue; }
339 var attrText = this.createTextNode(feature.attributes[attr]);
341 if (attr.search(":") != -1) {
342 nodename = attr.split(":")[1];
344 var attrContainer = this.createElementNS(this.featureNS, "feature:"+nodename);
345 attrContainer.appendChild(attrText);
346 featureNode.appendChild(attrContainer);
348 featureNode.appendChild(geometryNode);
353 * Method: buildGeometryNode
354 * builds a GeoRSS node with a given geometry
357 * geometry - {<OpenLayers.Geometry>}
360 * {DOMElement} A gml node.
362 buildGeometryNode: function(geometry) {
363 if (this.internalProjection && this.externalProjection) {
364 geometry = geometry.clone();
365 geometry.transform(this.internalProjection,
366 this.externalProjection);
370 if (geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") {
371 node = this.createElementNS(this.georssns, 'georss:polygon');
373 node.appendChild(this.buildCoordinatesNode(geometry.components[0]));
376 else if (geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") {
377 node = this.createElementNS(this.georssns, 'georss:line');
379 node.appendChild(this.buildCoordinatesNode(geometry));
382 else if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
383 node = this.createElementNS(this.georssns, 'georss:point');
384 node.appendChild(this.buildCoordinatesNode(geometry));
386 throw "Couldn't parse " + geometry.CLASS_NAME;
392 * Method: buildCoordinatesNode
395 * geometry - {<OpenLayers.Geometry>}
397 buildCoordinatesNode: function(geometry) {
400 if (geometry.components) {
401 points = geometry.components;
406 var numPoints = points.length;
407 var parts = new Array(numPoints);
408 for (var i = 0; i < numPoints; i++) {
409 parts[i] = points[i].y + " " + points[i].x;
411 path = parts.join(" ");
413 path = geometry.y + " " + geometry.x;
415 return this.createTextNode(path);
418 CLASS_NAME: "OpenLayers.Format.GeoRSS"