Files
openlayers/lib/OpenLayers/Format/GeoRSS.js
crschmidt dd1b1433e4 Format.GeoRSS didn't use Format.XML serializer, nor did it support reading
anything other than points. Both of these are resolved with the new GeoRSS
support, which supports all of GeoRSS simple. Includes tests and significant
review from Senor Schaub, and addition to the examples/vector-formats.html
file. (Closes #973)


git-svn-id: http://svn.openlayers.org/trunk/openlayers@4305 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
2007-09-14 22:50:30 +00:00

340 lines
12 KiB
JavaScript

/* Copyright (c) 2006-2007 MetaCarta, Inc., published under a modified BSD license.
* See http://svn.openlayers.org/trunk/openlayers/repository-license.txt
* for the full text of the license. */
/**
* @requires OpenLayers/Format.js
* @requires OpenLayers/Format/XML.js
*
* Class: OpenLayers.Format.GeoRSS
* Read/write GeoRSS parser. Create a new instance with the
* <OpenLayers.Format.GeoRSS> constructor.
*
* Inherits from:
* - <OpenLayers.Format.XML>
*/
OpenLayers.Format.GeoRSS = OpenLayers.Class(OpenLayers.Format.XML, {
/**
* APIProperty: rssns
* {String} RSS namespace to use. Defaults to
* "http://backend.userland.com/rss2"
*/
rssns: "http://backend.userland.com/rss2",
/**
* APIProperty: featurens
* {String} Feature Attributes namespace. Defaults to
* "http://mapserver.gis.umn.edu/mapserver"
*/
featureNS: "http://mapserver.gis.umn.edu/mapserver",
/**
* APIProperty: georssns
* {String} GeoRSS namespace to use. Defaults to
* "http://www.georss.org/georss"
*/
georssns: "http://www.georss.org/georss",
/**
* APIProperty: featureTitle
* {String} Default title for features. Defaults to "Untitled"
*/
featureTitle: "Untitled",
/**
* APIProperty: featureDescription
* {String} Default description for features. Defaults to "No Description"
*/
featureDescription: "No Description",
/**
* Constructor: OpenLayers.Format.GeoRSS
* Create a new parser for GeoRSS.
*
* Parameters:
* options - {Object} An optional object whose properties will be set on
* this instance.
*/
initialize: function(options) {
OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
},
/**
* Method: createGeometryFromItem
* Return a geometry from a GeoRSS Item.
*
* Parameters:
* item - {DOMElement} A GeoRSS item node.
*
* Returns:
* {<OpenLayers.Geometry>} A geometry representing the node.
*/
createGeometryFromItem: function(item) {
var point = this.getElementsByTagNameNS(item, this.georssns, "point");
var lat = this.getElementsByTagNameNS(item, this.geons, 'lat');
var lon = this.getElementsByTagNameNS(item, this.geons, 'long');
var line = this.getElementsByTagNameNS(item,
this.georssns,
"line");
var polygon = this.getElementsByTagNameNS(item,
this.georssns,
"polygon");
if (point.length > 0 || (lat.length > 0 && lon.length > 0)) {
if (point.length > 0) {
var location = OpenLayers.String.trim(
point[0].firstChild.nodeValue).split(/\s+/);
if (location.length !=2) {
var location = OpenLayers.String.trim(
point[0].firstChild.nodeValue).split(/\s*,\s*/);
}
} else {
var location = [parseFloat(lat[0].firstChild.nodeValue),
parseFloat(lon[0].firstChild.nodeValue)];
}
var geometry = new OpenLayers.Geometry.Point(parseFloat(location[1]),
parseFloat(location[0]));
} else if (line.length > 0) {
var coords = OpenLayers.String.trim(line[0].firstChild.nodeValue).split(/\s+/);
var components = [];
for (var i=0; i < coords.length; i+=2) {
var point = new OpenLayers.Geometry.Point(parseFloat(coords[i+1]), parseFloat(coords[i]));
components.push(point);
}
geometry = new OpenLayers.Geometry.LineString(components);
} else if (polygon.length > 0) {
var coords = OpenLayers.String.trim(polygon[0].firstChild.nodeValue).split(/\s+/);
var components = [];
for (var i=0; i < coords.length; i+=2) {
var point = new OpenLayers.Geometry.Point(parseFloat(coords[i+1]), parseFloat(coords[i]));
components.push(point);
}
geometry = new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(components)]);
}
return geometry;
},
/**
* Method: createGeometryFromItem
* Return a feature from a GeoRSS Item.
*
* Parameters:
* item - {DOMElement} A GeoRSS item node.
*
* Returns:
* {<OpenLayers.Feature.Vector>} A feature representing the item.
*/
createFeatureFromItem: function(item) {
var geometry = this.createGeometryFromItem(item);
/* Provide defaults for title and description */
var title = this.getChildValue(item, "*", "title", this.featureTitle);
/* First try RSS descriptions, then Atom summaries */
var description = this.getChildValue(
item, "*", "description",
this.getChildValue(item, "*", "content", this.featureDescription)
);
/* If no link URL is found in the first child node, try the
href attribute */
var link = this.getChildValue(item, "*", "link");
if(!link) {
try {
link = this.getElementsByTagNameNS(item, "*", "link")[0].getAttribute("href");
} catch(e) {
link = null;
}
}
var id = this.getChildValue(item, "*", "id", null);
var data = {
"title": title,
"description": description,
"link": link
};
var feature = new OpenLayers.Feature.Vector(geometry, data);
feature.fid = id;
return feature;
},
/**
* Method: getChildValue
*
* Parameters:
* node - {DOMElement}
* nsuri - {String} Child node namespace uri ("*" for any).
* name - {String} Child node name.
* def - {String} Optional string default to return if no child found.
*
* Returns:
* {String} The value of the first child with the given tag name. Returns
* default value or empty string if none found.
*/
getChildValue: function(node, nsuri, name, def) {
var value;
try {
value = this.getElementsByTagNameNS(node, nsuri, name)[0].firstChild.nodeValue;
} catch(e) {
value = (def == undefined) ? "" : def;
}
return value;
},
/**
* APIMethod: read
* Return a list of features from a GeoRSS doc
* Parameters:
* data - {Element}
*
* Returns:
* An Array of <OpenLayers.Feature.Vector>s
*/
read: function(doc) {
if (typeof doc == "string") {
doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]);
}
/* Try RSS items first, then Atom entries */
var itemlist = null;
itemlist = this.getElementsByTagNameNS(doc, '*', 'item');
if (itemlist.length == 0) {
itemlist = this.getElementsByTagNameNS(doc, '*', 'entry');
}
var numItems = itemlist.length;
var features = new Array(numItems);
for(var i=0; i<numItems; i++) {
features[i] = this.createFeatureFromItem(itemlist[i]);
}
return features;
},
/**
* APIMethod: write
* Accept Feature Collection, and return a string.
*
* Parameters:
* features - Array({<OpenLayers.Feature.Vector>}) List of features to serialize into a string.
*/
write: function(features) {
var georss;
if(features instanceof Array) {
georss = this.createElementNS(this.rssns, "rss");
for(var i=0; i < features.length; i++) {
georss.appendChild(this.createFeatureXML(features[i]));
}
} else {
georss = this.createFeatureXML(features);
}
return OpenLayers.Format.XML.prototype.write.apply(this, [georss]);
},
/**
* Method: createFeatureXML
* Accept an <OpenLayers.Feature.Vector>, and build a geometry for it.
*
* Parameters:
* feature - {<OpenLayers.Feature.Vector>}
*
* Returns:
* {DOMElement}
*/
createFeatureXML: function(feature) {
var geometryNode = this.buildGeometryNode(feature.geometry);
var featureNode = this.createElementNS(this.rssns, "item");
var titleNode = this.createElementNS(this.rssns, "title");
titleNode.appendChild(this.createTextNode(feature.attributes.title ? feature.attributes.title : ""));
var descNode = this.createElementNS(this.rssns, "description");
descNode.appendChild(this.createTextNode(feature.attributes.description ? feature.attributes.description : ""));
featureNode.appendChild(titleNode);
featureNode.appendChild(descNode);
if (feature.attributes.link) {
var linkNode = this.createElementNS(this.rssns, "link");
linkNode.appendChild(this.createTextNode(feature.attributes.link));
featureNode.appendChild(linkNode);
}
for(var attr in feature.attributes) {
if (attr == "link" || attr == "title" || attr == "description") { continue; }
var attrText = this.createTextNode(feature.attributes[attr]);
var nodename = attr;
if (attr.search(":") != -1) {
nodename = attr.split(":")[1];
}
var attrContainer = this.createElementNS(this.featureNS, "feature:"+nodename);
attrContainer.appendChild(attrText);
featureNode.appendChild(attrContainer);
}
featureNode.appendChild(geometryNode);
return featureNode;
},
/**
* Method: buildGeometryNode
* builds a GeoRSS node with a given geometry
*
* Parameters:
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} A gml node.
*/
buildGeometryNode: function(geometry) {
var node;
// match Polygon
if (geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") {
node = this.createElementNS(this.georssns, 'georss:polygon');
node.appendChild(this.buildCoordinatesNode(geometry.components[0]));
}
// match LineString
else if (geometry.CLASS_NAME == "OpenLayers.Geometry.LineString") {
node = this.createElementNS(this.georssns, 'georss:line');
node.appendChild(this.buildCoordinatesNode(geometry));
}
// match Point
else if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point") {
node = this.createElementNS(this.georssns, 'georss:point');
node.appendChild(this.buildCoordinatesNode(geometry));
} else {
throw "Couldn't parse " + geometry.CLASS_NAME;
}
return node;
},
/**
* Method: buildCoordinatesNode
*
* Parameters:
* geometry - {<OpenLayers.Geometry>}
*/
buildCoordinatesNode: function(geometry) {
var points = null;
if (geometry.components) {
points = geometry.components;
}
var path;
if (points) {
var numPoints = points.length;
var parts = new Array(numPoints);
for (var i = 0; i < numPoints; i++) {
parts[i] = points[i].y + " " + points[i].x;
}
path = parts.join(" ");
} else {
path = geometry.y + " " + geometry.x;
}
return this.createTextNode(path);
},
CLASS_NAME: "OpenLayers.Format.GeoRSS"
});