More trip planner testing with colors
[busui.git] / labs / openlayers / lib / OpenLayers / Format / XML.js
blob:a/labs/openlayers/lib/OpenLayers/Format/XML.js -> blob:b/labs/openlayers/lib/OpenLayers/Format/XML.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.js
  */
   
  /**
  * Class: OpenLayers.Format.XML
  * Read and write XML. For cross-browser XML generation, use methods on an
  * instance of the XML format class instead of on <code>document<end>.
  * The DOM creation and traversing methods exposed here all mimic the
  * W3C XML DOM methods. Create a new parser with the
  * <OpenLayers.Format.XML> constructor.
  *
  * Inherits from:
  * - <OpenLayers.Format>
  */
  OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
   
  /**
  * Property: namespaces
  * {Object} Mapping of namespace aliases to namespace URIs. Properties
  * of this object should not be set individually. Read-only. All
  * XML subclasses should have their own namespaces object. Use
  * <setNamespace> to add or set a namespace alias after construction.
  */
  namespaces: null,
   
  /**
  * Property: namespaceAlias
  * {Object} Mapping of namespace URI to namespace alias. This object
  * is read-only. Use <setNamespace> to add or set a namespace alias.
  */
  namespaceAlias: null,
   
  /**
  * Property: defaultPrefix
  * {String} The default namespace alias for creating element nodes.
  */
  defaultPrefix: null,
   
  /**
  * 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: {},
   
  /**
  * Property: writers
  * As a compliment to the <readers> property, this structure contains public
  * writing functions grouped by namespace alias and named like the
  * node names they produce.
  */
  writers: {},
   
  /**
  * Property: xmldom
  * {XMLDom} If this browser uses ActiveX, this will be set to a XMLDOM
  * object. It is not intended to be a browser sniffing property.
  * Instead, the xmldom property is used instead of <code>document<end>
  * where namespaced node creation methods are not supported. In all
  * other browsers, this remains null.
  */
  xmldom: null,
   
  /**
  * Constructor: OpenLayers.Format.XML
  * Construct an XML parser. The parser is used to read and write XML.
  * Reading XML from a string returns a DOM element. Writing XML from
  * a DOM element returns a string.
  *
  * Parameters:
  * options - {Object} Optional object whose properties will be set on
  * the object.
  */
  initialize: function(options) {
  if(window.ActiveXObject) {
  this.xmldom = new ActiveXObject("Microsoft.XMLDOM");
  }
  OpenLayers.Format.prototype.initialize.apply(this, [options]);
  // clone the namespace object and set all namespace aliases
  this.namespaces = OpenLayers.Util.extend({}, this.namespaces);
  this.namespaceAlias = {};
  for(var alias in this.namespaces) {
  this.namespaceAlias[this.namespaces[alias]] = alias;
  }
  },
   
  /**
  * APIMethod: destroy
  * Clean up.
  */
  destroy: function() {
  this.xmldom = null;
  OpenLayers.Format.prototype.destroy.apply(this, arguments);
  },
   
  /**
  * Method: setNamespace
  * Set a namespace alias and URI for the format.
  *
  * Parameters:
  * alias - {String} The namespace alias (prefix).
  * uri - {String} The namespace URI.
  */
  setNamespace: function(alias, uri) {
  this.namespaces[alias] = uri;
  this.namespaceAlias[uri] = alias;
  },
   
  /**
  * APIMethod: read
  * Deserialize a XML string and return a DOM node.
  *
  * Parameters:
  * text - {String} A XML string
   
  * Returns:
  * {DOMElement} A DOM node
  */
  read: function(text) {
  var index = text.indexOf('<');
  if(index > 0) {
  text = text.substring(index);
  }
  var node = OpenLayers.Util.Try(
  OpenLayers.Function.bind((
  function() {
  var xmldom;
  /**
  * Since we want to be able to call this method on the prototype
  * itself, this.xmldom may not exist even if in IE.
  */
  if(window.ActiveXObject && !this.xmldom) {
  xmldom = new ActiveXObject("Microsoft.XMLDOM");
  } else {
  xmldom = this.xmldom;
   
  }
  xmldom.loadXML(text);
  return xmldom;
  }
  ), this),
  function() {
  return new DOMParser().parseFromString(text, 'text/xml');
  },
  function() {
  var req = new XMLHttpRequest();
  req.open("GET", "data:" + "text/xml" +
  ";charset=utf-8," + encodeURIComponent(text), false);
  if(req.overrideMimeType) {
  req.overrideMimeType("text/xml");
  }
  req.send(null);
  return req.responseXML;
  }
  );
   
  if(this.keepData) {
  this.data = node;
  }
   
  return node;
  },
   
  /**
  * APIMethod: write
  * Serialize a DOM node into a XML string.
  *
  * Parameters:
  * node - {DOMElement} A DOM node.
  *
  * Returns:
  * {String} The XML string representation of the input node.
  */
  write: function(node) {
  var data;
  if(this.xmldom) {
  data = node.xml;
  } else {
  var serializer = new XMLSerializer();
  if (node.nodeType == 1) {
  // Add nodes to a document before serializing. Everything else
  // is serialized as is. This may need more work. See #1218 .
  var doc = document.implementation.createDocument("", "", null);
  if (doc.importNode) {
  node = doc.importNode(node, true);
  }
  doc.appendChild(node);
  data = serializer.serializeToString(doc);
  } else {
  data = serializer.serializeToString(node);
  }
  }
  return data;
  },
   
  /**
  * APIMethod: createElementNS
  * Create a new element with namespace. This node can be appended to
  * another node with the standard node.appendChild method. For
  * cross-browser support, this method must be used instead of
  * document.createElementNS.
  *
  * Parameters:
  * uri - {String} Namespace URI for the element.
  * name - {String} The qualified name of the element (prefix:localname).
  *
  * Returns:
  * {Element} A DOM element with namespace.
  */
  createElementNS: function(uri, name) {
  var element;
  if(this.xmldom) {
  if(typeof uri == "string") {
  element = this.xmldom.createNode(1, name, uri);
  } else {
  element = this.xmldom.createNode(1, name, "");
  }
  } else {
  element = document.createElementNS(uri, name);
  }
  return element;
  },
   
  /**
  * APIMethod: createTextNode
  * Create a text node. This node can be appended to another node with
  * the standard node.appendChild method. For cross-browser support,
  * this method must be used instead of document.createTextNode.
  *
  * Parameters:
  * text - {String} The text of the node.
  *
  * Returns:
  * {DOMElement} A DOM text node.
  */
  createTextNode: function(text) {
  var node;
  if (typeof text !== "string") {
  text = String(text);
  }
  if(this.xmldom) {
  node = this.xmldom.createTextNode(text);
  } else {
  node = document.createTextNode(text);
  }
  return node;
  },
   
  /**
  * APIMethod: getElementsByTagNameNS
  * Get a list of elements on a node given the namespace URI and local name.
  * To return all nodes in a given namespace, use '*' for the name
  * argument. To return all nodes of a given (local) name, regardless
  * of namespace, use '*' for the uri argument.
  *
  * Parameters:
  * node - {Element} Node on which to search for other nodes.
  * uri - {String} Namespace URI.
  * name - {String} Local name of the tag (without the prefix).
  *
  * Returns:
  * {NodeList} A node list or array of elements.
  */
  getElementsByTagNameNS: function(node, uri, name) {
  var elements = [];
  if(node.getElementsByTagNameNS) {
  elements = node.getElementsByTagNameNS(uri, name);
  } else {
  // brute force method
  var allNodes = node.getElementsByTagName("*");
  var potentialNode, fullName;
  for(var i=0, len=allNodes.length; i<len; ++i) {
  potentialNode = allNodes[i];
  fullName = (potentialNode.prefix) ?
  (potentialNode.prefix + ":" + name) : name;
  if((name == "*") || (fullName == potentialNode.nodeName)) {
  if((uri == "*") || (uri == potentialNode.namespaceURI)) {
  elements.push(potentialNode);
  }
  }
  }
  }
  return elements;
  },
   
  /**
  * APIMethod: getAttributeNodeNS
  * Get an attribute node given the namespace URI and local name.
  *
  * Parameters:
  * node - {Element} Node on which to search for attribute nodes.
  * uri - {String} Namespace URI.
  * name - {String} Local name of the attribute (without the prefix).
  *
  * Returns:
  * {DOMElement} An attribute node or null if none found.
  */
  getAttributeNodeNS: function(node, uri, name) {
  var attributeNode = null;
  if(node.getAttributeNodeNS) {
  attributeNode = node.getAttributeNodeNS(uri, name);
  } else {
  var attributes = node.attributes;
  var potentialNode, fullName;
  for(var i=0, len=attributes.length; i<len; ++i) {
  potentialNode = attributes[i];
  if(potentialNode.namespaceURI == uri) {
  fullName = (potentialNode.prefix) ?
  (potentialNode.prefix + ":" + name) : name;
  if(fullName == potentialNode.nodeName) {
  attributeNode = potentialNode;
  break;
  }
  }
  }
  }
  return attributeNode;
  },
   
  /**
  * APIMethod: getAttributeNS
  * Get an attribute value given the namespace URI and local name.
  *
  * Parameters:
  * node - {Element} Node on which to search for an attribute.
  * uri - {String} Namespace URI.
  * name - {String} Local name of the attribute (without the prefix).
  *
  * Returns:
  * {String} An attribute value or and empty string if none found.
  */
  getAttributeNS: function(node, uri, name) {
  var attributeValue = "";
  if(node.getAttributeNS) {
  attributeValue = node.getAttributeNS(uri, name) || "";
  } else {
  var attributeNode = this.getAttributeNodeNS(node, uri, name);
  if(attributeNode) {
  attributeValue = attributeNode.nodeValue;
  }
  }
  return attributeValue;
  },
   
  /**
  * APIMethod: getChildValue
  * Get the textual value of the node if it exists, or return an
  * optional default string. Returns an empty string if no first child
  * exists and no default value is supplied.
  *
  * Parameters:
  * node - {DOMElement} The element used to look for a first child value.
  * def - {String} Optional string to return in the event that no
  * first child value exists.
  *
  * Returns:
  * {String} The value of the first child of the given node.
  */
  getChildValue: function(node, def) {
  var value = def || "";
  if(node) {
  for(var child=node.firstChild; child; child=child.nextSibling) {
  switch(child.nodeType) {
  case 3: // tex