]> dev.renevier.net Git - syp.git/blob - openlayers/lib/OpenLayers/Format/GeoRSS.js
initial commit
[syp.git] / openlayers / lib / OpenLayers / Format / GeoRSS.js
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. */
4
5 /**
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
11  */
12
13 /**
14  * Class: OpenLayers.Format.GeoRSS
15  * Read/write GeoRSS parser. Create a new instance with the 
16  *     <OpenLayers.Format.GeoRSS> constructor.
17  *
18  * Inherits from:
19  *  - <OpenLayers.Format.XML>
20  */
21 OpenLayers.Format.GeoRSS = OpenLayers.Class(OpenLayers.Format.XML, {
22     
23     /**
24      * APIProperty: rssns
25      * {String} RSS namespace to use. Defaults to
26      *   "http://backend.userland.com/rss2"
27      */
28     rssns: "http://backend.userland.com/rss2",
29     
30     /**
31      * APIProperty: featurens
32      * {String} Feature Attributes namespace.  Defaults to
33      *    "http://mapserver.gis.umn.edu/mapserver"
34      */
35     featureNS: "http://mapserver.gis.umn.edu/mapserver",
36     
37     /**
38      * APIProperty: georssns
39      * {String} GeoRSS namespace to use.  Defaults to
40      *     "http://www.georss.org/georss"
41      */
42     georssns: "http://www.georss.org/georss",
43
44     /**
45      * APIProperty: geons
46      * {String} W3C Geo namespace to use.  Defaults to
47      *     "http://www.w3.org/2003/01/geo/wgs84_pos#"
48      */
49     geons: "http://www.w3.org/2003/01/geo/wgs84_pos#",
50     
51     /**
52      * APIProperty: featureTitle
53      * {String} Default title for features.  Defaults to "Untitled"
54      */
55     featureTitle: "Untitled",
56     
57     /**
58      * APIProperty: featureDescription
59      * {String} Default description for features.  Defaults to "No Description"
60      */
61     featureDescription: "No Description",
62     
63     /**
64      * Property: gmlParse
65      * {Object} GML Format object for parsing features
66      * Non-API and only created if necessary
67      */
68     gmlParser: null,
69
70     /**
71      * APIProperty: xy
72      * {Boolean} Order of the GML coordinate: true:(x,y) or false:(y,x)
73      * For GeoRSS the default is (y,x), therefore: false
74      */ 
75     xy: false,
76     
77     /**
78      * Constructor: OpenLayers.Format.GeoRSS
79      * Create a new parser for GeoRSS.
80      *
81      * Parameters:
82      * options - {Object} An optional object whose properties will be set on
83      *     this instance.
84      */
85     initialize: function(options) {
86         OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
87     },
88     
89     /**
90      * Method: createGeometryFromItem
91      * Return a geometry from a GeoRSS Item.
92      *
93      * Parameters:
94      * item - {DOMElement} A GeoRSS item node.
95      *
96      * Returns:
97      * {<OpenLayers.Geometry>} A geometry representing the node.
98      */
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');
103         
104         var line = this.getElementsByTagNameNS(item,
105                                                 this.georssns,
106                                                 "line");
107         var polygon = this.getElementsByTagNameNS(item,
108                                                 this.georssns,
109                                                 "polygon");
110         var where = this.getElementsByTagNameNS(item, 
111                                                 this.georssns, 
112                                                 "where");
113         var box = this.getElementsByTagNameNS(item, 
114                                               this.georssns, 
115                                               "box");
116                                                                                                 
117         if (point.length > 0 || (lat.length > 0 && lon.length > 0)) {
118             var location;
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*/);
125                 }
126             } else {
127                 location = [parseFloat(lat[0].firstChild.nodeValue),
128                                 parseFloat(lon[0].firstChild.nodeValue)];
129             }    
130
131             var geometry = new OpenLayers.Geometry.Point(parseFloat(location[1]),
132                                                          parseFloat(location[0]));
133               
134         } else if (line.length > 0) {
135             var coords = OpenLayers.String.trim(this.concatChildValues(line[0])).split(/\s+/);
136             var components = []; 
137             var point;
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);
142             }
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+/);
146             var components = []; 
147             var point;
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);
152             }
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});
157             }
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+/);
162             var components = [];
163             var point;
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);
180             }
181             geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]);                                                                        
182         }
183         
184         if (geometry && this.internalProjection && this.externalProjection) {
185             geometry.transform(this.externalProjection, 
186                                this.internalProjection);
187         }
188
189         return geometry;
190     },        
191
192     /**
193      * Method: createFeatureFromItem
194      * Return a feature from a GeoRSS Item.
195      *
196      * Parameters:
197      * item - {DOMElement} A GeoRSS item node.
198      *
199      * Returns:
200      * {<OpenLayers.Feature.Vector>} A feature representing the item.
201      */
202     createFeatureFromItem: function(item) {
203         var geometry = this.createGeometryFromItem(item);
204      
205         /* Provide defaults for title and description */
206         var title = this.getChildValue(item, "*", "title", this.featureTitle);
207        
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)));
213
214         /* If no link URL is found in the first child node, try the
215            href attribute */
216         var link = this.getChildValue(item, "*", "link");
217         if(!link) {
218             try {
219                 link = this.getElementsByTagNameNS(item, "*", "link")[0].getAttribute("href");
220             } catch(e) {
221                 link = null;
222             }
223         }
224
225         var id = this.getChildValue(item, "*", "id", null);
226         
227         var data = {
228             "title": title,
229             "description": description,
230             "link": link
231         };
232         var feature = new OpenLayers.Feature.Vector(geometry, data);
233         feature.fid = id;
234         return feature;
235     },        
236     
237     /**
238      * Method: getChildValue
239      *
240      * Parameters:
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.
245      *
246      * Returns:
247      * {String} The value of the first child with the given tag name.  Returns
248      *     default value or empty string if none found.
249      */
250     getChildValue: function(node, nsuri, name, def) {
251         var value;
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;
256         } else {
257             value = (def == undefined) ? "" : def;
258         }
259         return value;
260     },
261     
262     /**
263      * APIMethod: read
264      * Return a list of features from a GeoRSS doc
265      
266      * Parameters:
267      * data - {Element} 
268      *
269      * Returns:
270      * An Array of <OpenLayers.Feature.Vector>s
271      */
272     read: function(doc) {
273         if (typeof doc == "string") { 
274             doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]);
275         }
276
277         /* Try RSS items first, then Atom entries */
278         var itemlist = null;
279         itemlist = this.getElementsByTagNameNS(doc, '*', 'item');
280         if (itemlist.length == 0) {
281             itemlist = this.getElementsByTagNameNS(doc, '*', 'entry');
282         }
283         
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]);
288         }
289         return features;
290     },
291     
292
293     /**
294      * APIMethod: write
295      * Accept Feature Collection, and return a string. 
296      * 
297      * Parameters: 
298      * features - {Array(<OpenLayers.Feature.Vector>)} List of features to serialize into a string.
299      */
300     write: function(features) {
301         var georss;
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]));
306             }
307         } else {
308             georss = this.createFeatureXML(features);
309         }
310         return OpenLayers.Format.XML.prototype.write.apply(this, [georss]);
311     },
312
313     /**
314      * Method: createFeatureXML
315      * Accept an <OpenLayers.Feature.Vector>, and build a geometry for it.
316      * 
317      * Parameters:
318      * feature - {<OpenLayers.Feature.Vector>} 
319      *
320      * Returns:
321      * {DOMElement}
322      */
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);
336         }    
337         for(var attr in feature.attributes) {
338             if (attr == "link" || attr == "title" || attr == "description") { continue; } 
339             var attrText = this.createTextNode(feature.attributes[attr]); 
340             var nodename = attr;
341             if (attr.search(":") != -1) {
342                 nodename = attr.split(":")[1];
343             }    
344             var attrContainer = this.createElementNS(this.featureNS, "feature:"+nodename);
345             attrContainer.appendChild(attrText);
346             featureNode.appendChild(attrContainer);
347         }    
348         featureNode.appendChild(geometryNode);
349         return featureNode;
350     },    
351     
352     /** 
353      * Method: buildGeometryNode
354      * builds a GeoRSS node with a given geometry
355      * 
356      * Parameters:
357      * geometry - {<OpenLayers.Geometry>}
358      *
359      * Returns:
360      * {DOMElement} A gml node.
361      */
362     buildGeometryNode: function(geometry) {
363         if (this.internalProjection && this.externalProjection) {
364             geometry = geometry.clone();
365             geometry.transform(this.internalProjection, 
366                                this.externalProjection);
367         }
368         var node;
369         // match Polygon
370         if (geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") {
371             node = this.createElementNS(this.georssns, 'georss:polygon');
372             
373             node.appendChild(this.buildCoordinatesNode(geometry.components[0]));
374         }
375         // match LineString
376         else if (geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") {
377             node = this.createElementNS(this.georssns, 'georss:line');
378             
379             node.appendChild(this.buildCoordinatesNode(geometry));
380         }
381         // match Point
382         else if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
383             node = this.createElementNS(this.georssns, 'georss:point');
384             node.appendChild(this.buildCoordinatesNode(geometry));
385         } else {
386             throw "Couldn't parse " + geometry.CLASS_NAME;
387         }  
388         return node;         
389     },
390     
391     /** 
392      * Method: buildCoordinatesNode
393      * 
394      * Parameters:
395      * geometry - {<OpenLayers.Geometry>}
396      */
397     buildCoordinatesNode: function(geometry) {
398         var points = null;
399         
400         if (geometry.components) {
401             points = geometry.components;
402         }
403
404         var path;
405         if (points) {
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;
410             }
411             path = parts.join(" ");
412         } else {
413             path = geometry.y + " " + geometry.x;
414         }
415         return this.createTextNode(path);
416     },
417
418     CLASS_NAME: "OpenLayers.Format.GeoRSS" 
419 });