[OpenLayers-Dev] OpenLayers.Format.KML.write()

Damien Corpataux damien.corpataux at camptocamp.com
Wed Aug 15 10:36:02 EDT 2007


Hello,

Here's what I did so far... Reading KML only work for KML 2.0 namespaces
for write() uses OpenLayers.Ajax.getElementsByTagNameNS(), but I'm
pretty sure it will work on future versions (2.1 parsing successful).
Also, GML and KML write() returns a Dom Document rather than a string.
Should one change the result type, breaking OpenLayers.Format interface,
or parse it into a string using OpenLayers.XML.....?

Cheers,
Damien


--8<-------------------------------------------------------------------------------------

Index: /home/dcorpataux/workspace/openlayers/lib/OpenLayers/Format/KML.js
===================================================================
---
/home/dcorpataux/workspace/openlayers/lib/OpenLayers/Format/KML.js   
(revision 3900)
+++
/home/dcorpataux/workspace/openlayers/lib/OpenLayers/Format/KML.js   
(working copy)
@@ -8,8 +8,8 @@
  * @requires OpenLayers/Ajax.js
  *
  * Class: OpenLayers.Format.KML
- * Read only KML. Largely Proof of Concept: does not support advanced
Features,
- *     including Polygons.  Create a new instance with the
+ * Read/write KML 2.0. Does not support advanced Features.
+ *     Create a new instance with the
  *     <OpenLayers.Format.KML> constructor.
  *
  * Inherits from:
@@ -100,6 +100,19 @@
                 // TBD Bounds only set for one of multiple geometries
                 geom.extendBounds(p.bounds);
             }
+
+        // match Polygon
+        } else if (OpenLayers.Ajax.getElementsByTagNameNS(xmlNode,
+            this.kmlns, "", "Polygon").length != 0) {
+            var polygon = OpenLayers.Ajax.getElementsByTagNameNS(xmlNode,
+                this.kmlns, "", "Polygon")[0];
+            p = this.parseCoords(polygon);
+            if (p.points) {
+                var linearRing = new
OpenLayers.Geometry.LinearRing(p.points);
+                geom = new OpenLayers.Geometry.Polygon(linearRing);
+                // TBD Bounds only set for one of multiple geometries
+                geom.extendBounds(p.bounds);
+            }
         }
        
         feature.geometry = geom;
@@ -190,6 +203,136 @@
         }
         return p;
     },
