<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type">
</head>
<body bgcolor="#ffffff" text="#000000">
Hi Tim,<br>
<br>
I just posted a patch on ticket #927. The patch suits the requirements:<br>
- KML extends XML<br>
- XML class methods are used for XML manipulation<br>
- tested on FF2/Linux and IE7<br>
- KML.write() returns a string (using XML.write())<br>
- GGE import of OL exported KML is working, and vice-versa<br>
<br>
My 2 cents<br>
<br>
Cheers,<br>
Damien<br>
<br>
<br>
Tim Schaub wrote:
<blockquote cite="mid46CF42ED.30502@openplans.org" type="cite">
  <pre wrap="">I've opened ticket #927 to track this.

If anybody has a patch for KML, please attach it to that ticket. 
Damien, I've referenced your email on the ticket.

Since XML flavors should now all inherit from the XML format class, I'd 
say that write will always return a string.

Thanks for any contributions.
Tim


Damien Corpataux wrote:
  </pre>
  <blockquote type="cite">
    <pre wrap="">Hello,

As far as I can see, the advantages of doing so are obvious. Althought I 
didn't have time to apply these, here is a new version of the patch:
- puts placemarks in a folder tag (for google earth import)
- bugfix with geometry tags

Is the question about write() return type (string or DOMDocuemt/DOMNode) 
still open?

Cheers,
Damien


Patch:
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
  *     &lt;OpenLayers.Format.KML&gt; constructor.
  *
  * Inherits from:
