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