+   
+    /**
+     * Accept Feature Collection, and return a string.
+     *
+     * @param {Array} List of features to serialize into a string.
+     */
+     write: function(features) {
+        var kml =
document.createElementNS("http://earth.google.com/kml/2.0", "kml:kml");
// 'kml:' NS to be removed?
+        for (var i=0; i < features.length; i++) {
+            kml.appendChild(this.createPlacemarkXML(features[i]));
+        }
+        return kml;
+     },
+
+    /**
+     * Accept an OpenLayers.Feature.Vector, and build a geometry for it.
+     *
+     * @param OpenLayers.Feature.Vector feature
+     * @return DOMElement
+     */
+    createPlacemarkXML: function(feature) {
+        // Placemark name
+        var placemarkName = document.createElementNS(this.kmlns, "kml:"
+ "name");
+        var placemarkNameText = document.createTextNode(feature.id);
+        placemarkName.appendChild(placemarkNameText);
+
+        // Placemark description
+        var placemarkDesc = document.createElementNS(this.kmlns, "kml:"
+ "description");
+        var placemarkDescText = document.createTextNode("Not available");
+        placemarkDesc.appendChild(placemarkDescText);
+       
+        // Placemark
+        var placemarkNode = document.createElementNS(this.kmlns, "kml:"
+ "Placemark");
+        placemarkNode.appendChild(placemarkName);
+        placemarkNode.appendChild(placemarkDesc);
+
+        // Geometry node (Point, LineString, etc. nodes)
+        var geometryNode = this.buildGeometryNode(feature.geometry);
+        placemarkNode.appendChild(geometryNode);       
+       
+        return placemarkNode;
+    },   
+
+    /**
+     * builds a KML geometry node with a given geometry
+     *
+     * @param {OpenLayers.Geometry} geometry
+     */
+    buildGeometryNode: function(geometry) {
+    // TBD test if geoserver can be given a Multi-geometry for a
simple-geometry data store
+    // ie if multipolygon can be sent for a polygon feature type
+        var kml = "";
+        // match MultiPolygon or Polygon
+        if (geometry.CLASS_NAME == "OpenLayers.Geometry.MultiPolygon"
+            || geometry.CLASS_NAME == "OpenLayers.Geometry.Polygon") {
+                kml = document.createElementNS(this.kmlns, 'kml:Polygon');
+               
+                var polygon = document.createElementNS(this.kmlns,
'kml:Polygon');
+                var outerRing = document.createElementNS(this.kmlns,
'kml:outerBoundaryIs');
+                var linearRing = document.createElementNS(this.kmlns,
'kml:LinearRing');
+               
+                // TBD manage polygons with holes
+               
linearRing.appendChild(this.buildCoordinatesNode(geometry.components[0]));
+                outerRing.appendChild(linearRing);
+                polygon.appendChild(outerRing);
+               
+                kml.appendChild(polygon);
+            }
+        // match MultiLineString or LineString
+        else if (geometry.CLASS_NAME ==
"OpenLayers.Geometry.MultiLineString"
+                 || geometry.CLASS_NAME ==
"OpenLayers.Geometry.LineString") {
+                     kml = document.createElementNS(this.kmlns,
'kml:LineString');
+                    
+                     var lineString =
document.createElementNS(this.kmlns, 'kml:LineString');
+                    
+                    
lineString.appendChild(this.buildCoordinatesNode(geometry));
+                    
+                     kml.appendChild(lineString);
+                 }
+        // match MultiPoint or Point
+        else if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point" ||
+                  geometry.CLASS_NAME ==
"OpenLayers.Geometry.MultiPoint") {                    
+                kml = document.createElementNS(this.kmlns, 'kml:Point');
+
+                // FIXME: There should be only one Point node per
Placemark node
+                var parts = "";
+                if (geometry.CLASS_NAME ==
"OpenLayers.Geometry.MultiPoint") {
+                    parts = geometry.components;
+                } else {
+                    parts = [geometry];
+                }   
+               
+                for (var i = 0; i < parts.length; i++) {
+                    var point = document.createElementNS(this.kmlns,
'kml:Point');
+                    point.appendChild(this.buildCoordinatesNode(parts[i]));
+                    kml.appendChild(point);
+               }    
+        }
+        return kml;        
+    },
+    
+    /**
+     * builds the coordinates XmlNode
+     * <kml:coordinates>...</kml:coordinates>
+     *
+     * @param {OpenLayers.Geometry} geometry
+     * @return {XmlNode} created xmlNode
+     */
+    buildCoordinatesNode: function(geometry) {
+        var coordinatesNode = document.createElementNS(this.kmlns,
"kml:coordinates");
+       
+        var points = null;
+        if (geometry.components) {
+            points = geometry.components;
+        }
+
+        var path = "";
+        if (points) {
+            for (var i = 0; i < points.length; i++) {
+                path += points[i].x + "," + points[i].y + " ";
+            }
+        } else {
+           path += geometry.x + "," + geometry.y + " ";
+        }   
+       
+        var txtNode = document.createTextNode(path);
+        coordinatesNode.appendChild(txtNode);
+       
+        return coordinatesNode;
+    },   
 
     CLASS_NAME: "OpenLayers.Format.KML"
 });    




Christopher Schmidt wrote:
> On Tue, Aug 14, 2007 at 04:16:32PM +0200, Damien Corpataux wrote:
>   
>> Hello,
>>
>> I'd like to implement a bit of OpenLayers.Format.KML.write() method, and
>> enhance OpenLayers.Format.KML.read() to enabl.e Polygon node parsing...
>>
>> Questions:
>> 1/ Did you have any reason not to have implemented Polygon parsing at
>> once with Point and LineString? I thought it could be because of the
>> outerBoudaryIs node, which cannot be translated into OpenLayers.Geometry
>> object...? Or was it just laziness? :-)
>>     
>
> Just laziness.
>
>   
>> 2/ How do you see the namespaces for KML? My view is that one can parse
>> any KML as a 2.0, fetching Placemark nodes and digging into their
>> geometries, since this seems not to change over versions. Do you think
>> it's a good way of doing it?
>>     
>
> I didn't know enough about KML at the time I wrote it to know if this
> was true or not. I'd be happy to be better informed either way. 
>
> Regards,
>   


-- 
Camptocamp SA
Damien Corpataux
PSE A
CH-1015 Lausanne
+41 21 619 10 22 (Direct)
+41 21 619 10 10 (Centrale)
+41 21 619 10 00 (Fax)
P Please consider the environment
Do you really need to print this email?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.osgeo.org/pipermail/openlayers-dev/attachments/20070815/bd94643f/attachment.html


More information about the Dev mailing list