Software: Apache. PHP/5.5.15 uname -a: Windows NT SVR-DMZ 6.1 build 7600 (Windows Server 2008 R2 Enterprise Edition) i586 SYSTEM Safe-mode: OFF (not secure) C:\dmz\phpMyAdmin\js\openlayers\src\openlayers\lib\OpenLayers\Format\ drwxrwxrwx |
Viewing file: KML.js (50.79 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) | /* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for * full list of contributors). Published under the Clear BSD license. * See http://svn.openlayers.org/trunk/openlayers/license.txt for the * full text of the license. */ /** * @requires OpenLayers/Format/XML.js * @requires OpenLayers/Feature/Vector.js * @requires OpenLayers/Geometry/Point.js * @requires OpenLayers/Geometry/LineString.js * @requires OpenLayers/Geometry/Polygon.js * @requires OpenLayers/Geometry/Collection.js * @requires OpenLayers/Request/XMLHttpRequest.js * @requires OpenLayers/Console.js * @requires OpenLayers/Projection.js */ /** * Class: OpenLayers.Format.KML * Read/Write KML. Create a new instance with the <OpenLayers.Format.KML> * constructor. * * Inherits from: * - <OpenLayers.Format.XML> */ OpenLayers.Format.KML = OpenLayers.Class(OpenLayers.Format.XML, { /** * Property: namespaces * {Object} Mapping of namespace aliases to namespace URIs. */ namespaces: { kml: "http://www.opengis.net/kml/2.2", gx: "http://www.google.com/kml/ext/2.2" }, /** * APIProperty: kmlns * {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". * If set to null, no name element will be created. */ foldersName: "OpenLayers export", /** * APIProperty: foldersDesc * {String} Description of the folders. Default is "Exported on [date]." * If set to null, no description element will be created. */ foldersDesc: "Exported on " + new Date(), /** * APIProperty: extractAttributes * {Boolean} Extract attributes from KML. Default is true. * Extracting styleUrls requires this to be set to true */ extractAttributes: true, /** * Property: extractStyles * {Boolean} Extract styles from KML. Default is false. * Extracting styleUrls also requires extractAttributes to be * set to true */ extractStyles: false, /** * APIProperty: extractTracks * {Boolean} Extract gx:Track elements from Placemark elements. Default * is false. If true, features will be generated for all points in * all gx:Track elements. Features will have a when (Date) attribute * based on when elements in the track. If tracks include angle * elements, features will have heading, tilt, and roll attributes. * If track point coordinates have three values, features will have * an altitude attribute with the third coordinate value. */ extractTracks: false, /** * APIProperty: trackAttributes * {Array} If <extractTracks> is true, points within gx:Track elements will * be parsed as features with when, heading, tilt, and roll attributes. * Any additional attribute names can be provided in <trackAttributes>. */ trackAttributes: null, /** * Property: internalns * {String} KML Namespace to use -- defaults to the namespace of the * Placemark node being parsed, but falls back to kmlns. */ internalns: null, /** * Property: features * {Array} Array of features * */ features: null, /** * Property: styles * {Object} Storage of style objects * */ styles: null, /** * Property: styleBaseUrl * {String} */ styleBaseUrl: "", /** * Property: fetched * {Object} Storage of KML URLs that have been fetched before * in order to prevent reloading them. */ fetched: null, /** * APIProperty: maxDepth * {Integer} Maximum depth for recursive loading external KML URLs * Defaults to 0: do no external fetching */ maxDepth: 0, /** * Constructor: OpenLayers.Format.KML * Create a new parser for KML. * * Parameters: * options - {Object} An optional object whose properties will be set on * this instance. */ initialize: function(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), kmlColor: (/(\w{2})(\w{2})(\w{2})(\w{2})/), kmlIconPalette: (/root:\/\/icons\/palette-(\d+)(\.\w+)/), straightBracket: (/\$\[(.*?)\]/g) }; // KML coordinates are always in longlat WGS84 this.externalProjection = new OpenLayers.Projection("EPSG:4326"); OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); }, /** * APIMethod: read * Read data from a string, and return a list of features. * * Parameters: * data - {String} or {DOMElement} data to read/parse. * * Returns: * {Array(<OpenLayers.Feature.Vector>)} List of features. */ read: function(data) { this.features = []; this.styles = {}; this.fetched = {}; // Set default options var options = { depth: 0, styleBaseUrl: this.styleBaseUrl }; return this.parseData(data, options); }, /** * Method: parseData * Read data from a string, and return a list of features. * * Parameters: * data - {String} or {DOMElement} data to read/parse. * options - {Object} Hash of options * * Returns: * {Array(<OpenLayers.Feature.Vector>)} List of features. */ parseData: function(data, options) { if(typeof data == "string") { data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); } // Loop throught the following node types in this order and // process the nodes found var types = ["Link", "NetworkLink", "Style", "StyleMap", "Placemark"]; for(var i=0, len=types.length; i<len; ++i) { var type = types[i]; var nodes = this.getElementsByTagNameNS(data, "*", type); // skip to next type if no nodes are found if(nodes.length == 0) { continue; } switch (type.toLowerCase()) { // Fetch external links case "link": case "networklink": this.parseLinks(nodes, options); break; // parse style information case "style": if (this.extractStyles) { this.parseStyles(nodes, options); } break; case "stylemap": if (this.extractStyles) { this.parseStyleMaps(nodes, options); } break; // parse features case "placemark": this.parseFeatures(nodes, options); break; } } return this.features; }, /** * Method: parseLinks * Finds URLs of linked KML documents and fetches them * * Parameters: * nodes - {Array} of {DOMElement} data to read/parse. * options - {Object} Hash of options * */ parseLinks: function(nodes, options) { // Fetch external links <NetworkLink> and <Link> // Don't do anything if we have reached our maximum depth for recursion if (options.depth >= this.maxDepth) { return false; } // increase depth var newOptions = OpenLayers.Util.extend({}, options); newOptions.depth++; for(var i=0, len=nodes.length; i<len; i++) { var href = this.parseProperty(nodes[i], "*", "href"); if(href && !this.fetched[href]) { this.fetched[href] = true; // prevent reloading the same urls var data = this.fetchLink(href); if (data) { this.parseData(data, newOptions); } } } }, /** * Method: fetchLink * Fetches a URL and returns the result * * Parameters: * href - {String} url to be fetched * */ fetchLink: function(href) { var request = OpenLayers.Request.GET({url: href, async: false}); if (request) { return request.responseText; } }, /** * Method: parseStyles * Looks for <Style> nodes in the data and parses them * Also parses <StyleMap> nodes, but only uses the 'normal' key * * Parameters: * nodes - {Array} of {DOMElement} data to read/parse. * options - {Object} Hash of options * */ parseStyles: function(nodes, options) { for(var i=0, len=nodes.length; i<len; i++) { var style = this.parseStyle(nodes[i]); if(style) { var styleName = (options.styleBaseUrl || "") + "#" + style.id; this.styles[styleName] = style; } } }, /** * Method: parseKmlColor * Parses a kml color (in 'aabbggrr' format) and returns the corresponding * color and opacity or null if the color is invalid. * * Parameters: * kmlColor - {String} a kml formated color * * Returns: * {Object} */ parseKmlColor: function(kmlColor) { var color = null; if (kmlColor) { var matches = kmlColor.match(this.regExes.kmlColor); if (matches) { color = { color: '#' + matches[4] + matches[3] + matches[2], opacity: parseInt(matches[1], 16) / 255 }; } } return color; }, /** * Method: parseStyle * Parses the children of a <Style> node and builds the style hash * accordingly * * Parameters: * node - {DOMElement} <Style> node * */ parseStyle: function(node) { var style = {}; var types = ["LineStyle", "PolyStyle", "IconStyle", "BalloonStyle", "LabelStyle"]; var type, nodeList, geometry, parser; for(var i=0, len=types.length; i<len; ++i) { type = types[i]; styleTypeNode = this.getElementsByTagNameNS(node, "*", type)[0]; if(!styleTypeNode) { continue; } // only deal with first geometry of this type switch (type.toLowerCase()) { case "linestyle": var kmlColor = this.parseProperty(styleTypeNode, "*", "color"); var color = this.parseKmlColor(kmlColor); if (color) { style["strokeColor"] = color.color; style["strokeOpacity"] = color.opacity; } var width = this.parseProperty(styleTypeNode, "*", "width"); if (width) { style["strokeWidth"] = width; } break; case "polystyle": var kmlColor = this.parseProperty(styleTypeNode, "*", "color"); var color = this.parseKmlColor(kmlColor); if (color) { style["fillOpacity"] = color.opacity; style["fillColor"] = color.color; } // Check if fill is disabled var fill = this.parseProperty(styleTypeNode, "*", "fill"); if (fill == "0") { style["fillColor"] = "none"; } // Check if outline is disabled var outline = this.parseProperty(styleTypeNode, "*", "outline"); if (outline == "0") { style["strokeWidth"] = "0"; } break; case "iconstyle": // set scale var scale = parseFloat(this.parseProperty(styleTypeNode, "*", "scale") || 1); // set default width and height of icon var width = 32 * scale; var height = 32 * scale; var iconNode = this.getElementsByTagNameNS(styleTypeNode, "*", "Icon")[0]; if (iconNode) { var href = this.parseProperty(iconNode, "*", "href"); if (href) { var w = this.parseProperty(iconNode, "*", "w"); var h = this.parseProperty(iconNode, "*", "h"); // Settings for Google specific icons that are 64x64 // We set the width and height to 64 and halve the // scale to prevent icons from being too big var google = "http://maps.google.com/mapfiles/kml"; if (OpenLayers.String.startsWith( href, google) && !w && !h) { w = 64; h = 64; scale = scale / 2; } // if only dimension is defined, make sure the // other one has the same value w = w || h; h = h || w; if (w) { width = parseInt(w) * scale; } if (h) { height = parseInt(h) * scale; } // support for internal icons // (/root://icons/palette-x.png) // x and y tell the position on the palette: // - in pixels // - starting from the left bottom // We translate that to a position in the list // and request the appropriate icon from the // google maps website var matches = href.match(this.regExes.kmlIconPalette); if (matches) { var palette = matches[1]; var file_extension = matches[2]; var x = this.parseProperty(iconNode, "*", "x"); var y = this.parseProperty(iconNode, "*", "y"); var posX = x ? x/32 : 0; var posY = y ? (7 - y/32) : 7; var pos = posY * 8 + posX; href = "http://maps.google.com/mapfiles/kml/pal" + palette + "/icon" + pos + file_extension; } style["graphicOpacity"] = 1; // fully opaque style["externalGraphic"] = href; } } // hotSpots define the offset for an Icon var hotSpotNode = this.getElementsByTagNameNS(styleTypeNode, "*", "hotSpot")[0]; if (hotSpotNode) { var x = parseFloat(hotSpotNode.getAttribute("x")); var y = parseFloat(hotSpotNode.getAttribute("y")); var xUnits = hotSpotNode.getAttribute("xunits"); if (xUnits == "pixels") { style["graphicXOffset"] = -x * scale; } else if (xUnits == "insetPixels") { style["graphicXOffset"] = -width + (x * scale); } else if (xUnits == "fraction") { style["graphicXOffset"] = -width * x; } var yUnits = hotSpotNode.getAttribute("yunits"); if (yUnits == "pixels") { style["graphicYOffset"] = -height + (y * scale) + 1; } else if (yUnits == "insetPixels") { style["graphicYOffset"] = -(y * scale) + 1; } else if (yUnits == "fraction") { style["graphicYOffset"] = -height * (1 - y) + 1; } } style["graphicWidth"] = width; style["graphicHeight"] = height; break; case "balloonstyle": var balloonStyle = OpenLayers.Util.getXmlNodeValue( styleTypeNode); if (balloonStyle) { style["balloonStyle"] = balloonStyle.replace( this.regExes.straightBracket, "${$1}"); } break; case "labelstyle": var kmlColor = this.parseProperty(styleTypeNode, "*", "color"); var color = this.parseKmlColor(kmlColor); if (color) { style["fontColor"] = color.color; style["fontOpacity"] = color.opacity; } break; default: } } // Some polygons have no line color, so we use the fillColor for that if (!style["strokeColor"] && style["fillColor"]) { style["strokeColor"] = style["fillColor"]; } var id = node.getAttribute("id"); if (id && style) { style.id = id; } return style; }, /** * Method: parseStyleMaps * Looks for <Style> nodes in the data and parses them * Also parses <StyleMap> nodes, but only uses the 'normal' key * * Parameters: * nodes - {Array} of {DOMElement} data to read/parse. * options - {Object} Hash of options * */ parseStyleMaps: function(nodes, options) { // Only the default or "normal" part of the StyleMap is processed now // To do the select or "highlight" bit, we'd need to change lots more for(var i=0, len=nodes.length; i<len; i++) { var node = nodes[i]; var pairs = this.getElementsByTagNameNS(node, "*", "Pair"); var id = node.getAttribute("id"); for (var j=0, jlen=pairs.length; j<jlen; j++) { var pair = pairs[j]; // Use the shortcut in the SLD format to quickly retrieve the // value of a node. Maybe it's good to have a method in // Format.XML to do this var key = this.parseProperty(pair, "*", "key"); var styleUrl = this.parseProperty(pair, "*", "styleUrl"); if (styleUrl && key == "normal") { this.styles[(options.styleBaseUrl || "") + "#" + id] = this.styles[(options.styleBaseUrl || "") + styleUrl]; } if (styleUrl && key == "highlight") { // TODO: implement the "select" part } } } }, /** * Method: parseFeatures * Loop through all Placemark nodes and parse them. * Will create a list of features * * Parameters: * nodes - {Array} of {DOMElement} data to read/parse. * options - {Object} Hash of options * */ parseFeatures: function(nodes, options) { var features = []; for(var i=0, len=nodes.length; i<len; i++) { var featureNode = nodes[i]; var feature = this.parseFeature.apply(this,[featureNode]) ; if(feature) { // Create reference to styleUrl if (this.extractStyles && feature.attributes && feature.attributes.styleUrl) { feature.style = this.getStyle(feature.attributes.styleUrl, options); } if (this.extractStyles) { // Make sure that <Style> nodes within a placemark are // processed as well var inlineStyleNode = this.getElementsByTagNameNS(featureNode, "*", "Style")[0]; if (inlineStyleNode) { var inlineStyle= this.parseStyle(inlineStyleNode); if (inlineStyle) { feature.style = OpenLayers.Util.extend( feature.style, inlineStyle ); } } } // check if gx:Track elements should be parsed if (this.extractTracks) { var tracks = this.getElementsByTagNameNS( featureNode, this.namespaces.gx, "Track" ); if (tracks && tracks.length > 0) { var track = tracks[0]; var container = { features: [], feature: feature }; this.readNode(track, container); if (container.features.length > 0) { features.push.apply(features, container.features); } } } else { // add feature to list of features features.push(feature); } } else { throw "Bad Placemark: " + i; } } // add new features to existing feature list this.features = this.features.concat(features); }, /** * Property: readers * Contains public functions, grouped by namespace prefix, that will * be applied when a namespaced node is found matching the function * name. The function will be applied in the scope of this parser * with two arguments: the node being read and a context object passed * from the parent. */ readers: { "kml": { "when": function(node, container) { container.whens.push(OpenLayers.Date.parse( this.getChildValue(node) )); }, "_trackPointAttribute": function(node, container) { var name = node.nodeName.split(":").pop(); container.attributes[name].push(this.getChildValue(node)); } }, "gx": { "Track": function(node, container) { var obj = { whens: [], points: [], angles: [] }; if (this.trackAttributes) { var name; obj.attributes = {}; for (var i=0, ii=this.trackAttributes.length; i<ii; ++i) { name = this.trackAttributes[i]; obj.attributes[name] = []; if (!(name in this.readers.kml)) { this.readers.kml[name] = this.readers.kml._trackPointAttribute; } } } this.readChildNodes(node, obj); if (obj.whens.length !== obj.points.length) { throw new Error("gx:Track with unequal number of when (" + obj.whens.length + ") and gx:coord (" + obj.points.length + ") elements."); } var hasAngles = obj.angles.length > 0; if (hasAngles && obj.whens.length !== obj.angles.length) { throw new Error("gx:Track with unequal number of when (" + obj.whens.length + ") and gx:angles (" + obj.angles.length + ") elements."); } var feature, point, angles; for (var i=0, ii=obj.whens.length; i<ii; ++i) { feature = container.feature.clone(); feature.fid = container.feature.fid || container.feature.id; point = obj.points[i]; feature.geometry = point; if ("z" in point) { feature.attributes.altitude = point.z; } if (this.internalProjection && this.externalProjection) { feature.geometry.transform( this.externalProjection, this.internalProjection ); } if (this.trackAttributes) { for (var j=0, jj=this.trackAttributes.length; j<jj; ++j) { feature.attributes[name] = obj.attributes[this.trackAttributes[j]][i]; } } feature.attributes.when = obj.whens[i]; feature.attributes.trackId = container.feature.id; if (hasAngles) { angles = obj.angles[i]; feature.attributes.heading = parseFloat(angles[0]); feature.attributes.tilt = parseFloat(angles[1]); feature.attributes.roll = parseFloat(angles[2]); } container.features.push(feature); } }, "coord": function(node, container) { var str = this.getChildValue(node); var coords = str.replace(this.regExes.trimSpace, "").split(/\s+/); var point = new OpenLayers.Geometry.Point(coords[0], coords[1]); if (coords.length > 2) { point.z = parseFloat(coords[2]); } container.points.push(point); }, "angles": function(node, container) { var str = this.getChildValue(node); var parts = str.replace(this.regExes.trimSpace, "").split(/\s+/); container.angles.push(parts); } } }, /** * 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, len=order.length; i<len; ++i) { type = order[i]; this.internalns = node.namespaceURI ? node.namespaceURI : this.kmlns; nodeList = this.getElementsByTagNameNS(node, this.internalns, 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]]); if (this.internalProjection && this.externalProjection) { geometry.transform(this.externalProjection, this.internalProjection); } } else { OpenLayers.Console.error(OpenLayers.i18n( "unsupportedGeometryType", {'geomType':type})); } // stop looking for different geometry types break; } } // construct feature (optionally with attributes) var attributes; if(this.extractAttributes) { attributes = this.parseAttributes(node); } var feature = new OpenLayers.Feature.Vector(geometry, attributes); var fid = node.getAttribute("id") || node.getAttribute("name"); if(fid != null) { feature.fid = fid; } return feature; }, /** * Method: getStyle * Retrieves a style from a style hash using styleUrl as the key * If the styleUrl doesn't exist yet, we try to fetch it * Internet * * Parameters: * styleUrl - {String} URL of style * options - {Object} Hash of options * * Returns: * {Object} - (reference to) Style hash */ getStyle: function(styleUrl, options) { var styleBaseUrl = OpenLayers.Util.removeTail(styleUrl); var newOptions = OpenLayers.Util.extend({}, options); newOptions.depth++; newOptions.styleBaseUrl = styleBaseUrl; // Fetch remote Style URLs (if not fetched before) if (!this.styles[styleUrl] && !OpenLayers.String.startsWith(styleUrl, "#") && newOptions.depth <= this.maxDepth && !this.fetched[styleBaseUrl] ) { var data = this.fetchLink(styleBaseUrl); if (data) { this.parseData(data, newOptions); } } // return requested style var style = OpenLayers.Util.extend({}, this.styles[styleUrl]); return style; }, /** * 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.internalns, "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; }, /** * 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.internalns, "coordinates"); var line = null; if(nodeList.length > 0) { var coordString = this.getChildValue(nodeList[0]); 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.internalns, "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, len=nodeList.length; i<len; ++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.Collection>} A geometry collection. */ multigeometry: function(node) { var child, parser; var parts = []; var children = node.childNodes; for(var i=0, len=children.length; i<len; ++i ) { child = children[i]; if(child.nodeType == 1) { var 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); } }, /** * Method: parseAttributes * * Parameters: * node - {DOMElement} * * Returns: * {Object} An attributes object. */ parseAttributes: function(node) { var attributes = {}; // Extended Data is parsed first. var edNodes = node.getElementsByTagName("ExtendedData"); if (edNodes.length) { attributes = this.parseExtendedData(edNodes[0]); } // assume attribute nodes are type 1 children with a type 3 or 4 child var child, grandchildren, grandchild; var children = node.childNodes; for(var i=0, len=children.length; i<len; ++i) { child = children[i]; if(child.nodeType == 1) { grandchildren = child.childNodes; if(grandchildren.length >= 1 && grandchildren.length <= 3) { var grandchild; switch (grandchildren.length) { case 1: grandchild = grandchildren[0]; break; case 2: var c1 = grandchildren[0]; var c2 = grandchildren[1]; grandchild = (c1.nodeType == 3 || c1.nodeType == 4) ? c1 : c2; break; case 3: default: grandchild = grandchildren[1]; break; } if(grandchild.nodeType == 3 || grandchild.nodeType == 4) { var name = (child.prefix) ? child.nodeName.split(":")[1] : child.nodeName; var value = OpenLayers.Util.getXmlNodeValue(grandchild); if (value) { value = value.replace(this.regExes.trimSpace, ""); attributes[name] = value; } } } } } return attributes; }, /** * Method: parseExtendedData * Parse ExtendedData from KML. Limited support for schemas/datatypes. * See http://code.google.com/apis/kml/documentation/kmlreference.html#extendeddata * for more information on extendeddata. */ parseExtendedData: function(node) { var attributes = {}; var i, len, data, key; var dataNodes = node.getElementsByTagName("Data"); for (i = 0, len = dataNodes.length; i < len; i++) { data = dataNodes[i]; key = data.getAttribute("name"); var ed = {}; var valueNode = data.getElementsByTagName("value"); if (valueNode.length) { ed['value'] = this.getChildValue(valueNode[0]); } var nameNode = data.getElementsByTagName("displayName"); if (nameNode.length) { ed['displayName'] = this.getChildValue(nameNode[0]); } attributes[key] = ed; } var simpleDataNodes = node.getElementsByTagName("SimpleData"); for (i = 0, len = simpleDataNodes.length; i < len; i++) { var ed = {}; data = simpleDataNodes[i]; key = data.getAttribute("name"); ed['value'] = this.getChildValue(data); ed['displayName'] = key; attributes[key] = ed; } return attributes; }, /** * Method: parseProperty * Convenience method to find a node and return its value * * Parameters: * xmlNode - {<DOMElement>} * namespace - {String} namespace of the node to find * tagName - {String} name of the property to parse * * Returns: * {String} The value for the requested property (defaults to null) */ parseProperty: function(xmlNode, namespace, tagName) { var value; var nodeList = this.getElementsByTagNameNS(xmlNode, namespace, tagName); try { value = OpenLayers.Util.getXmlNodeValue(nodeList[0]); } catch(e) { value = null; } return value; }, /** * APIMethod: write * Accept Feature Collection, and return a string. * * Parameters: * features - {Array(<OpenLayers.Feature.Vector>} An array of 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, len=features.length; i<len; ++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 var folder = this.createElementNS(this.kmlns, "Folder"); // Folder name if (this.foldersName) { var folderName = this.createElementNS(this.kmlns, "name"); var folderNameText = this.createTextNode(this.foldersName); folderName.appendChild(folderNameText); folder.appendChild(folderName); } // Folder description if (this.foldersDesc) { var folderDesc = this.createElementNS(this.kmlns, "description"); var folderDescText = this.createTextNode(this.foldersDesc); folderDesc.appendChild(folderDescText); folder.appendChild(folderDesc); } return folder; }, /** * Method: createPlacemarkXML * Creates and returns a KML placemark node representing the given feature. * * Parameters: * feature - {<OpenLayers.Feature.Vector>} * * Returns: * {DOMElement} */ createPlacemarkXML: function(feature) { // Placemark name var placemarkName = this.createElementNS(this.kmlns, "name"); var name = feature.style && feature.style.label ? feature.style.label : feature.attributes.name || feature.id; placemarkName.appendChild(this.createTextNode(name)); // Placemark description var placemarkDesc = this.createElementNS(this.kmlns, "description"); var desc = feature.attributes.description || this.placemarksDesc; placemarkDesc.appendChild(this.createTextNode(desc)); // 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); // 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) { if (this.internalProjection && this.externalProjection) { geometry = geometry.clone(); geometry.transform(this.internalProjection, this.externalProjection); } 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; }, /** * 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.apply(this, [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; }, /** * 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.apply(this, [geometry]); }, /** * 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, len=rings.length; i<len; ++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; }, /** * 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.apply(this, [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, len=geometry.components.length; i<len; ++i) { child = this.buildGeometryNode.apply(this, [geometry.components[i]]); if(child) { kml.appendChild(child); } } return kml; } }, /** * 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" }); |
:: Command execute :: | |
--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0156 ]-- |