|
/* 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 |