/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD * license.  See http://svn.openlayers.org/trunk/openlayers/license.txt for the * full text of the license. *//** * @requires OpenLayers/Format/XML.js * @requires OpenLayers/Feature/Vector.js * @requires OpenLayers/Geometry/Point.js * @requires OpenLayers/Geometry/LineString.js * @requires OpenLayers/Geometry/Polygon.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: geons    * {String} W3C Geo namespace to use.  Defaults to    *     "http://www.w3.org/2003/01/geo/wgs84_pos#"    */    geons: "http://www.w3.org/2003/01/geo/wgs84_pos#",    /**    * 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",    featureIcon: "Standard",    featureStation: "na",    featureGasoline: "na",    featureE85: "na",    featureDiesel: "na",    featureAddress: "na",    featureCity: "na",    featureName: "na",    featureB98: "na",    featureBVP: "na",    featureADB: "na",    /**    * Property: gmlParse    * {Object} GML Format object for parsing features    * Non-API and only created if necessary    */    gmlParser: null,    /**    * APIProperty: xy    * {Boolean} Order of the GML coordinate: true:(x,y) or false:(y,x)    * For GeoRSS the default is (y,x), therefore: false    */    xy: false,    /**    * 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");        var where = this.getElementsByTagNameNS(item, this.georssns, "where");        if (point.length > 0 || (lat.length > 0 && lon.length > 0)) {            var location;            if (point.length > 0) {                location = OpenLayers.String.trim(point[0].firstChild.nodeValue).split(/\s+/);                if (location.length != 2) {                    location = OpenLayers.String.trim(point[0].firstChild.nodeValue).split(/\s*,\s*/);                }            } else {                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(this.concatChildValues(line[0])).split(/\s+/);            var components = [];            var point;            for (var i = 0, len = coords.length; i < len; i += 2) {                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(this.concatChildValues(polygon[0])).split(/\s+/);            var components = [];            var point;            for (var i = 0, len = coords.length; i < len; i += 2) {                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)]);        } else if (where.length > 0) {            if (!this.gmlParser) {                this.gmlParser = new OpenLayers.Format.GML({ 'xy': this.xy });            }            var feature = this.gmlParser.parseFeature(where[0]);            geometry = feature.geometry;        }        if (geometry && this.internalProjection && this.externalProjection) {            geometry.transform(this.externalProjection, this.internalProjection);        }        return geometry;    },    /**    * Method: createFeatureFromItem    * 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)        );        var iconPath = this.getChildValue(item, "*", "icon", this.featureIcon);        var station = this.getChildValue(item, "*", "station",this.featureStation);        var city = this.getChildValue(item, "*", "city",this.featureCity);        var address = this.getChildValue(item, "*", "address",this.featureAddress);        var name = this.getChildValue(item, "*", "name",this.featureName);                var gasoline = this.getChildValue(item, "*", "gasoline",this.featureGasoline);        var e85 = this.getChildValue(item, "*", "e85",this.featureE85);        var diesel = this.getChildValue(item, "*", "diesel",this.featureDiesel);        var b98 = this.getChildValue(item, "*", "b98",this.featureB98);        var bvp = this.getChildValue(item, "*", "bvp",this.featureBVP);        var adb = this.getChildValue(item, "*", "adb",this.featureADB);                /* 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,            "iconPath": iconPath,            "station": station,            "city": city,            "address": address,            "name": name,            "bensin": gasoline,            "e85": e85,            "diesel": diesel,            "b98": b98,            "bvp": bvp,            "adb": adb        };        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;        var eles = this.getElementsByTagNameNS(node, nsuri, name);        if (eles && eles[0] && eles[0].firstChild && eles[0].firstChild.nodeValue) {            value = eles[0].firstChild.nodeValue;        } else {            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, len = features.length; i < len; 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) {        if (this.internalProjection && this.externalProjection) {            geometry = geometry.clone();            geometry.transform(this.internalProjection, this.externalProjection);        }        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"});     
