More trip planner testing with colors
[busui.git] / labs / openlayers / lib / OpenLayers / Format / OWSContext / v0_3_1.js
blob:a/labs/openlayers/lib/OpenLayers/Format/OWSContext/v0_3_1.js -> blob:b/labs/openlayers/lib/OpenLayers/Format/OWSContext/v0_3_1.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/Format/KML.js
  * @requires OpenLayers/Format/GML.js
  * @requires OpenLayers/Format/GML/v2.js
  * @requires OpenLayers/Format/SLD/v1_0_0.js
  * @requires OpenLayers/Format/OWSContext.js
  * @requires OpenLayers/Format/OWSCommon/v1_0_0.js
  */
   
  /**
  * Class: OpenLayers.Format.OWSContext.v0_3_1
  * Read and write OWSContext version 0.3.1.
  *
  * Inherits from:
  * - <OpenLayers.Format.XML>
  */
  OpenLayers.Format.OWSContext.v0_3_1 = OpenLayers.Class(OpenLayers.Format.XML, {
   
  /**
  * Property: namespaces
  * {Object} Mapping of namespace aliases to namespace URIs.
  */
  namespaces: {
  owc: "http://www.opengis.net/ows-context",
  gml: "http://www.opengis.net/gml",
  kml: "http://www.opengis.net/kml/2.2",
  ogc: "http://www.opengis.net/ogc",
  ows: "http://www.opengis.net/ows",
  sld: "http://www.opengis.net/sld",
  xlink: "http://www.w3.org/1999/xlink",
  xsi: "http://www.w3.org/2001/XMLSchema-instance"
  },
   
  /**
  * Constant: VERSION
  * {String} 0.3.1
  */
  VERSION: "0.3.1",
   
  /**
  * Property: schemaLocation
  * {String} Schema location
  */
  schemaLocation: "http://www.opengis.net/ows-context http://www.ogcnetwork.net/schemas/owc/0.3.1/owsContext.xsd",
   
  /**
  * Property: defaultPrefix
  * {String} Default namespace prefix to use.
  */
  defaultPrefix: "owc",
   
  /**
  * APIProperty: extractAttributes
  * {Boolean} Extract attributes from GML. Default is true.
  */
  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,
   
  /**
  * Property: regExes
  * Compiled regular expressions for manipulating strings.
  */
  regExes: {
  trimSpace: (/^\s*|\s*$/g),
  removeSpace: (/\s*/g),
  splitSpace: (/\s+/),
  trimComma: (/\s*,\s*/g)
  },
   
  /**
  * Property: featureNS
  * {String} The namespace uri to use for writing InlineGeometry
  */
  featureNS: "http://mapserver.gis.umn.edu/mapserver",
   
  /**
  * Property: featureType
  * {String} The name to use as the feature type when writing out
  * InlineGeometry
  */
  featureType: 'vector',
   
  /**
  * Property: geometryName
  * {String} The name to use for the geometry attribute when writing out
  * InlineGeometry
  */
  geometryName: 'geometry',
   
  /**
  * Property: nestingLayerLookup
  * {Object} Hashtable lookup for nesting layer nodes. Used while writing
  * the OWS context document. It is necessary to keep track of the
  * nestingPaths for which nesting layer nodes have already been
  * created, so (nesting) layer nodes are added to those nodes.
  *
  * For example:
  *
  * If there are three layers with nestingPaths:
  * layer1.metadata.nestingPath = "a/b/"
  * layer2.metadata.nestingPath = "a/b/"
  * layer2.metadata.nestingPath = "a/c"
  *
  * then a nesting layer node "a" should be created once and added
  * to the resource list, a nesting layer node "b" should be created
  * once and added under "a", and a nesting layer node "c" should be
  * created and added under "a". The lookup paths for these nodes
  * will be "a", "a/b", and "a/c" respectively.
  */
  nestingLayerLookup: null,
   
  /**
  * Constructor: OpenLayers.Format.OWSContext.v0_3_1
  * Instances of this class are not created directly. Use the
  * <OpenLayers.Format.OWSContext> constructor instead.
  *
  * Parameters:
  * options - {Object} An optional object whose properties will be set on
  * this instance.
  */
  initialize: function(options) {
  OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
  OpenLayers.Format.GML.v2.prototype.setGeometryTypes.call(this);
  },
   
  /**
  * Method: setNestingPath
  * Set the nestingPath property of the layer depending on the position
  * of the layer in hierarchy of layers.
  *
  * Parameters:
  * l - {Object} An object that may have a layersContext array property.
  *
  */
  setNestingPath : function(l){
  if(l.layersContext){
  for (var i = 0, len = l.layersContext.length; i < len; i++) {
  var layerContext = l.layersContext[i];
  var nPath = [];
  var nTitle = l.title || "";
  if(l.metadata && l.metadata.nestingPath){
  nPath = l.metadata.nestingPath.slice();
  }
  if (nTitle != "") {
  nPath.push(nTitle);
  }
  layerContext.metadata.nestingPath = nPath;
  if(layerContext.layersContext){
  this.setNestingPath(layerContext);
  }
  }
  }
  },
   
  /**
  * Function: decomposeNestingPath
  * Takes a nestingPath like "a/b/c" and decomposes it into subpaths:
  * "a", "a/b", "a/b/c"
  *
  * Parameters:
  * nPath - {Array} the nesting path
  *
  * Returns:
  * Array({String}) Array with subpaths, or empty array if there is nothing
  * to decompose
  */
  decomposeNestingPath: function(nPath){
  var a = [];
  if (nPath instanceof Array) {
  while (nPath.length > 0) {
  a.push(nPath.slice());
  nPath.pop();
  }
  a.reverse();
  }
  return a;
  },
   
  /**
  * APIMethod: read
  * Read OWS context data from a string or DOMElement, and return a list
  * of layers.
  *
  * Parameters:
  * data - {String} or {DOMElement} data to read/parse.
  *
  * Returns:
  * {Object} The context object with a flat layer list as a property named
  * layersContext.
  */
  read: function(data) {
  if(typeof data == "string") {
  data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
  }
  if(data && data.nodeType == 9) {
  data = data.documentElement;
  }
  var context = {};
  this.readNode(data, context);
  // since an OWSContext can be nested we need to go through this
  // structure recursively
  this.setNestingPath({layersContext : context.layersContext});
  // after nesting path has been set, create a flat list of layers
  var layers = [];
  this.processLayer(layers, context);
  delete context.layersContext;
  context.layersContext = layers;
  return context;
  },
   
  /**
  * Method: processLayer
  * Recursive function to get back a flat list of layers from the hierarchic
  * layer structure.
  *
  * Parameters:
  * layerArray - {Array({Object})} Array of layerContext objects
  * layerContext - {Object} layerContext object
  */
  processLayer: function(layerArray, layer) {
  if (layer.layersContext) {
  for (var i=0, len = layer.layersContext.length; i<len; i++) {
  var l = layer.layersContext[i];
  layerArray.push(l);
  if (l.layersContext) {
  this.processLayer(layerArray, l);
  }
  }
  }
  },
   
  /**
  * APIMethod: write
  *
  * Parameters:
  * context - {Object} An object representing the map context.
  * options - {Object} Optional object.
  *
  * Returns:
  * {String} An OWS Context document string.
  */
  write: function(context, options) {
  var name = "OWSContext";
  this.nestingLayerLookup = {}; //start with empty lookup
  options = options || {};
  OpenLayers.Util.applyDefaults(options, context);
  var root = this.writeNode(name, options);
  this.nestingLayerLookup = null; //clear lookup
  this.setAttributeNS(
  root, this.namespaces["xsi"],
  "xsi:schemaLocation", this.schemaLocation
  );
  return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
  },
   
  /**
  * 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": {
  "Document": function(node, obj) {
  obj.features = new OpenLayers.Format.KML(
  {kmlns: this.namespaces.kml,
  extractStyles: true}).read(node);
  }
  },
  "owc": {
  "OWSContext": function(node, obj) {
  this.readChildNodes(node, obj);
  },
  "General": function(node, obj) {
  this.readChildNodes(node, obj);
  },
  "ResourceList": function(node, obj) {
  this.readChildNodes(node, obj);
  },
  "Layer": function(node, obj) {
  var layerContext = {
  metadata: {},
  visibility: (node.getAttribute("hidden") != "1"),
  queryable: (node.getAttribute("queryable") == "1"),
  opacity: ((node.getAttribute("opacity") != null) ?
  parseFloat(node.getAttribute("opacity")) : null),
  name: node.getAttribute("name"),
  /* A category layer is a dummy layer meant for creating
  hierarchies. It is not a physical layer in the
  OpenLayers sense. The assumption we make here is that
  category layers do not have a name attribute */
  categoryLayer: (node.getAttribute("name") == null),
  formats: [],
  styles: []
  };
  if (!obj.layersContext) {
  obj.layersContext = [];
  }
  obj.layersContext.push(layerContext);
  this.readChildNodes(node, layerContext);
  },
  "InlineGeometry": function(node, obj) {
  obj.features = [];
  var elements = this.getElementsByTagNameNS(node,
  this.namespaces.gml, "featureMember");
  var el;
  if (elements.length >= 1) {
  el = elements[0];
  }
  if (el && el.firstChild) {
  var featurenode = (el.firstChild.nextSibling) ?
  el.firstChild.nextSibling : el.firstChild;
  this.setNamespace("feature", featurenode.namespaceURI);
  this.featureType = featurenode.localName ||
  featurenode.nodeName.split(":").pop();
  this.readChildNodes(node, obj);
  }
  },
  "Server": function(node, obj) {
  // when having multiple Server types, we prefer WMS
  if ((!obj.service && !obj.version) ||
  (obj.service !=
  OpenLayers.Format.Context.serviceTypes.WMS)) {
  obj.service = node.getAttribute("service");
  obj.version = node.getAttribute("version");
  this.readChildNodes(node, obj);
  }
  },
  "Name": function(node, obj) {
  obj.name = this.getChildValue(node);
  this.readChildNodes(node, obj);
  },
  "Title": function(node, obj) {
  obj.title = this.getChildValue(node);
  this.readChildNodes(node, obj);
  },
  "StyleList": function(node, obj) {
  this.readChildNodes(node, obj.styles);
  },
  "Style": function(node, obj) {
  var style = {};
  obj.push(style);
  this.readChildNodes(node, style);
  },
  "LegendURL": function(node, obj) {
  var legend = {};
  obj.legend = legend;
  this.readChildNodes(node, legend);
  },
  "OnlineResource": function(node, obj) {
  obj.url = this.getAttributeNS(node, this.namespaces.xlink,