GeoRSS.js 14 KB

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