@@ -24,6 +24,24 @@
     kmlns: <a class="moz-txt-link-rfc2396E" href="http://earth.google.com/kml/2.0">"http://earth.google.com/kml/2.0"</a>,
    
     /**
+     * APIProperty: placemarksDesc
+     * Default description for a placemark
+     */
+    placemarksDesc: "No description available",
+
+    /**
+     * APIProperty: foldersName
+     * Default name for a folder
+     */
+    foldersName: "OpenLayers export",
+
+    /**
+     * APIProperty: foldersDesc
+     * Default description for a folder
+     */
+    foldersDesc: "Exported on " + new Date(),
+
+    /**
      * Constructor: OpenLayers.Format.KML
      * Create a new parser for KML
      *
@@ -46,7 +64,7 @@
         if (typeof data == "string") {
             data = OpenLayers.parseXMLString(data);
         }   
-        var featureNodes = OpenLayers.Ajax.getElementsByTagNameNS(data, 
this.kmlns, "", "Placemark");
+        var featureNodes = OpenLayers.Ajax.getElementsByTagNameNS(data, 
this.kmlns, "kml", "Placemark");
        
         var features = [];
        
@@ -100,6 +118,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;
@@ -191,5 +222,171 @@
         return p;
     },
 
+    /**
+     * Method: write
+     * Accept Feature Collection, and return an XML Document.
+     *
+     * Parameters:
+     * features - An array of &lt;OpenLayers.Feature.Vector&gt; features.
+     *
+     * Returns:
+     * &lt;DOMDocument&gt;
+     */
+     write: function(features) {
+        var kml = document.createElementNS(this.kmlns, "kml");
+        var folder = this.createFolderXML();
+        for (var i=0; i &lt; features.length; i++) {
+            folder.appendChild(this.createPlacemarkXML(features[i]));
+        }
+        kml.appendChild(folder);
+        return kml;
+     },
+
+    /**
+     * Method: createFolderXML
+     * Creates and returns a KML Folder node with default name and 
description
+     *
+     * Returns:
+     * xmlNode - {&lt;XMLNode&gt;}
+     */
+    createFolderXML: function() {
+        // Folder name
+        var folderName = document.createElementNS(this.kmlns, "name");
+        var folderNameText = document.createTextNode(this.foldersName);
+        folderName.appendChild(folderNameText);
+
+        // Folder description
+        var folderDesc = document.createElementNS(this.kmlns, 
"description");       
+        var folderDescText = document.createTextNode(this.foldersDesc);
+        folderDesc.appendChild(folderDescText);
+
+        // Folder
+        var folder = document.createElementNS(this.kmlns, "Folder");
+        folder.appendChild(folderName);
+        folder.appendChild(folderDesc);
+       
+        return folder;
+    },
+
+    /**
+     * Method: createPlacemarkXML
+     * Accept an OpenLayers.Feature.Vector, and create a KML Placemark node
+     *
+     * Parameters:
+     * feature - {&lt;OpenLayers.Feature.Vector&gt;}
+     *
+     * Returns:
+     * xmlNode - {&lt;XMLNode&gt;}
+     */
+    createPlacemarkXML: function(feature) {
+        // Placemark name
+        var placemarkName = document.createElementNS(this.kmlns, "name");
+        var placemarkNameText = document.createTextNode(feature.id);
+        placemarkName.appendChild(placemarkNameText);
+
+        // Placemark description
+        var placemarkDesc = document.createElementNS(this.kmlns, 
"description");
+        var placemarkDescText = 
document.createTextNode(this.placemarksDesc);
+        placemarkDesc.appendChild(placemarkDescText);
+       
+        // Placemark
+        var placemarkNode = document.createElementNS(this.kmlns, 
"Placemark");
+        placemarkNode.appendChild(placemarkName);
+        placemarkNode.appendChild(placemarkDesc);
+
+        // Geometry node (Point, LineString, etc. nodes)
+        var geometryNode = this.buildGeometryNode(feature.geometry);
+        placemarkNode.appendChild(geometryNode);       
+       
+        return placemarkNode;
+    },   
+
+    /**
+     * Method: buildGeometryNode
+     * Builds a KML geometry node with a given geometry
+     *
+     * Parameters:
+     * geometry - {&lt;OpenLayers.Geometry&gt;}
+     *
+     * Returns:
+     * xmlNode - {&lt;XMLNode&gt;}
+     */
+    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, 'Polygon');
+               
+                var outerRing = document.createElementNS(this.kmlns, 
'outerBoundaryIs');
+                var linearRing = document.createElementNS(this.kmlns, 
'LinearRing');
+               
+                // TBD manage polygons with holes
+                
linearRing.appendChild(this.buildCoordinatesNode(geometry.components[0]));
+                outerRing.appendChild(linearRing);
+               
+                kml.appendChild(outerRing);
+            }
+        // match MultiLineString or LineString
+        else if (geometry.CLASS_NAME == 
"OpenLayers.Geometry.MultiLineString"
+                 || geometry.CLASS_NAME == 
"OpenLayers.Geometry.LineString") {
+                     kml = document.createElementNS(this.kmlns, 
'LineString');
+                                         
+                     kml.appendChild(this.buildCoordinatesNode(geometry));
+                 }
+        // match MultiPoint or Point
+        else if (geometry.CLASS_NAME == "OpenLayers.Geometry.Point" ||
+                  geometry.CLASS_NAME == 
"OpenLayers.Geometry.MultiPoint") {                    
+                kml = document.createElementNS(this.kmlns, '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 &lt; parts.length; i++) {
+                    kml.appendChild(this.buildCoordinatesNode(parts[i]));
+               }    
+        }
+        return kml;        
+    },
+    /**
+     * Method: buildCoordinatesNode
+     * builds the KML coordinates node
+     *
+     * Parameters:
+     * geometry - {&lt;OpenLayers.Geometry&gt;}
+     *
+     * Returns:
+     * xmlNode - {&lt;XMLNode&gt;}
+     */
+    buildCoordinatesNode: function(geometry) {
+        var coordinatesNode = document.createElementNS(this.kmlns, 
"coordinates");
+       
+        var points = null;
+        if (geometry.components) {
+            points = geometry.components;
+        }
+
+        var path = "";
+        if (points) {
+            for (var i = 0; i &lt; 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"
 });    


Tim Schaub wrote:
    </pre>
    <blockquote type="cite">
      <pre wrap="">Hi-

So, we're mid-way through changing how XML flavors are read/written in 
OpenLayers.

I've checked a new XML format in to the trunk.  This format has most of 
the methods we need for reading/writing XML cross-browser.

To parse other XML flavors, format classes should be created that 
inherit from the XML format.

For an (incomplete) example, see:
<a class="moz-txt-link-freetext" href="http://dev.openlayers.org/sandbox/tschaub/xml/lib/OpenLayers/Format/GML.js">http://dev.openlayers.org/sandbox/tschaub/xml/lib/OpenLayers/Format/GML.js</a>

(The important part to notice in the above example is that the GML 
format inherits from the XML format.)

Instead of using OpenLayers.Ajax methods or document methods, DOM 
creation and traversal should be done with OpenLayers.Format.XML 
methods.  I've created methods to reflect the W3C standard XML DOM 
methods - wrapping the standard ones and accommodating for non-compliant 
browsers.

If you (or anyone) needs additional XML DOM methods, they should be 
added to the XML format.  The next addition (in my mind) is 
setAttributeNS.  Aside from that, you should be able to do efficient 
parsing and dom creation with the XML format methods.

Please make modifications to the KML format in the trunk.  Create a 
ticket and attach patches in Trac.  I can offer review or other help as 
needed.

I don't have time to keep these sandboxes entirely clean right now - so 
please forgive anything you find that is in a half-developed state.

Tim

PS - Eventually, I'll move the following example into the trunk.  It 
would be nice if we could demonstrate read/write capability for all 
vector formats in this way:
<a class="moz-txt-link-freetext" href="http://dev.openlayers.org/sandbox/tschaub/xml/examples/vector-formats.html">http://dev.openlayers.org/sandbox/tschaub/xml/examples/vector-formats.html</a>

(note again that this reflects partially complete work - and you should 
not be surprised to encounter errors or see changes at any time)


Damien Corpataux wrote:
  
      </pre>
      <blockquote type="cite">
        <pre wrap="">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

    
        </pre>
      </blockquote>
    </blockquote>
    <pre wrap="">[patch stripped]

-- 
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?
!DSPAM:4033,46cd662e41812090977483!


------------------------------------------------------------------------

_______________________________________________
Dev mailing list
<a class="moz-txt-link-abbreviated" href="mailto:Dev@openlayers.org">Dev@openlayers.org</a>
<a class="moz-txt-link-freetext" href="http://openlayers.org/mailman/listinfo/dev">http://openlayers.org/mailman/listinfo/dev</a>


!DSPAM:4033,46cd662e41812090977483!
    </pre>
  </blockquote>
  <pre wrap=""><!---->
_______________________________________________
Dev mailing list
<a class="moz-txt-link-abbreviated" href="mailto:Dev@openlayers.org">Dev@openlayers.org</a>
<a class="moz-txt-link-freetext" href="http://openlayers.org/mailman/listinfo/dev">http://openlayers.org/mailman/listinfo/dev</a>
  </pre>
</blockquote>
<br>
<br>
<div class="moz-signature">-- <br>
<style>
<!--
.signature {
  font-family:verdana,helvetica,sans-serif;
  font-size:0.8em;
  line-height: 1.25em;
  color: #9999BB;
  width: 27em;
}

.signature div {
  padding: 0.22em;
  margin-bottom: 0.5em;
  margin-top: 0.5em;
  border-bottom: 1px dotted lightgray;
  background-color: #FCFCFF;
}

.signature .attention {
  background-color: #FFFAFA;
  color: #FFBBBB;
  font-size: 0.8em;
  font-weight: bold;
}

.header {
}
-->
</style>
<div class="signature">
<div> <span style="font-weight: bold;">Camptocamp SA</span><br>
Damien Corpataux<br>
PSE A<br>
CH-1015 Lausanne<br>
</div>
<div> +41 21 619 10 22 <span class="header">(Direct)</span><br>
+41 21 619 10 10 <span class="header">(Centrale)</span><br>
+41 21 619 10 00 <span class="header">(Fax)</span><br>
</div>
<div style="color: rgb(102, 204, 102);"> <span
 style="position: relative; top: -3px; font-family: Webdings; font-size: 24pt;">P</span>
<span style="">Please consider the environment <br>
Do you really need to print this email?</span>
</div>
</div>
</div>
</body>
</html>