Adding readers and writers properties to xml formats. These will contain public functions used in serializing and deserializing various formats. Shorthand methods for calling these readers & writers are writeNode and readNode. r=ahocever (closes #1722)

git-svn-id: http://svn.openlayers.org/trunk/openlayers@7982 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
Tim Schaub
2008-09-08 21:31:39 +00:00
parent 8114c092b7
commit a5687716b7
4 changed files with 630 additions and 2 deletions

View File

@@ -19,6 +19,37 @@
*/
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.
*/
namespaces: {},
/**
* Property: defaultNamespace
* {String} The default namespace alias for creating element nodes.
*/
defaultNamespace: 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
@@ -45,6 +76,15 @@ OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
}
OpenLayers.Format.prototype.initialize.apply(this, [options]);
},
/**
* APIMethod: destroy
* Clean up.
*/
destroy: function() {
this.xmldom = null;
OpenLayers.Format.prototype.destroy.apply(this, arguments);
},
/**
* APIMethod: read
@@ -384,6 +424,196 @@ OpenLayers.Format.XML = OpenLayers.Class(OpenLayers.Format, {
}
},
/**
* Method: getNamespacePrefix
* Get the namespace prefix for a given uri from the <namespaces> object.
*
* Returns:
* {String} A namespace prefix or null if none found.
*/
getNamespacePrefix: function(uri) {
var prefix = null;
if(uri == null) {
prefix = this.defaultPrefix;
} else {
var prefix = null;
for(var p in this.namespaces) {
if(this.namespaces[p] == uri) {
prefix = p;
break;
}
}
}
return prefix;
},
/**
* Method: createElementNSPlus
* Shorthand for creating namespaced elements with optional attributes and
* child text nodes.
*
* Parameters:
* name - {String} The qualified node name.
* options - {Object} Optional object for node configuration.
*
* Valid options:
* uri - {String} Optional namespace uri for the element - supply a prefix
* instead if the namespace uri is a property of the format's namespace
* object.
* attributes - {Object} Optional attributes to be set using the
* <setAttributes> method.
* value - {String} Optional text to be appended as a text node.
*
* Returns:
* {Element} An element node.
*/
createElementNSPlus: function(name, options) {
options = options || {};
var loc = name.indexOf(":");
// order of prefix preference
// 1. in the uri option
// 2. in the prefix option
// 3. in the qualified name
// 4. from the defaultPrefix
var uri = options.uri || this.namespaces[options.prefix];
if(!uri) {
loc = name.indexOf(":");
uri = this.namespaces[name.substring(0, loc)];
}
if(!uri) {
uri = this.namespaces[this.defaultPrefix];
}
var node = this.createElementNS(uri, name);
if(options.attributes) {
this.setAttributes(node, options.attributes);
}
if(options.value) {
node.appendChild(this.createTextNode(options.value));
}
return node;
},
/**
* Method: setAttributes
* Set multiple attributes given key value pairs from an object.
*
* Parameters:
* node - {Element} An element node.
* obj - {Object || Array} An object whose properties represent attribute
* names and values represent attribute values. If an attribute name
* is a qualified name ("prefix:local"), the prefix will be looked up
* in the parsers {namespaces} object. If the prefix is found,
* setAttributeNS will be used instead of setAttribute.
*/
setAttributes: function(node, obj) {
var value, loc, alias, uri;
for(var name in obj) {
if(obj[name] != null && obj[name].toString) {
value = obj[name].toString();
// check for qualified attribute name ("prefix:local")
uri = this.namespaces[name.substring(0, name.indexOf(":"))] || null;
this.setAttributeNS(node, uri, name, value);
}
}
},
/**
* Method: readNode
* Shorthand for applying one of the named readers given the node
* namespace and local name. Readers take two args (node, obj) and
* generally extend or modify the second.
*
* Parameters:
* node - {DOMElement} The node to be read (required).
* obj - {Object} The object to be modified (optional).
*
* Returns:
* {Object} The input object, modified (or a new one if none was provided).
*/
readNode: function(node, obj) {
if(!obj) {
obj = {};
}
var prefix = this.getNamespacePrefix(node.namespaceURI);
var local = node.nodeName.split(":").pop();
var group = this.readers[prefix];
if(group) {
var reader = group[local] || group["*"];
if(reader) {
reader.apply(this, [node, obj]);
}
}
return obj;
},
/**
* Method: readChildNodes
* Shorthand for applying the named readers to all children of a node.
* For each child of type 1 (element), <readSelf> is called.
*
* Parameters:
* node - {DOMElement} The node to be read (required).
* obj - {Object} The object to be modified (optional).
*
* Returns:
* {Object} The input object, modified.
*/
readChildNodes: function(node, obj) {
if(!obj) {
obj = {};
}
var children = node.childNodes;
var child;
for(var i=0; i<children.length; ++i) {
child = children[i];
if(child.nodeType == 1) {
this.readNode(child, obj);
}
}
return obj;
},
/**
* Method: writeNode
* Shorthand for applying one of the named writers and appending the
* results to a node. If a qualified name is not provided for the
* second argument (and a local name is used instead), the namespace
* of the parent node will be assumed.
*
* Parameters:
* name - {String} The name of a node to generate. If a qualified name
* (e.g. "pre:Name") is used, the namespace prefix is assumed to be
* in the <writers> group. If a local name is used (e.g. "Name") then
* the namespace of the parent is assumed. If a local name is used
* and no parent is supplied, then the default namespace is assumed.
* obj - {Object} Structure containing data for the writer.
* parent - {DOMElement} Result will be appended to this node. If no parent
* is supplied, the node will not be appended to anything.
*
* Returns:
* {DOMElement} The child node.
*/
writeNode: function(name, obj, parent) {
var prefix, local;
var split = name.indexOf(":");
if(split > 0) {
prefix = name.substring(0, split);
local = name.substring(split + 1);
} else {
if(parent) {
prefix = this.getNamespacePrefix(parent.namespaceURI);
} else {
prefix = this.defaultPrefix;
}
local = name;
}
var child = this.writers[prefix][local].apply(this, [obj]);
if(parent) {
parent.appendChild(child);
}
return child;
},
CLASS_NAME: "OpenLayers.Format.XML"
});