#841 - cross-browser XML DOM methods for creation, traversal, reading, and writing - see the xml.html example for use

git-svn-id: http://svn.openlayers.org/trunk/openlayers@3862 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
Tim Schaub
2007-08-05 15:55:02 +00:00
parent e3490e7aba
commit 04f1fe5385
6 changed files with 626 additions and 0 deletions

145
examples/xml.html Normal file
View File

@@ -0,0 +1,145 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>XML Parsing Example</title>
<style type="text/css">
body {
margin: 0 2em;
font-family: sans-serif;
}
#output {
font-family: monospace;
background-color: #efefef;
font-size: 0.9em;
padding: 1em;
}
span.code {
font-family: monospace;
background-color: #efefef;
font-size: 0.9em;
padding: 0.25em;
line-height: 1.5em;
}
ul {
margin: 0;
padding: 0 0 1em 1.5em;
}
ul li {
padding-left: 0;
}
</style>
<script src="../lib/Firebug/firebug.js" type="text/javascript"></script>
<script src="../lib/OpenLayers.js" type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
var format = new OpenLayers.Format.XML();
var doc = null;
function init() {
var url = "xml/features.xml";
OpenLayers.loadURL(url, null, null, loadSuccess, loadFailure);
}
function loadSuccess(request) {
updateStatus("loaded");
if(!request.responseXML.documentElement) {
doc = format.read(request.responseText);
} else {
doc = request.responseXML;
}
}
function loadFailure(request) {
updateStatus("failed to load");
}
function updateStatus(msg) {
document.getElementById("loadStatus").firstChild.nodeValue = msg;
}
function updateOutput(text) {
document.getElementById("output").firstChild.nodeValue = text;
}
function write() {
var text = format.write(doc);
updateOutput(text);
}
function getElementsByTagNameNS(node, uri, name) {
var nodes = format.getElementsByTagNameNS(node, uri, name);
var pieces = [];
for(var i=0; i<nodes.length; ++i) {
pieces.push(format.write(nodes[i]));
}
updateOutput(pieces.join(' '));
}
function hasAttributeNS(node, uri, name) {
updateOutput(format.hasAttributeNS(node, uri, name))
}
function getAttributeNodeNS(node, uri, name) {
var attributeNode = format.getAttributeNodeNS(node, uri, name);
updateOutput(attributeNode.nodeName + ' = "' +
attributeNode.nodeValue + '"');
}
function getAttributeNS(node, uri, name) {
var attributeValue = format.getAttributeNS(node, uri, name);
updateOutput('"' + attributeValue + '"')
}
function createElementNS(uri, name) {
var node = format.createElementNS(uri, name);
doc.documentElement.appendChild(node);
write();
}
function createTextNode(text) {
var node = format.createTextNode(text);
doc.documentElement.appendChild(node);
write();
}
window.onload = init;
//]]>
</script>
</head>
<body>
<h3>OpenLayers XML Example</h3>
<p>OpenLayers has a very simple XML format class (OpenLayers.Format.XML)
that can be used to read/write XML docs. The methods available on the
XML format (or parser if you like) allow for reading and writing of the
various XML flavors used by the library - in particular the vector data
formats. It is by no means intended to be a full-fledged XML toolset.
Additional methods will be added only as needed elsewhere in the
library.</p>
<p>This page loads an XML document and demonstrates a few of the methods
available in the parser.</p>
<p>Status: <b>XML document <span id="loadStatus">loading..</span>.</b></p>
<p>After the XML document loads, see the result of a few of the methods
below. Assume that you start with the following code:
<br />
<span class="code">
var format = new OpenLayers.Format.XML();
</span>
</p>
Sample methods
<ul>
<li><a href="javascript:void write();">format.write()</a> - write the XML doc as text</li>
<li><a href="javascript:void getElementsByTagNameNS(doc, 'http://www.opengis.net/gml', 'MultiPolygon');">format.getElementsByTagNameNS()</a> - get all gml:MultiPolygon</li>
<li><a href="javascript:void hasAttributeNS(doc.documentElement, 'http://www.w3.org/2001/XMLSchema-instance', 'schemaLocation');">format.hasAttributeNS()</a> - test to see schemaLocation attribute exists in the http://www.w3.org/2001/XMLSchema-instance namespace</li>
<li><a href="javascript:void getAttributeNodeNS(doc.documentElement, 'http://www.w3.org/2001/XMLSchema-instance', 'schemaLocation');">format.getAttributeNodeNS()</a> - get schemaLocation attribute in the http://www.w3.org/2001/XMLSchema-instance namespace</li>
<li><a href="javascript:void getAttributeNS(doc.documentElement, 'http://www.w3.org/2001/XMLSchema-instance', 'schemaLocation');">format.getAttributeNS()</a> - get schemaLocation attribute value in the http://www.w3.org/2001/XMLSchema-instance namespace</li>
<li><a href="javascript:void createElementNS('http://bar.com/foo', 'foo:TestNode');">format.createElementNS()</a> - create a foo:TestNode element (and append it to the doc)</li>
<li><a href="javascript:void createTextNode('test text ');">format.createTextNode()</a> - create a text node (and append it to the doc)</li>
</ul>
Output:
<div id="output">&nbsp;</div>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@@ -159,6 +159,7 @@
"OpenLayers/Layer/Vector.js",
"OpenLayers/Layer/GML.js",
"OpenLayers/Format.js",
"OpenLayers/Format/XML.js",
"OpenLayers/Format/GML.js",
"OpenLayers/Format/KML.js",
"OpenLayers/Format/GeoRSS.js",

