More trip planner testing with colors
[busui.git] / labs / openlayers / lib / OpenLayers / Format / GML.js
blob:a/labs/openlayers/lib/OpenLayers/Format/GML.js -> blob:b/labs/openlayers/lib/OpenLayers/Format/GML.js
  /* 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/MultiPoint.js
  * @requires OpenLayers/Geometry/LineString.js
  * @requires OpenLayers/Geometry/MultiLineString.js
  * @requires OpenLayers/Geometry/Polygon.js
  * @requires OpenLayers/Geometry/MultiPolygon.js
  * @requires OpenLayers/Console.js
  */
   
  /**
  * Class: OpenLayers.Format.GML
  * Read/Wite GML. Create a new instance with the <OpenLayers.Format.GML>
  * constructor. Supports the GML simple features profile.
  *
  * Inherits from:
  * - <OpenLayers.Format>
  */
  OpenLayers.Format.GML = OpenLayers.Class(OpenLayers.Format.XML, {
   
  /*
  * APIProperty: featureNS
  * {String} Namespace used for feature attributes. Default is
  * "http://mapserver.gis.umn.edu/mapserver".
  */
  featureNS: "http://mapserver.gis.umn.edu/mapserver",
   
  /**
  * APIProperty: featurePrefix
  * {String} Namespace alias (or prefix) for feature nodes. Default is
  * "feature".
  */
  featurePrefix: "feature",
   
  /*
  * APIProperty: featureName
  * {String} Element name for features. Default is "featureMember".
  */
  featureName: "featureMember",
   
  /*
  * APIProperty: layerName
  * {String} Name of data layer. Default is "features".
  */
  layerName: "features",
   
  /**
  * APIProperty: geometryName
  * {String} Name of geometry element. Defaults to "geometry".
  */
  geometryName: "geometry",
   
  /**
  * APIProperty: collectionName
  * {String} Name of featureCollection element.
  */
  collectionName: "FeatureCollection",
   
  /**
  * APIProperty: gmlns
  * {String} GML Namespace.
  */
  gmlns: "http://www.opengis.net/gml",
   
  /**
  * APIProperty: extractAttributes
  * {Boolean} Extract attributes from GML.
  */
  extractAttributes: true,
   
  /**
  * APIProperty: xy
  * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
  * Changing is not recommended, a new Format should be instantiated.
  */
  xy: true,
   
  /**
  * Constructor: OpenLayers.Format.GML
  * Create a new parser for GML.
  *
  * 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)
  };
  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>)} An array of features.
  */
  read: function(data) {
  if(typeof data == "string") {
  data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
  }
  var featureNodes = this.getElementsByTagNameNS(data.documentElement,
  this.gmlns,
  this.featureName);
  var features = [];
  for(var i=0; i<featureNodes.length; i++) {
  var feature = this.parseFeature(featureNodes[i]);
  if(feature) {
  features.push(feature);
  }
  }
  return features;
  },
   
  /**
  * Method: parseFeature
  * This function is the core of the GML 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} A GML feature node.
  */
  parseFeature: function(node) {
  // only accept one geometry per feature - look for highest "order"
  var order = ["MultiPolygon", "Polygon",
  "MultiLineString", "LineString",
  "MultiPoint", "Point", "Envelope"];
  // FIXME: In case we parse a feature with no geometry, but boundedBy an Envelope,
  // this code creates a geometry derived from the Envelope. This is not correct.
  var type, nodeList, geometry, parser;
  for(var i=0; i<order.length; ++i) {
  type = order[i];
  nodeList = this.getElementsByTagNameNS(node, this.gmlns, type);
  if(nodeList.length > 0) {
  // only deal with first geometry of this type
  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;
  }
  }
   
  var bounds;
  var boxNodes = this.getElementsByTagNameNS(node, this.gmlns, "Box");
  for(i=0; i<boxNodes.length; ++i) {
  var boxNode = boxNodes[i];
  var box = this.parseGeometry["box"].apply(this, [boxNode]);
  var parentNode = boxNode.parentNode;
  var parentName = parentNode.localName ||
  parentNode.nodeName.split(":").pop();
  if(parentName === "boundedBy") {
  bounds = box;
  } else {
  geometry = box.toGeometry();
  }
  }
   
  // construct feature (optionally with attributes)
  var attributes;
  if(this.extractAttributes) {
  attributes = this.parseAttributes(node);
  }
  var feature = new OpenLayers.Feature.Vector(geometry, attributes);
  feature.bounds = bounds;
   
  feature.gml = {
  featureType: node.firstChild.nodeName.split(":")[1],
  featureNS: node.firstChild.namespaceURI,
  featureNSPrefix: node.firstChild.prefix
  };
   
  // assign fid - this can come from a "fid" or "id" attribute
  var childNode = node.firstChild;
  var fid;
  while(childNode) {
  if(childNode.nodeType == 1) {
  fid = childNode.getAttribute("fid") ||
  childNode.getAttribute("id");
  if(fid) {
  break;
  }
  }
  childNode = childNode.nextSibling;
  }
  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 GML node representing a point geometry, create an OpenLayers
  * point geometry.
  *
  * Parameters:
  * node - {DOMElement} A GML node.
  *
  * Returns:
  * {<OpenLayers.Geometry.Point>} A point geometry.
  */
  point: function(node) {
  /**
  * Three coordinate variations to consider:
  * 1) <gml:pos>x y z</gml:pos>
  * 2) <gml:coordinates>x, y, z</gml:coordinates>
  * 3) <gml:coord><gml:X>x</gml:X><gml:Y>y</gml:Y></gml:coord>
  */
  var nodeList, coordString;
  var coords = [];
   
  // look for <gml:pos>
  var nodeList = this.getElementsByTagNameNS(node, this.gmlns, "pos");
  if(nodeList.length > 0) {
  coordString = nodeList[0].firstChild.nodeValue;
  coordString = coordString.replace(this.regExes.trimSpace, "");
  coords = coordString.split(this.regExes.splitSpace);
  }
   
  // look for <gml:coordinates>
  if(coords.length == 0) {
  nodeList = this.getElementsByTagNameNS(node, this.gmlns,
  "coordinates");
  if(nodeList.length > 0) {
  coordString = nodeList[0].firstChild.nodeValue;
  coordString = coordString.replace(this.regExes.removeSpace,
  "");
  coords = coordString.split(",");
  }
  }
   
  // look for <gml:coord>
  if(coords.length == 0) {
  nodeList = this.getElementsByTagNameNS(node, this.gmlns,
  "coord");
  if(nodeList.length > 0) {
  var xList = this.getElementsByTagNameNS(nodeList[0],
  this.gmlns, "X");
  var yList = this.getElementsByTagNameNS(nodeList[0],
  this.gmlns, "Y");
  if(xList.length > 0 && yList.length > 0) {
  coords = [xList[0].firstChild.nodeValue,
  yList[0].firstChild.nodeValue];
  }
  }
  }
   
  // preserve third dimension
  if(coords.length == 2) {
  coords[2] = null;
  }
   
  if (this.xy) {
  return new OpenLayers.Geometry.Point(coords[0], coords[1],
  coords[2]);
  }
  else{
  return new OpenLayers.Geometry.Point(coords[1], coords[0],
  coords[2]);
  }
  },
   
  /**
  * Method: parseGeometry.multipoint
  * Given a GML node representing a multipoint geometry, create an
  * OpenLayers multipoint geometry.
  *
  * Parameters:
  * node - {DOMElement} A GML node.
  *
  * Returns:
  * {<OpenLayers.Geometry.MultiPoint>} A multipoint geometry.
  */
  multipoint: function(node) {
  var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
  "Point");
  var components = [];
  if(nodeList.length > 0) {
  var point;
  for(var i=0; i<nodeList.length; ++i) {
  point = this.parseGeometry.point.apply(this, [nodeList[i]]);
  if(point) {
  components.push(point);
  }
  }
  }
  return new OpenLayers.Geometry.MultiPoint(components);
  },
   
  /**
  * Method: parseGeometry.linestring
  * Given a GML node representing a linestring geometry, create an
  * OpenLayers linestring geometry.
  *
  * Parameters:
  * node - {DOMElement} A GML node.
  *
  * Returns:
  * {<OpenLayers.Geometry.LineString>} A linestring geometry.
  */
  linestring: function(node, ring) {
  /**
  * Two coordinate variations to consider:
  * 1) <gml:posList dimension="d">x0 y0 z0 x1 y1 z1</gml:posList>
  * 2) <gml:coordinates>x0, y0, z0 x1, y1, z1</gml:coordinates>
  */
  var nodeList, coordString;
  var coords = [];
  var points = [];
   
  // look for <gml:posList>
  nodeList = this.getElementsByTagNameNS(node, this.gmlns, "posList");
  if(nodeList.length > 0) {
  coordString = this.getChildValue(nodeList[0]);
  coordString = coordString.replace(this.regExes.trimSpace, "");
  coords = coordString.split(this.regExes.splitSpace);
  var dim = parseInt(nodeList[0].getAttribute("dimension"));
  var j, x, y, z;
  for(var i=0; i<coords.length/dim; ++i) {
  j = i * dim;
  x = coords[j];
  y = coords[j+1];
  z = (dim == 2) ? null : coords[j+2];
  if (this.xy) {
  points.push(new OpenLayers.Geometry.Point(x, y, z));
  } else {
  points.push(new OpenLayers.Geometry.Point(y, x, z));
  }
  }
  }
   
  // look for <gml:coordinates>
  if(coords.length == 0) {
  nodeList = this.getElementsByTagNameNS(node, this.gmlns,
 </