[OpenLayers-Commits] r4219 - in trunk/openlayers: examples lib/OpenLayers/Format tests/Format
commits at openlayers.org
commits at openlayers.org
Tue Sep 11 11:18:43 EDT 2007
Author: tschaub
Date: 2007-09-11 11:18:42 -0400 (Tue, 11 Sep 2007)
New Revision: 4219
Modified:
trunk/openlayers/examples/vector-formats.html
trunk/openlayers/lib/OpenLayers/Format/KML.js
trunk/openlayers/tests/Format/test_KML.html
Log:
Full read/write support for KML. All KML 2.1 geometries supported. All OL geometries supported (closes #927).
Modified: trunk/openlayers/examples/vector-formats.html
===================================================================
--- trunk/openlayers/examples/vector-formats.html 2007-09-11 14:46:55 UTC (rev 4218)
+++ trunk/openlayers/examples/vector-formats.html 2007-09-11 15:18:42 UTC (rev 4219)
@@ -77,8 +77,8 @@
formats = {
wkt: new OpenLayers.Format.WKT(),
geojson: new OpenLayers.Format.GeoJSON(),
- gml: new OpenLayers.Format.GML() //,
- //kml: new OpenLayers.Format.KML()
+ gml: new OpenLayers.Format.GML(),
+ kml: new OpenLayers.Format.KML()
};
map.setCenter(new OpenLayers.LonLat(0, 0), 1);
@@ -146,7 +146,7 @@
<label for="formatType">Format</label>
<select name="formatType" id="formatType">
<option value="geojson" selected="selected">GeoJSON</option>
- <!--<option value="kml">KML</option>-->
+ <option value="kml">KML</option>
<option value="gml">GML</option>
<option value="wkt">Well-Known Text (WKT)</option>
</select>
Modified: trunk/openlayers/lib/OpenLayers/Format/KML.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Format/KML.js 2007-09-11 14:46:55 UTC (rev 4218)
+++ trunk/openlayers/lib/OpenLayers/Format/KML.js 2007-09-11 15:18:42 UTC (rev 4219)
@@ -5,34 +5,63 @@
/**
* @requires OpenLayers/Format.js
* @requires OpenLayers/Feature/Vector.js
- * @requires OpenLayers/Ajax.js
+ *
+ * Class: OpenLayers.Format.KML
+ * Read/Wite KML. Create a new instance with the <OpenLayers.Format.KML>
+ * constructor.
*
- * Class: OpenLayers.Format.KML
- * Read only KML. Largely Proof of Concept: does not support advanced Features,
- * including Polygons. Create a new instance with the
- * <OpenLayers.Format.KML> constructor.
- *
* Inherits from:
- * - <OpenLayers.Format>
+ * - <OpenLayers.Format.XML>
*/
-OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format, {
+OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, {
/**
* APIProperty: kmlns
- * KML Namespace to use. Defaults to 2.0 namespace.
+ * {String} KML Namespace to use. Defaults to 2.0 namespace.
*/
kmlns: "http://earth.google.com/kml/2.0",
+ /**
+ * APIProperty: placemarksDesc
+ * {String} Name of the placemarks. Default is "No description available."
+ */
+ placemarksDesc: "No description available",
+
+ /**
+ * APIProperty: foldersName
+ * {String} Name of the folders. Default is "OpenLayers export."
+ */
+ foldersName: "OpenLayers export",
+
+ /**
+ * APIProperty: foldersDesc
+ * {String} Description of the folders. Default is "Exported on [date]."
+ */
+ foldersDesc: "Exported on " + new Date(),
+
/**
+ * APIProperty: extractAttributes
+ * {Boolean} Extract attributes from KML. Default is true.
+ */
+ extractAttributes: true,
+
+ /**
* Constructor: OpenLayers.Format.KML
- * Create a new parser for KML
+ * Create a new parser for KML.
*
* Parameters:
* options - {Object} An optional object whose properties will be set on
- * this instance.
+ * this instance.
*/
initialize: function(options) {
- OpenLayers.Format.prototype.initialize.apply(this, [options]);
+ // compile regular expressions once instead of every time they are used
+ this.regExes = {
+ trimSpace: (/^\s*|\s*$/g),
+ removeSpace: (/\s*/g),
+ splitSpace: (/\s+/),
+ trimComma: (/\s*,\s*/g)
+ };
+ OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
},
/**
@@ -40,156 +69,569 @@
* Read data from a string, and return a list of features.
*
* Parameters:
- * data - {string} or {XMLNode>} data to read/parse.
+ * data - {String} or {DOMElement} data to read/parse.
+ *
+ * Returns:
+ * {Array(<OpenLayers.Feature.Vector>)} List of features.
*/
- read: function(data) {
- if (typeof data == "string") {
- data = OpenLayers.parseXMLString(data);
- }
- var featureNodes = OpenLayers.Ajax.getElementsByTagNameNS(data, this.kmlns, "", "Placemark");
-
- var features = [];
-
- // Process all the featureMembers
- for (var i = 0; i < featureNodes.length; i++) {
+ read: function(data) {
+ if(typeof data == "string") {
+ data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
+ }
+ var featureNodes = this.getElementsByTagNameNS(data,
+ this.kmlns,
+ "Placemark");
+ var numFeatures = featureNodes.length;
+ var features = new Array(numFeatures);
+ for(var i=0; i<numFeatures; i++) {
var feature = this.parseFeature(featureNodes[i]);
-
- if (feature) {
- features.push(feature);
+ if(feature) {
+ features[i] = feature;
+ } else {
+ throw "Bad Placemark: " + i;
}
}
return features;
- },
+ },
- /**
- * Method: parseFeature
- * This function is the core of the KML parsing code in OpenLayers.
- * It creates the geometries that are then attached to the returned
- * feature, and calls parseAttributes() to get attribute data out.
- *
- * Parameters:
- * xmlNode - {<DOMElement>}
- */
- parseFeature: function(xmlNode) {
- var geom;
- var p; // [points,bounds]
+ /**
+ * Method: parseFeature
+ * This function is the core of the KML parsing code in OpenLayers.
+ * It creates the geometries that are then attached to the returned
+ * feature, and calls parseAttributes() to get attribute data out.
+ *
+ * Parameters:
+ * node - {<DOMElement>}
+ *
+ * Returns:
+ * {<OpenLayers.Feature.Vector>} A vector feature.
+ */
+ parseFeature: function(node) {
+ // only accept one geometry per feature - look for highest "order"
+ var order = ["MultiGeometry", "Polygon", "LineString", "Point"];
+ var type, nodeList, geometry, parser;
+ for(var i=0; i<order.length; ++i) {
+ type = order[i];
+ nodeList = this.getElementsByTagNameNS(node, this.kmlns, type);
+ if(nodeList.length > 0) {
+ // only deal with first geometry of this type
+ var parser = this.parseGeometry[type.toLowerCase()];
+ if(parser) {
+ geometry = parser.apply(this, [nodeList[0]]);
+ } else {
+ OpenLayers.Console.error("Unsupported geometry type: " +
+ type);
+ }
+ // stop looking for different geometry types
+ break;
+ }
+ }
- var feature = new OpenLayers.Feature.Vector();
+ // construct feature (optionally with attributes)
+ var attributes;
+ if(this.extractAttributes) {
+ attributes = this.parseAttributes(node);
+ }
+ var feature = new OpenLayers.Feature.Vector(geometry, attributes);
- // match Point
- if (OpenLayers.Ajax.getElementsByTagNameNS(xmlNode,
- this.kmlns, "", "Point").length != 0) {
- var point = OpenLayers.Ajax.getElementsByTagNameNS(xmlNode,
- this.kmlns, "", "Point")[0];
-
- p = this.parseCoords(point);
- if (p.points) {
- geom = p.points[0];
- // TBD Bounds only set for one of multiple geometries
- geom.extendBounds(p.bounds);
+ var fid = node.getAttribute("id");
+ if(fid != null) {
+ feature.fid = fid;
+ }
+
+ return feature;
+ },
+
+ /**
+ * Property: parseGeometry
+ * Properties of this object are the functions that parse geometries based
+ * on their type.
+ */
+ parseGeometry: {
+
+ /**
+ * Method: parseGeometry.point
+ * Given a KML node representing a point geometry, create an OpenLayers
+ * point geometry.
+ *
+ * Parameters:
+ * node - {DOMElement} A KML Point node.
+ *
+ * Returns:
+ * {<OpenLayers.Geometry.Point>} A point geometry.
+ */
+ point: function(node) {
+ var nodeList = this.getElementsByTagNameNS(node, this.kmlns,
+ "coordinates");
+ var coords = [];
+ if(nodeList.length > 0) {
+ var coordString = nodeList[0].firstChild.nodeValue;
+ coordString = coordString.replace(this.regExes.removeSpace, "");
+ coords = coordString.split(",");
}
+
+ var point = null;
+ if(coords.length > 1) {
+ // preserve third dimension
+ if(coords.length == 2) {
+ coords[2] = null;
+ }
+ point = new OpenLayers.Geometry.Point(coords[0], coords[1],
+ coords[2]);
+ } else {
+ throw "Bad coordinate string: " + coordString;
+ }
+ return point;
+ },
- // match LineString
- } else if (OpenLayers.Ajax.getElementsByTagNameNS(xmlNode,
- this.kmlns, "", "LineString").length != 0) {
- var linestring = OpenLayers.Ajax.getElementsByTagNameNS(xmlNode,
- this.kmlns, "", "LineString")[0];
- p = this.parseCoords(linestring);
- if (p.points) {
- geom = new OpenLayers.Geometry.LineString(p.points);
- // TBD Bounds only set for one of multiple geometries
- geom.extendBounds(p.bounds);
+ /**
+ * Method: parseGeometry.linestring
+ * Given a KML node representing a linestring geometry, create an
+ * OpenLayers linestring geometry.
+ *
+ * Parameters:
+ * node - {DOMElement} A KML LineString node.
+ *
+ * Returns:
+ * {<OpenLayers.Geometry.LineString>} A linestring geometry.
+ */
+ linestring: function(node, ring) {
+ var nodeList = this.getElementsByTagNameNS(node, this.kmlns,
+ "coordinates");
+ var line = null;
+ if(nodeList.length > 0) {
+ var coordString = nodeList[0].firstChild.nodeValue;
+ coordString = coordString.replace(this.regExes.trimSpace,
+ "");
+ coordString = coordString.replace(this.regExes.trimComma,
+ ",");
+ var pointList = coordString.split(this.regExes.splitSpace);
+ var numPoints = pointList.length;
+ var points = new Array(numPoints);
+ var coords, numCoords;
+ for(var i=0; i<numPoints; ++i) {
+ coords = pointList[i].split(",");
+ numCoords = coords.length;
+ if(numCoords > 1) {
+ if(coords.length == 2) {
+ coords[2] = null;
+ }
+ points[i] = new OpenLayers.Geometry.Point(coords[0],
+ coords[1],
+ coords[2]);
+ } else {
+ throw "Bad LineString point coordinates: " +
+ pointList[i];
+ }
+ }
+ if(numPoints) {
+ if(ring) {
+ line = new OpenLayers.Geometry.LinearRing(points);
+ } else {
+ line = new OpenLayers.Geometry.LineString(points);
+ }
+ } else {
+ throw "Bad LineString coordinates: " + coordString;
+ }
}
+
+ return line;
+ },
+
+ /**
+ * Method: parseGeometry.polygon
+ * Given a KML node representing a polygon geometry, create an
+ * OpenLayers polygon geometry.
+ *
+ * Parameters:
+ * node - {DOMElement} A KML Polygon node.
+ *
+ * Returns:
+ * {<OpenLayers.Geometry.Polygon>} A polygon geometry.
+ */
+ polygon: function(node) {
+ var nodeList = this.getElementsByTagNameNS(node, this.kmlns,
+ "LinearRing");
+ var numRings = nodeList.length;
+ var components = new Array(numRings);
+ if(numRings > 0) {
+ // this assumes exterior ring first, inner rings after
+ var ring;
+ for(var i=0; i<nodeList.length; ++i) {
+ ring = this.parseGeometry.linestring.apply(this,
+ [nodeList[i], true]);
+ if(ring) {
+ components[i] = ring;
+ } else {
+ throw "Bad LinearRing geometry: " + i;
+ }
+ }
+ }
+ return new OpenLayers.Geometry.Polygon(components);
+ },
+
+ /**
+ * Method: parseGeometry.multigeometry
+ * Given a KML node representing a multigeometry, create an
+ * OpenLayers geometry collection.
+ *
+ * Parameters:
+ * node - {DOMElement} A KML MultiGeometry node.
+ *
+ * Returns:
+ * {<OpenLayers.Geometry.Polygon>} A geometry collection.
+ */
+ multigeometry: function(node) {
+ var child, parser;
+ var parts = [];
+ var children = node.childNodes;
+ for(var i=0; i<children.length; ++i ) {
+ child = children[i];
+ if(child.nodeType == 1) {
+ type = (child.prefix) ?
+ child.nodeName.split(":")[1] :
+ child.nodeName;
+ var parser = this.parseGeometry[type.toLowerCase()];
+ if(parser) {
+ parts.push(parser.apply(this, [child]));
+ }
+ }
+ }
+ return new OpenLayers.Geometry.Collection(parts);
}
- feature.geometry = geom;
- feature.attributes = this.parseAttributes(xmlNode);
-
- return feature;
- },
-
+ },
+
/**
* Method: parseAttributes
- * recursive function parse the attributes of a KML node.
- * Searches for any child nodes which aren't geometries,
- * and gets their value.
*
* Parameters:
- * xmlNode - {<DOMElement>}
+ * node - {<DOMElement>}
+ *
+ * Returns:
+ * {Object} An attributes object.
*/
- parseAttributes: function(xmlNode) {
- var nodes = xmlNode.childNodes;
+ parseAttributes: function(node) {
var attributes = {};
- for(var i = 0; i < nodes.length; i++) {
- var name = nodes[i].nodeName;
- var value = OpenLayers.Util.getXmlNodeValue(nodes[i]);
- // Ignore Geometry attributes
- // match ".//gml:pos|.//gml:posList|.//gml:coordinates"
- if((name.search(":pos")!=-1)
- ||(name.search(":posList")!=-1)
- ||(name.search(":coordinates")!=-1)){
- continue;
+ // assume attribute nodes are type 1 children with a type 3 child
+ var child, grandchildren, grandchild;
+ var children = node.childNodes;
+ for(var i=0; i<children.length; ++i) {
+ child = children[i];
+ if(child.nodeType == 1) {
+ grandchildren = child.childNodes;
+ if(grandchildren.length == 1) {
+ grandchild = grandchildren[0];
+ if(grandchild.nodeType == 3) {
+ name = (child.prefix) ?
+ child.nodeName.split(":")[1] :
+ child.nodeName;
+ value = grandchild.nodeValue.replace(
+ this.regExes.trimSpace, "");
+ attributes[name] = value;
+ }
+ }
}
-
- // Check for a leaf node
- if((nodes[i].childNodes.length == 1 && nodes[i].childNodes[0].nodeName == "#text")
- || (nodes[i].childNodes.length == 0 && nodes[i].nodeName!="#text")) {
- attributes[name] = value;
- }
- OpenLayers.Util.extend(attributes, this.parseAttributes(nodes[i]))
- }
+ }
return attributes;
},
-
+
/**
- * Method: parseCoords
- * Extract Geographic coordinates from an XML node.
+ * APIMethod: write
+ * Accept Feature Collection, and return a string.
+ *
+ * Parameters:
+ * features - An array of <OpenLayers.Feature.Vector> features.
*
+ * Returns:
+ * {String} A KML string.
+ */
+ write: function(features) {
+ if(!(features instanceof Array)) {
+ features = [features];
+ }
+ var kml = this.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 OpenLayers.Format.XML.prototype.write.apply(this, [kml]);
+ },
+
+ /**
+ * Method: createFolderXML
+ * Creates and returns a KML folder node
+ *
+ * Returns:
+ * {DOMElement}
+ */
+ createFolderXML: function() {
+ // Folder name
+ var folderName = this.createElementNS(this.kmlns, "name");
+ var folderNameText = this.createTextNode(this.foldersName);
+ folderName.appendChild(folderNameText);
+
+ // Folder description
+ var folderDesc = this.createElementNS(this.kmlns, "description");
+ var folderDescText = this.createTextNode(this.foldersDesc);
+ folderDesc.appendChild(folderDescText);
+
+ // Folder
+ var folder = this.createElementNS(this.kmlns, "Folder");
+ folder.appendChild(folderName);
+ folder.appendChild(folderDesc);
+
+ return folder;
+ },
+
+ /**
+ * Method: createPlacemarkXML
+ * Creates and returns a KML placemark node representing the given feature.
+ *
* Parameters:
- * xmlNode - {<XMLNode>}
+ * feature - {<OpenLayers.Feature.Vector>}
*
* Returns:
- * An array of <OpenLayers.Geometry.Point> points.
+ * {DOMElement}
*/
- parseCoords: function(xmlNode) {
- var p = [];
- p.points = [];
- // TBD: Need to handle an array of coordNodes not just coordNodes[0]
+ createPlacemarkXML: function(feature) {
+ // Placemark name
+ var placemarkName = this.createElementNS(this.kmlns, "name");
+ var name = (feature.attributes.name) ?
+ feature.attributes.name : feature.id;
+ placemarkName.appendChild(this.createTextNode(name));
+
+ // Placemark description
+ var placemarkDesc = this.createElementNS(this.kmlns, "description");
+ var desc = (feature.attributes.description) ?
+ feature.attributes.description : this.placemarksDesc;
+ placemarkDesc.appendChild(this.createTextNode(desc));
- var coordNodes = OpenLayers.Ajax.getElementsByTagNameNS(xmlNode, this.kmlns, "", "coordinates")[0];
- var coordString = OpenLayers.Util.getXmlNodeValue(coordNodes);
+ // Placemark
+ var placemarkNode = this.createElementNS(this.kmlns, "Placemark");
+ if(feature.fid != null) {
+ placemarkNode.setAttribute("id", feature.fid);
+ }
+ placemarkNode.appendChild(placemarkName);
+ placemarkNode.appendChild(placemarkDesc);
+
+ // Geometry node (Point, LineString, etc. nodes)
+ var geometryNode = this.buildGeometryNode(feature.geometry);
+ placemarkNode.appendChild(geometryNode);
- var firstCoord = coordString.split(" ");
+ // TBD - deal with remaining (non name/description) attributes.
+ return placemarkNode;
+ },
+
+ /**
+ * Method: buildGeometryNode
+ * Builds and returns a KML geometry node with the given geometry.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement}
+ */
+ buildGeometryNode: function(geometry) {
+ var className = geometry.CLASS_NAME;
+ var type = className.substring(className.lastIndexOf(".") + 1);
+ var builder = this.buildGeometry[type.toLowerCase()];
+ var node = null;
+ if(builder) {
+ node = builder.apply(this, [geometry]);
+ }
+ return node;
+ },
+
+ /**
+ * Property: buildGeometry
+ * Object containing methods to do the actual geometry node building
+ * based on geometry type.
+ */
+ buildGeometry: {
+ // TBD: Anybody care about namespace aliases here (these nodes have
+ // no prefixes)?
+
+ /**
+ * Method: buildGeometry.point
+ * Given an OpenLayers point geometry, create a KML point.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry.Point>} A point geometry.
+ *
+ * Returns:
+ * {DOMElement} A KML point node.
+ */
+ point: function(geometry) {
+ var kml = this.createElementNS(this.kmlns, "Point");
+ kml.appendChild(this.buildCoordinatesNode(geometry));
+ return kml;
+ },
- while (firstCoord[0] == "")
- firstCoord.shift();
+ /**
+ * Method: buildGeometry.multipoint
+ * Given an OpenLayers multipoint geometry, create a KML
+ * GeometryCollection.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry.Point>} A multipoint geometry.
+ *
+ * Returns:
+ * {DOMElement} A KML GeometryCollection node.
+ */
+ multipoint: function(geometry) {
+ return this.buildGeometry.collection(geometry);
+ },
+
+ /**
+ * Method: buildGeometry.linestring
+ * Given an OpenLayers linestring geometry, create a KML linestring.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry.LineString>} A linestring geometry.
+ *
+ * Returns:
+ * {DOMElement} A KML linestring node.
+ */
+ linestring: function(geometry) {
+ var kml = this.createElementNS(this.kmlns, "LineString");
+ kml.appendChild(this.buildCoordinatesNode(geometry));
+ return kml;
+ },
- var dim = firstCoord[0].split(",").length;
+ /**
+ * Method: buildGeometry.multilinestring
+ * Given an OpenLayers multilinestring geometry, create a KML
+ * GeometryCollection.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry.Point>} A multilinestring geometry.
+ *
+ * Returns:
+ * {DOMElement} A KML GeometryCollection node.
+ */
+ multilinestring: function(geometry) {
+ return this.buildGeometry.collection(geometry);
+ },
- // Extract an array of Numbers from CoordString
- var nums = (coordString) ? coordString.split(/[, \n\t]+/) : [];
+ /**
+ * Method: buildGeometry.linearring
+ * Given an OpenLayers linearring geometry, create a KML linearring.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry.LinearRing>} A linearring geometry.
+ *
+ * Returns:
+ * {DOMElement} A KML linearring node.
+ */
+ linearring: function(geometry) {
+ var kml = this.createElementNS(this.kmlns, "LinearRing");
+ kml.appendChild(this.buildCoordinatesNode(geometry));
+ return kml;
+ },
+ /**
+ * Method: buildGeometry.polygon
+ * Given an OpenLayers polygon geometry, create a KML polygon.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry.Polygon>} A polygon geometry.
+ *
+ * Returns:
+ * {DOMElement} A KML polygon node.
+ */
+ polygon: function(geometry) {
+ var kml = this.createElementNS(this.kmlns, "Polygon");
+ var rings = geometry.components;
+ var ringMember, ringGeom, type;
+ for(var i=0; i<rings.length; ++i) {
+ type = (i==0) ? "outerBoundaryIs" : "innerBoundaryIs";
+ ringMember = this.createElementNS(this.kmlns, type);
+ ringGeom = this.buildGeometry.linearring.apply(this,
+ [rings[i]]);
+ ringMember.appendChild(ringGeom);
+ kml.appendChild(ringMember);
+ }
+ return kml;
+ },
- // Remove elements caused by leading and trailing white space
- while (nums[0] == "")
- nums.shift();
-
- while (nums[nums.length-1] == "")
- nums.pop();
-
- for(i = 0; i < nums.length; i = i + dim) {
- x = parseFloat(nums[i]);
- y = parseFloat(nums[i+1]);
- p.points.push(new OpenLayers.Geometry.Point(x, y));
-
- if (!p.bounds) {
- p.bounds = new OpenLayers.Bounds(x, y, x, y);
- } else {
- p.bounds.extend(x, y);
+ /**
+ * Method: buildGeometry.multipolygon
+ * Given an OpenLayers multipolygon geometry, create a KML
+ * GeometryCollection.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry.Point>} A multipolygon geometry.
+ *
+ * Returns:
+ * {DOMElement} A KML GeometryCollection node.
+ */
+ multipolygon: function(geometry) {
+ return this.buildGeometry.collection(geometry);
+ },
+
+ /**
+ * Method: buildGeometry.collection
+ * Given an OpenLayers geometry collection, create a KML MultiGeometry.
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry.Collection>} A geometry collection.
+ *
+ * Returns:
+ * {DOMElement} A KML MultiGeometry node.
+ */
+ collection: function(geometry) {
+ var kml = this.createElementNS(this.kmlns, "MultiGeometry");
+ var child;
+ for(var i=0; i<geometry.components.length; ++i) {
+ child = this.buildGeometryNode.apply(this,
+ [geometry.components[i]]);
+ if(child) {
+ kml.appendChild(child);
+ }
}
+ return kml;
}
- return p;
},
+ /**
+ * Method: buildCoordinatesNode
+ * Builds and returns the KML coordinates node with the given geometry
+ * <coordinates>...</coordinates>
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Return:
+ * {DOMElement}
+ */
+ buildCoordinatesNode: function(geometry) {
+ var coordinatesNode = this.createElementNS(this.kmlns, "coordinates");
+
+ var path;
+ var points = geometry.components;
+ if(points) {
+ // LineString or LinearRing
+ var point;
+ var numPoints = points.length;
+ var parts = new Array(numPoints);
+ for(var i=0; i<numPoints; ++i) {
+ point = points[i];
+ parts[i] = point.x + "," + point.y;
+ }
+ path = parts.join(" ");
+ } else {
+ // Point
+ path = geometry.x + "," + geometry.y;
+ }
+
+ var txtNode = this.createTextNode(path);
+ coordinatesNode.appendChild(txtNode);
+
+ return coordinatesNode;
+ },
+
CLASS_NAME: "OpenLayers.Format.KML"
-});
+});
\ No newline at end of file
Modified: trunk/openlayers/tests/Format/test_KML.html
===================================================================
--- trunk/openlayers/tests/Format/test_KML.html 2007-09-11 14:46:55 UTC (rev 4218)
+++ trunk/openlayers/tests/Format/test_KML.html 2007-09-11 15:18:42 UTC (rev 4219)
@@ -3,6 +3,7 @@
<script src="../../lib/OpenLayers.js"></script>
<script type="text/javascript">
+ var test_content = '<kml xmlns="http://earth.google.com/kml/2.0"><Folder><name>OpenLayers export</name><description>Vector geometries from OpenLayers</description><Placemark id="KML.Polygon"><name>OpenLayers.Feature.Vector_344</name><description>A KLM Polygon</description><Polygon><outerBoundaryIs><LinearRing><coordinates>5.001370157823406,49.26855713824488 8.214706453896161,49.630662409673505 8.397385910100951,48.45172350357396 5.001370157823406,49.26855713824488</coordinates></LinearRing></outerBoundaryIs></Polygon></Placemark><Placemark id="KML.LineString"><name>OpenLayers.Feature.Vector_402</name><description>A KML LineString</description><LineString><coordinates>5.838523393080493,49.74814616928052 5.787079558782349,48.410795432216574 8.91427702008381,49.28932499608202</coordinates></LineString></Placemark><Placemark id="KML.Point"><name>OpenLayers.Feature.Vector_451</name><description>A KML Point</description><Point><coordinates>6.985073041685488,49.8682250149058</coordinates></Point></Placemark><Placemark id="KML.MultiGeometry"><name>SF Marina Harbor Master</name><description>KML MultiGeometry</description><MultiGeometry><LineString><coordinates>-122.4425587930444,37.80666418607323 -122.4428379594768,37.80663578323093</coordinates></LineString><LineString><coordinates>-122.4425509770566,37.80662588061205 -122.4428340530617,37.8065999493009</coordinates></LineString></MultiGeometry></Placemark></Folder></kml>';
function test_Format_KML_constructor(t) {
t.plan(4);
@@ -14,24 +15,32 @@
t.eq(format.foo, "bar", "constructor sets options correctly");
t.eq(typeof format.read, "function", "format has a read function");
t.eq(typeof format.write, "function", "format has a write function");
-
}
function test_Format_KML_read(t) {
- t.plan(1);
- t.ok(true, "Read tests not done yet.");
+ t.plan(5);
+ var features = (new OpenLayers.Format.KML()).read(this.test_content);
+ t.eq(features.length, 4, "Number of features read is correct");
+ t.ok(features[0].geometry.toString() == "POLYGON((5.001370157823406 49.26855713824488,8.214706453896161 49.630662409673505,8.397385910100951 48.45172350357396,5.001370157823406 49.26855713824488))", "polygon feature geometry correctly created");
+ t.ok(features[1].geometry.toString() == "LINESTRING(5.838523393080493 49.74814616928052,5.787079558782349 48.410795432216574,8.91427702008381 49.28932499608202)", "linestring feature geometry correctly created");
+ t.ok(features[2].geometry.toString() == "POINT(6.985073041685488 49.8682250149058)", "point feature geometry correctly created");
+ t.ok(features[3].geometry.CLASS_NAME == "OpenLayers.Geometry.Collection",
+ "read geometry collection");
}
function test_Format_KML_write(t) {
+ // make sure id, name, and description are preserved
t.plan(1);
- t.ok(true, "Write tests not done yet.");
+ var kmlExpected = this.test_content;
+ var options = {
+ folderName: "OpenLayers export",
+ foldersDesc: "Vector geometries from OpenLayers"
+ }
- var format = new OpenLayers.Format.KML();
- //var doc = format.read(text);
- //var out = format.write(doc);
- //out = out.replace(/[\r\n]/g, '');
- //t.eq(text, out,
- // "correctly writes an KML DOM doc");
+ var format = new OpenLayers.Format.KML(options);
+ var features = format.read(kmlExpected);
+ var kmlOut = format.write(features);
+ t.eq(kmlOut, kmlExpected, "correctly writes an KML doc string");
}
</script>
More information about the Commits
mailing list