View File

@@ -0,0 +1,283 @@
/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license.
* See http://svn.openlayers.org/trunk/openlayers/repository-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.create();
OpenLayers.Format.XML.prototype =
OpenLayers.Class.inherit(OpenLayers.Format, {
/**
* 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]);
},
/**
* 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(
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;
},
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;
}
);
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();
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) {
element = this.xmldom.createNode(1, name, uri);
} 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(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 {
var allNodes = node.getElementsByTagName("*");
var potentialNode, fullName;
for(var i=0; i<allNodes.length; ++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; i<attributes.length; ++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: hasAttributeNS
* Determine whether a node has a particular attribute matching the given
* name and namespace.
*
* 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:
* {Boolean} The node has an attribute matching the name and namespace.
*/
hasAttributeNS: function(node, uri, name) {
var found = false;
if(node.hasAttributeNS) {
found = node.hasAttributeNS(uri, name);
} else {
found = !!this.getAttributeNodeNS(node, uri, name);
}
return found;
},
CLASS_NAME: "OpenLayers.Format.XML"
});

194
tests/Format/test_XML.html Normal file
View File

@@ -0,0 +1,194 @@
<html>
<head>
<script src="../../lib/OpenLayers.js"></script>
<script type="text/javascript"><!--
var text =
'<?xml version="1.0"?>' +
'<ol:root xmlns="http://namespace.default.net" ' +
'xmlns:ol="http://namespace.openlayers.org" ' +
'xmlns:ta="http://namespace.testattribute.net">' +
'<ol:child ta:attribute="value1" ' +
'attribute="value2">' +
'junk1' +
'<' + '/ol:child>' +
'<ol:child>junk2<' + '/ol:child>' +
'<ol:child>junk3<' + '/ol:child>' +
'<element>junk4<' + '/element>' +
'<ol:element>junk5<' + '/ol:element>' +
'<' + '/ol:root>';
function test_Format_XML_constructor(t) {
t.plan(4);
var options = {'foo': 'bar'};
var format = new OpenLayers.Format.XML(options);
t.ok(format instanceof OpenLayers.Format.XML,
"new OpenLayers.Format.XML returns object" );
t.eq(format.foo, "bar", "constructor sets options correctly");
t.eq(typeof format.read, "function", "format has a read function");
t.eq(typeof format.write, "function", "format has a write function");
}
function test_Format_XML_read(t) {
t.plan(5);
var format = new OpenLayers.Format.XML();
var doc = format.read(text);
t.eq(doc.nodeType, 9,
"doc has the correct node type");
t.eq(doc.nodeName, "#document",
"doc has the correct node name");
t.ok(doc.documentElement,
"ok to access doc.documentElement");
t.eq(doc.documentElement.nodeName, "ol:root",
"doc root has the correct node name");
t.eq(doc.documentElement.childNodes[1].firstChild.nodeValue, "junk2",
"second child of doc root has correct child node");
}
function test_Format_XML_write(t) {
t.plan(1);
var format = new OpenLayers.Format.XML();
var doc = format.read(text);
var out = format.write(doc);
out = out.replace(/[\r\n]/g, '');
t.eq(text, out,
"correctly writes an XML DOM doc");
}
function test_Format_XML_createElementNS(t) {
t.plan(5);
var format = new OpenLayers.Format.XML();
var uri = "http://foo.com";
var prefix = "foo";
var localName = "bar";
var qualifiedName = prefix + ":" + name;
var node = format.createElementNS(uri, qualifiedName);
t.eq(node.nodeType, 1,
"node has correct type");
t.eq(node.nodeName, qualifiedName,
"node has correct qualified name");
t.eq(node.prefix, prefix,
"node has correct prefix");
t.eq(node.namespaceURI, uri,
"node has correct namespace uri");
var doc = format.read(text);
t.ok(doc.documentElement.appendChild(node),
"node can be appended to a doc root");
}
function test_Format_XML_createTextNode(t) {
t.plan(4);
var format = new OpenLayers.Format.XML();
var value = Math.random().toString();
var node = format.createTextNode(value);
t.eq(node.nodeType, 3,
"node has correct type");
t.eq(node.nodeName, "#text",
"node has correct name");
t.eq(node.nodeValue, value,
"node has correct value");
var doc = format.read(text);
t.ok(doc.documentElement.appendChild(node),
"node can be appended to a doc root");
}
function test_Format_XML_getElementsByTagNameNS(t) {
t.plan(3);
var format = new OpenLayers.Format.XML();
var olUri = "http://namespace.openlayers.org";
var name = "child";
var doc = format.read(text);
var nodes = format.getElementsByTagNameNS(doc.documentElement,
olUri, name);
t.eq(nodes.length, 3,
"gets correct number of nodes");
var qualifiedName = nodes[0].prefix + ":" + name;
t.eq(nodes[0].nodeName, qualifiedName,
"first node has correct qualified name");
var defaultUri = "http://namespace.default.net";
name = "element";
nodes = format.getElementsByTagNameNS(doc.documentElement,
defaultUri, name);
t.eq(nodes.length, 1,
"gets correct number of nodes in default namespace");
}
function test_Format_XML_getAttributeNodeNS(t) {
t.plan(5);
var format = new OpenLayers.Format.XML();
var doc = format.read(text);
var olUri = "http://namespace.openlayers.org";
var taUri = "http://namespace.testattribute.net";
var localNodeName = "child";
var localAttrName = "attribute";
var nodes = format.getElementsByTagNameNS(doc.documentElement,
olUri, localNodeName);
var attributeNode = format.getAttributeNodeNS(nodes[0],
taUri, localAttrName);
var qualifiedName = attributeNode.prefix + ":" + localAttrName;
t.ok(attributeNode,
"returns non-null value");
t.eq(attributeNode.nodeType, 2,
"attribute node has correct type");
t.eq(attributeNode.nodeName, qualifiedName,
"attribute node has correct qualified name");
t.eq(attributeNode.nodeValue, "value1",
"attribute node has correct value");
var nullAttribute = format.getAttributeNodeNS(nodes[0],
taUri, "nothing");
t.ok(nullAttribute === null,
"returns null for nonexistent attribute");
}
function test_Format_XML_getAttributeNS(t) {
t.plan(2);
var format = new OpenLayers.Format.XML();
var doc = format.read(text);
var olUri = "http://namespace.openlayers.org";
var taUri = "http://namespace.testattribute.net";
var localNodeName = "child";
var localAttrName = "attribute";
var nodes = format.getElementsByTagNameNS(doc.documentElement,
olUri, localNodeName);
var attributeValue = format.getAttributeNS(nodes[0],
taUri, localAttrName);
t.eq(attributeValue, "value1",
"got correct attribute value");
var emptyValue = format.getAttributeNS(nodes[0],
taUri, "nothing");
t.ok(emptyValue === "",
"returns empty string for nonexistent attributes");
}
function test_Format_XML_hasAttributeNS(t) {
t.plan(2);
var format = new OpenLayers.Format.XML();
var doc = format.read(text);
var olUri = "http://namespace.openlayers.org";
var taUri = "http://namespace.testattribute.net";
var localNodeName = "child";
var localAttrName = "attribute";
var nodes = format.getElementsByTagNameNS(doc.documentElement,
olUri, localNodeName);
var found = format.hasAttributeNS(nodes[0], taUri, localAttrName);
t.ok(found === true, "returns true for good attribute");
found = format.hasAttributeNS(nodes[0], taUri, "nothing");
t.ok(found === false, "returns false for bad attribute");
}
// -->
</script>
</head>
<body>
</body>
</html>

View File

@@ -20,6 +20,7 @@
<li>Geometry/test_Rectangle.html</li>
<li>Geometry/test_Surface.html</li>
<li>test_Format.html</li>
<li>Format/test_XML.html</li>
<li>Format/test_GeoRSS.html</li>
<li>Format/test_GML.html</li>
<li>Format/test_WKT.html</li>