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

Damien Corpataux damien.corpataux at camptocamp.com
Tue Sep 4 10:28:52 EDT 2007


Hi Tim,

I just posted a patch on ticket #927. The patch suits the requirements:
- KML extends XML
- XML class methods are used for XML manipulation
- tested on FF2/Linux and IE7
- KML.write() returns a string (using XML.write())
- GGE import of OL exported KML is working, and vice-versa

My 2 cents

Cheers,
Damien


Tim Schaub wrote:
> 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:
>   
>> 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
>>   *     <OpenLayers.Format.KML> constructor.
>>   *
>>   * Inherits from:
>> @@ -24,6 +24,24 @@
>>      kmlns: "http://earth.google.com/kml/2.0",
>>     
>>      /**
>> +     * 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 <OpenLayers.Feature.Vector> features.
>> +     *
>> +     * Returns:
>> +     * <DOMDocument>
>> +     */
>> +     write: function(features) {
>> +        var kml = document.createElementNS(this.kmlns, "kml");
>> +        var folder = this.createFolderXML();
>> +        for (var i=0; i < 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 - {<XMLNode>}
>> +     */
>> +    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 - {<OpenLayers.Feature.Vector>}
>> +     *
>> +     * Returns:
>> +     * xmlNode - {<XMLNode>}
>> +     */
>> +    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 - {<OpenLayers.Geometry>}
>> +     *
>> +     * Returns:
>> +     * xmlNode - {<XMLNode>}
>> +     */
>> +    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 < parts.length; i++) {
>> +                    kml.appendChild(this.buildCoordinatesNode(parts[i]));
>> +               }    
>> +        }
>> +        return kml;        
>> +    },
>> +    /**
>> +     * Method: buildCoordinatesNode
>> +     * builds the KML coordinates node
>> +     *
>> +     * Parameters:
>> +     * geometry - {<OpenLayers.Geometry>}
>> +     *
>> +     * Returns:
>> +     * xmlNode - {<XMLNode>}
>> +     */
>> +    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 < 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:
>>     
>>> 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:
>>> http://dev.openlayers.org/sandbox/tschaub/xml/lib/OpenLayers/Format/GML.js
>>>
>>> (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:
>>> http://dev.openlayers.org/sandbox/tschaub/xml/examples/vector-formats.html
>>>
>>> (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:
>>>   
>>>       
>>>> 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
>>>>
>>>>     
>>>>         
>> [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
>> Dev at openlayers.org
>> http://openlayers.org/mailman/listinfo/dev
>>
>>
>> !DSPAM:4033,46cd662e41812090977483!
>>     
>
> _______________________________________________
> Dev mailing list
> Dev at openlayers.org
> http://openlayers.org/mailman/listinfo/dev
>   


-- 
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/20070904/e2418c7e/attachment.html


More information about the Dev mailing list