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@openlayers.org >>> http://openlayers.org/mailman/listinfo/dev >>> >>> >>> !DSPAM:4033,46cd662e41812090977483! >>> >> >> _______________________________________________ >> Dev mailing list >> Dev@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@openlayers.org http://openlayers.org/mailman/listinfo/dev