1
|
/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
|
2
|
* full list of contributors). Published under the 2-clause BSD license.
|
3
|
* See license.txt in the OpenLayers distribution or repository for the
|
4
|
* full text of the license. */
|
5
|
|
6
|
/**
|
7
|
* @requires OpenLayers/Format/XML.js
|
8
|
* @requires OpenLayers/Feature/Vector.js
|
9
|
* @requires OpenLayers/Geometry/Point.js
|
10
|
* @requires OpenLayers/Geometry/LineString.js
|
11
|
* @requires OpenLayers/Geometry/Polygon.js
|
12
|
*/
|
13
|
|
14
|
/**
|
15
|
* Class: OpenLayers.Format.GeoRSS
|
16
|
* Read/write GeoRSS parser. Create a new instance with the
|
17
|
* <OpenLayers.Format.GeoRSS> constructor.
|
18
|
*
|
19
|
* Inherits from:
|
20
|
* - <OpenLayers.Format.XML>
|
21
|
*/
|
22
|
OpenLayers.Format.GeoRSS = OpenLayers.Class(OpenLayers.Format.XML, {
|
23
|
|
24
|
/**
|
25
|
* APIProperty: rssns
|
26
|
* {String} RSS namespace to use. Defaults to
|
27
|
* "http://backend.userland.com/rss2"
|
28
|
*/
|
29
|
rssns: "http://backend.userland.com/rss2",
|
30
|
|
31
|
/**
|
32
|
* APIProperty: featurens
|
33
|
* {String} Feature Attributes namespace. Defaults to
|
34
|
* "http://mapserver.gis.umn.edu/mapserver"
|
35
|
*/
|
36
|
featureNS: "http://mapserver.gis.umn.edu/mapserver",
|
37
|
|
38
|
/**
|
39
|
* APIProperty: georssns
|
40
|
* {String} GeoRSS namespace to use. Defaults to
|
41
|
* "http://www.georss.org/georss"
|
42
|
*/
|
43
|
georssns: "http://www.georss.org/georss",
|
44
|
|
45
|
/**
|
46
|
* APIProperty: geons
|
47
|
* {String} W3C Geo namespace to use. Defaults to
|
48
|
* "http://www.w3.org/2003/01/geo/wgs84_pos#"
|
49
|
*/
|
50
|
geons: "http://www.w3.org/2003/01/geo/wgs84_pos#",
|
51
|
|
52
|
/**
|
53
|
* APIProperty: featureTitle
|
54
|
* {String} Default title for features. Defaults to "Untitled"
|
55
|
*/
|
56
|
featureTitle: "Untitled",
|
57
|
|
58
|
/**
|
59
|
* APIProperty: featureDescription
|
60
|
* {String} Default description for features. Defaults to "No Description"
|
61
|
*/
|
62
|
featureDescription: "No Description",
|
63
|
|
64
|
/**
|
65
|
* Property: gmlParse
|
66
|
* {Object} GML Format object for parsing features
|
67
|
* Non-API and only created if necessary
|
68
|
*/
|
69
|
gmlParser: null,
|
70
|
|
71
|
/**
|
72
|
* APIProperty: xy
|
73
|
* {Boolean} Order of the GML coordinate: true:(x,y) or false:(y,x)
|
74
|
* For GeoRSS the default is (y,x), therefore: false
|
75
|
*/
|
76
|
xy: false,
|
77
|
|
78
|
/**
|
79
|
* Constructor: OpenLayers.Format.GeoRSS
|
80
|
* Create a new parser for GeoRSS.
|
81
|
*
|
82
|
* Parameters:
|
83
|
* options - {Object} An optional object whose properties will be set on
|
84
|
* this instance.
|
85
|
*/
|
86
|
|
87
|
/**
|
88
|
* Method: createGeometryFromItem
|
89
|
* Return a geometry from a GeoRSS Item.
|
90
|
*
|
91
|
* Parameters:
|
92
|
* item - {DOMElement} A GeoRSS item node.
|
93
|
*
|
94
|
* Returns:
|
95
|
* {<OpenLayers.Geometry>} A geometry representing the node.
|
96
|
*/
|
97
|
createGeometryFromItem: function(item) {
|
98
|
var point = this.getElementsByTagNameNS(item, this.georssns, "point");
|
99
|
var lat = this.getElementsByTagNameNS(item, this.geons, 'lat');
|
100
|
var lon = this.getElementsByTagNameNS(item, this.geons, 'long');
|
101
|
|
102
|
var line = this.getElementsByTagNameNS(item,
|
103
|
this.georssns,
|
104
|
"line");
|
105
|
var polygon = this.getElementsByTagNameNS(item,
|
106
|
this.georssns,
|
107
|
"polygon");
|
108
|
var where = this.getElementsByTagNameNS(item,
|
109
|
this.georssns,
|
110
|
"where");
|
111
|
var box = this.getElementsByTagNameNS(item,
|
112
|
this.georssns,
|
113
|
"box");
|
114
|
|
115
|
if (point.length > 0 || (lat.length > 0 && lon.length > 0)) {
|
116
|
var location;
|
117
|
if (point.length > 0) {
|
118
|
location = OpenLayers.String.trim(
|
119
|
point[0].firstChild.nodeValue).split(/\s+/);
|
120
|
if (location.length !=2) {
|
121
|
location = OpenLayers.String.trim(
|
122
|
point[0].firstChild.nodeValue).split(/\s*,\s*/);
|
123
|
}
|
124
|
} else {
|
125
|
location = [parseFloat(lat[0].firstChild.nodeValue),
|
126
|
parseFloat(lon[0].firstChild.nodeValue)];
|
127
|
}
|
128
|
|
129
|
var geometry = new OpenLayers.Geometry.Point(location[1], location[0]);
|
130
|
|
131
|
} else if (line.length > 0) {
|
132
|
var coords = OpenLayers.String.trim(this.getChildValue(line[0])).split(/\s+/);
|
133
|
var components = [];
|
134
|
var point;
|
135
|
for (var i=0, len=coords.length; i<len; i+=2) {
|
136
|
point = new OpenLayers.Geometry.Point(coords[i+1], coords[i]);
|
137
|
components.push(point);
|
138
|
}
|
139
|
geometry = new OpenLayers.Geometry.LineString(components);
|
140
|
} else if (polygon.length > 0) {
|
141
|
var coords = OpenLayers.String.trim(this.getChildValue(polygon[0])).split(/\s+/);
|
142
|
var components = [];
|
143
|
var point;
|
144
|
for (var i=0, len=coords.length; i<len; i+=2) {
|
145
|
point = new OpenLayers.Geometry.Point(coords[i+1], coords[i]);
|
146
|
components.push(point);
|
147
|
}
|
148
|
geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]);
|
149
|
} else if (where.length > 0) {
|
150
|
if (!this.gmlParser) {
|
151
|
this.gmlParser = new OpenLayers.Format.GML({'xy': this.xy});
|
152
|
}
|
153
|
var feature = this.gmlParser.parseFeature(where[0]);
|
154
|
geometry = feature.geometry;
|
155
|
} else if (box.length > 0) {
|
156
|
var coords = OpenLayers.String.trim(box[0].firstChild.nodeValue).split(/\s+/);
|
157
|
var components = [];
|
158
|
var point;
|
159
|
if (coords.length > 3) {
|
160
|
point = new OpenLayers.Geometry.Point(coords[1], coords[0]);
|
161
|
components.push(point);
|
162
|
point = new OpenLayers.Geometry.Point(coords[1], coords[2]);
|
163
|
components.push(point);
|
164
|
point = new OpenLayers.Geometry.Point(coords[3], coords[2]);
|
165
|
components.push(point);
|
166
|
point = new OpenLayers.Geometry.Point(coords[3], coords[0]);
|
167
|
components.push(point);
|
168
|
point = new OpenLayers.Geometry.Point(coords[1], coords[0]);
|
169
|
components.push(point);
|
170
|
}
|
171
|
geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]);
|
172
|
}
|
173
|
|
174
|
if (geometry && this.internalProjection && this.externalProjection) {
|
175
|
geometry.transform(this.externalProjection,
|
176
|
this.internalProjection);
|
177
|
}
|
178
|
|
179
|
return geometry;
|
180
|
},
|
181
|
|
182
|
/**
|
183
|
* Method: createFeatureFromItem
|
184
|
* Return a feature from a GeoRSS Item.
|
185
|
*
|
186
|
* Parameters:
|
187
|
* item - {DOMElement} A GeoRSS item node.
|
188
|
*
|
189
|
* Returns:
|
190
|
* {<OpenLayers.Feature.Vector>} A feature representing the item.
|
191
|
*/
|
192
|
createFeatureFromItem: function(item) {
|
193
|
var geometry = this.createGeometryFromItem(item);
|
194
|
|
195
|
/* Provide defaults for title and description */
|
196
|
var title = this._getChildValue(item, "*", "title", this.featureTitle);
|
197
|
|
198
|
/* First try RSS descriptions, then Atom summaries */
|
199
|
var description = this._getChildValue(
|
200
|
item, "*", "description",
|
201
|
this._getChildValue(item, "*", "content",
|
202
|
this._getChildValue(item, "*", "summary", this.featureDescription)));
|
203
|
|
204
|
/* If no link URL is found in the first child node, try the
|
205
|
href attribute */
|
206
|
var link = this._getChildValue(item, "*", "link");
|
207
|
if(!link) {
|
208
|
try {
|
209
|
link = this.getElementsByTagNameNS(item, "*", "link")[0].getAttribute("href");
|
210
|
} catch(e) {
|
211
|
link = null;
|
212
|
}
|
213
|
}
|
214
|
|
215
|
var id = this._getChildValue(item, "*", "id", null);
|
216
|
|
217
|
var data = {
|
218
|
"title": title,
|
219
|
"description": description,
|
220
|
"link": link
|
221
|
};
|
222
|
var feature = new OpenLayers.Feature.Vector(geometry, data);
|
223
|
feature.fid = id;
|
224
|
return feature;
|
225
|
},
|
226
|
|
227
|
/**
|
228
|
* Method: _getChildValue
|
229
|
*
|
230
|
* Parameters:
|
231
|
* node - {DOMElement}
|
232
|
* nsuri - {String} Child node namespace uri ("*" for any).
|
233
|
* name - {String} Child node name.
|
234
|
* def - {String} Optional string default to return if no child found.
|
235
|
*
|
236
|
* Returns:
|
237
|
* {String} The value of the first child with the given tag name. Returns
|
238
|
* default value or empty string if none found.
|
239
|
*/
|
240
|
_getChildValue: function(node, nsuri, name, def) {
|
241
|
var value;
|
242
|
var eles = this.getElementsByTagNameNS(node, nsuri, name);
|
243
|
if(eles && eles[0] && eles[0].firstChild
|
244
|
&& eles[0].firstChild.nodeValue) {
|
245
|
value = this.getChildValue(eles[0]);
|
246
|
} else {
|
247
|
value = (def == undefined) ? "" : def;
|
248
|
}
|
249
|
return value;
|
250
|
},
|
251
|
|
252
|
/**
|
253
|
* APIMethod: read
|
254
|
* Return a list of features from a GeoRSS doc
|
255
|
*
|
256
|
* Parameters:
|
257
|
* doc - {Element}
|
258
|
*
|
259
|
* Returns:
|
260
|
* {Array(<OpenLayers.Feature.Vector>)}
|
261
|
*/
|
262
|
read: function(doc) {
|
263
|
if (typeof doc == "string") {
|
264
|
doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]);
|
265
|
}
|
266
|
|
267
|
/* Try RSS items first, then Atom entries */
|
268
|
var itemlist = null;
|
269
|
itemlist = this.getElementsByTagNameNS(doc, '*', 'item');
|
270
|
if (itemlist.length == 0) {
|
271
|
itemlist = this.getElementsByTagNameNS(doc, '*', 'entry');
|
272
|
}
|
273
|
|
274
|
var numItems = itemlist.length;
|
275
|
var features = new Array(numItems);
|
276
|
for(var i=0; i<numItems; i++) {
|
277
|
features[i] = this.createFeatureFromItem(itemlist[i]);
|
278
|
}
|
279
|
return features;
|
280
|
},
|
281
|
|
282
|
|
283
|
/**
|
284
|
* APIMethod: write
|
285
|
* Accept Feature Collection, and return a string.
|
286
|
*
|
287
|
* Parameters:
|
288
|
* features - {Array(<OpenLayers.Feature.Vector>)} List of features to serialize into a string.
|
289
|
*/
|
290
|
write: function(features) {
|
291
|
var georss;
|
292
|
if(OpenLayers.Util.isArray(features)) {
|
293
|
georss = this.createElementNS(this.rssns, "rss");
|
294
|
for(var i=0, len=features.length; i<len; i++) {
|
295
|
georss.appendChild(this.createFeatureXML(features[i]));
|
296
|
}
|
297
|
} else {
|
298
|
georss = this.createFeatureXML(features);
|
299
|
}
|
300
|
return OpenLayers.Format.XML.prototype.write.apply(this, [georss]);
|
301
|
},
|
302
|
|
303
|
/**
|
304
|
* Method: createFeatureXML
|
305
|
* Accept an <OpenLayers.Feature.Vector>, and build a geometry for it.
|
306
|
*
|
307
|
* Parameters:
|
308
|
* feature - {<OpenLayers.Feature.Vector>}
|
309
|
*
|
310
|
* Returns:
|
311
|
* {DOMElement}
|
312
|
*/
|
313
|
createFeatureXML: function(feature) {
|
314
|
var geometryNode = this.buildGeometryNode(feature.geometry);
|
315
|
var featureNode = this.createElementNS(this.rssns, "item");
|
316
|
var titleNode = this.createElementNS(this.rssns, "title");
|
317
|
titleNode.appendChild(this.createTextNode(feature.attributes.title ? feature.attributes.title : ""));
|
318
|
var descNode = this.createElementNS(this.rssns, "description");
|
319
|
descNode.appendChild(this.createTextNode(feature.attributes.description ? feature.attributes.description : ""));
|
320
|
featureNode.appendChild(titleNode);
|
321
|
featureNode.appendChild(descNode);
|
322
|
if (feature.attributes.link) {
|
323
|
var linkNode = this.createElementNS(this.rssns, "link");
|
324
|
linkNode.appendChild(this.createTextNode(feature.attributes.link));
|
325
|
featureNode.appendChild(linkNode);
|
326
|
}
|
327
|
for(var attr in feature.attributes) {
|
328
|
if (attr == "link" || attr == "title" || attr == "description") { continue; }
|
329
|
var attrText = this.createTextNode(feature.attributes[attr]);
|
330
|
var nodename = attr;
|
331
|
if (attr.search(":") != -1) {
|
332
|
nodename = attr.split(":")[1];
|
333
|
}
|
334
|
var attrContainer = this.createElementNS(this.featureNS, "feature:"+nodename);
|
335
|
attrContainer.appendChild(attrText);
|
336
|
featureNode.appendChild(attrContainer);
|
337
|
}
|
338
|
featureNode.appendChild(geometryNode);
|
339
|
return featureNode;
|
340
|
},
|
341
|
|
342
|
/**
|
343
|
* Method: buildGeometryNode
|
344
|
* builds a GeoRSS node with a given geometry
|
345
|
*
|
346
|
* Parameters:
|
347
|
* geometry - {<OpenLayers.Geometry>}
|
348
|
*
|
349
|
* Returns:
|
350
|
* {DOMElement} A gml node.
|
351
|
*/
|
352
|
buildGeometryNode: function(geometry) {
|
353
|
if (this.internalProjection && this.externalProjection) {
|
354
|
geometry = geometry.clone();
|
355
|
geometry.transform(this.internalProjection,
|
356
|
this.externalProjection);
|
357
|
}
|
358
|
var node;
|
359
|
// match Polygon
|
360
|
if (geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") {
|
361
|
node = this.createElementNS(this.georssns, 'georss:polygon');
|
362
|
|
363
|
node.appendChild(this.buildCoordinatesNode(geometry.components[0]));
|
364
|
}
|
365
|
// match LineString
|
366
|
else if (geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") {
|
367
|
node = this.createElementNS(this.georssns, 'georss:line');
|
368
|
|
369
|
node.appendChild(this.buildCoordinatesNode(geometry));
|
370
|
}
|
371
|
// match Point
|
372
|
else if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
|
373
|
node = this.createElementNS(this.georssns, 'georss:point');
|
374
|
node.appendChild(this.buildCoordinatesNode(geometry));
|
375
|
} else {
|
376
|
throw "Couldn't parse " + geometry.CLASS_NAME;
|
377
|
}
|
378
|
return node;
|
379
|
},
|
380
|
|
381
|
/**
|
382
|
* Method: buildCoordinatesNode
|
383
|
*
|
384
|
* Parameters:
|
385
|
* geometry - {<OpenLayers.Geometry>}
|
386
|
*/
|
387
|
buildCoordinatesNode: function(geometry) {
|
388
|
var points = null;
|
389
|
|
390
|
if (geometry.components) {
|
391
|
points = geometry.components;
|
392
|
}
|
393
|
|
394
|
var path;
|
395
|
if (points) {
|
396
|
var numPoints = points.length;
|
397
|
var parts = new Array(numPoints);
|
398
|
for (var i = 0; i < numPoints; i++) {
|
399
|
parts[i] = points[i].y + " " + points[i].x;
|
400
|
}
|
401
|
path = parts.join(" ");
|
402
|
} else {
|
403
|
path = geometry.y + " " + geometry.x;
|
404
|
}
|
405
|
return this.createTextNode(path);
|
406
|
},
|
407
|
|
408
|
CLASS_NAME: "OpenLayers.Format.GeoRSS"
|
409
|
});
|