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

Frank Porcelli fporcelli at taic.net
Tue Sep 11 20:50:21 EDT 2007


Hi Tim --

The only thing I noticed is when using IE6 the KML features do not overlay
with the same map when using IE7 or Firefox. It seems the features in IE6
are not displaying at the correct locations. Is this a known bug?

Regards,

Frank

-----Original Message-----
From: dev-bounces at openlayers.org [mailto:dev-bounces at openlayers.org] On
Behalf Of Tim Schaub
Sent: Tuesday, September 11, 2007 1:12 PM
To: dev at openlayers.org
Subject: Re: [OpenLayers-Dev] OpenLayers.Format.KML.write()

Damien Corpataux wrote:
> 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
> 

Thanks for the patch Damien.  I rewrote things a bit and put this in 
with r4219 [1].  I added support for KML MultiGeometry and improved the 
read/write stuff so all OL geometries are supported.  Also, 
name/description attributes and feature id survive a round trip through 
read/write.

There are likely still issues with the parser.  In particular, we don't 
write out feature attributes (beyond name/description).

You can play with the vector formats example to see OL KML output [2]. 
Paste in any KML you can find and report back any trouble with the parser.

Tim

[1] http://trac.openlayers.org/changeset/4219

[2] http://openlayers.org/dev/examples/vector-formats.html



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

_______________________________________________
Dev mailing list
Dev at openlayers.org
http://openlayers.org/mailman/listinfo/dev




More information about the Dev mailing list