skip to main |
skip to sidebar
RSS Feeds
ASP.NET, JavaScript, Oracle and SQL articles and code.
ASP.NET, JavaScript, Oracle and SQL articles and code.
9:51 AM
Posted by Michael Heliso
Here is a small library/wrapper for JavaScript XML. Some parts of it belong to other authors like the Opera serialization and the loading of the XML document from a string. I had to do a lot of work on the part related to namespaces, especially on Opera. At this time, the library doesn’t work under Chrome if the XML document makes use of namespaces. So you will not be able to create XPath expression for namespace-d XML documents under Chrome browser. You will notice that the library exposes two layers, first of them is an abstraction of the native DOM and of all its functionality and the second one is the native DOM its self. I have used this library for different XML related tasks; the most important one in my case is the SOAP library and the .NET DataSet serialization to JavaScript data objects. I’m too lazy to explain it in details, but if you have questions feel free to ask them and I’ll give you an answer as fast as possible. You can download the source from HERE
if (typeof (MG) == 'undefined') throw ("MG.Core.js is required!"); if(typeof(MG.Collections) === 'undefined') throw ("MG.Collections.js is required!"); if (typeof (MG.Xml) == 'undefined') MG.Xml = {}; MG.Xml.XmlDocument = function(rootTagName, namespaceURL) { if(document.implementation && document.implementation.createDocument) { Document.prototype.loadXML = function(strXML) { var domParser = new DOMParser(); var xmlDoc = domParser.parseFromString(strXML, "text/xml"); while(this.hasChildNodes()) this.removeChild(this.lastChild); for(var index = 0; index < xmlDoc.childNodes.length; index++) { var impNode = this.importNode(xmlDoc.childNodes[index], true); this.appendChild(impNode); } var nsResolvers = new MG.Collections.Dictionary(); if(xmlDoc.childNodes.length > 0) { nsResolvers = fixNS(strXML); } function fixNS(xml) { var regEx = /<[a-z\dA-Z\d]+:/g; var results = xml.match(regEx); var prefixes = new MG.Collections.ArrayList(); var resolvedPrefixes = new MG.Collections.ArrayList(); var unresolvedPrefixes = new MG.Collections.ArrayList(); var count = results !== null ? results.length : 0; for(var index = 0; index < count; index++) { var matchValue = results[index]; var value = matchValue.slice(1, matchValue.length - 1); if(prefixes.IndexOf(value) < 0) prefixes.Add(value); } regEx = /:[a-zA-Z]+=|[a-zA-Z]+=/g; results = xml.match(regEx); count = results !== null ? results.length : 0; var prefixesCount = prefixes.Count(); for(var index = 0; index < prefixesCount; index++) { var resolved = false; var prefix = prefixes.Item(index); for(var j = 0; j < count; j++) { var attribute = results[j]; var value= null; if(attribute.indexOf(":") === 0) value = attribute.slice(1, attribute.length - 1); else value = attribute.slice(0, attribute.length - 1); if(prefix === value) { if(resolvedPrefixes.IndexOf(value) < 0) resolvedPrefixes.Add(prefixes.Item(index)); resolved = true; } else { if(resolvedPrefixes.IndexOf(value) < 0) resolvedPrefixes.Add(value); } } if(!resolved) unresolvedPrefixes.Add(prefixes.Item(index)); } var uniqueNamespaces = new MG.Collections.Dictionary(); var exPrefixesCount = resolvedPrefixes.Count(); for(var index = 0; index < exPrefixesCount; index++) { var prefix = resolvedPrefixes.Item(index); var regexS = "\\b" + prefix + "=\s*\".*?\""; var regex = new RegExp(regexS); var results = regex.exec(xml); if(results !== null && results.length > 0) { var prefixValues = new MG.Collections.ArrayList(); for(var j = 0; j < results.length; j++) { var value = results[j].substring(prefix.length + 2, results[j].length - 1); prefixValues.Add(value); } uniqueNamespaces.Add(prefix, prefixValues); } } return uniqueNamespaces; } function createNSResolvers(node) { var childNodes = node.childNodes; for(var index = 0; index < childNodes.length; index++) { var prefix = childNodes[index].prefix; var nsURI = childNodes[index].namespaceURI; if(prefix && nsURI) { if(!nsResolvers.Item(prefix)) nsResolvers.Add(prefix, nsURI); } createNSResolvers(childNodes[index]); } } this.nsResolvers = nsResolvers; } function __getXml() { var xmlSerializer = new XMLSerializer(); var xml = xmlSerializer.serializeToString(this); return xml; } if(Node.prototype.__defineGetter__) Node.prototype.__defineGetter__("xml", __getXml); return new MG.Xml.XmlNode(document.implementation.createDocument(namespaceURL, rootTagName, null)); } else { var doc = new ActiveXObject("MSXML2.DOMDocument"); if(rootTagName) { var prefix = ""; var tagName = rootTagName; var pos = rootTagName.indexOf(":"); if(pos != -1) { rootTagName = rootTagName.substring(0, pos); tagName = rootTagName.substring(pos + 1); } if (namespaceURL) { if (!prefix) prefix = "a0"; } else prefix = ""; var text = "<" + (prefix?(prefix+":"):"") + tagName + (namespaceURL?(" xmlns:" + prefix + '="' + namespaceURL +'"'):"") + "/>"; doc.loadXML(text); } return new MG.Xml.XmlNode(doc); } }; MG.Xml.XmlNode = function(nativeNode) { if(nativeNode) { this.NativeNode = nativeNode; this.NativeAttributes = nativeNode.attributes; this.NativeChildNodes = nativeNode.childNodes; } }; MG.Xml.XmlNode.prototype.mdcXPath = function(node, xpathExpression, queryType) { var xpe = new XPathEvaluator(); var nsResolver = function(prefix) { var nsResolvers = node.nsResolvers; if(!nsResolvers) nsResolvers = node.ownerDocument.nsResolvers; var item = nsResolvers.Item(prefix); if(item) { if (item.Count() > 0) { return item.Item(0); } } else return xpe.createNSResolver(node.ownerDocument == null ? node.documentElement : node.ownerDocument.documentElement); }; var result = xpe.evaluate(xpathExpression, node, nsResolver, queryType, null); return result; }; MG.Xml.XmlNode.prototype.fixNameSpaces = function(node, nsResolvers, xml) { if(nsResolvers) { if(node.prefix) { var nsResolver = nsResolvers.Item(node.prefix); if(nsResolver) { xml += " " + "xmlns:" + node.prefix + "=\"" + nsResolver + "\""; nsResolvers.Remove(node.prefix); } } for(var index = 0; index < node.childNodes.length; index++) xml = this.fixNameSpaces(node.childNodes[index], nsResolvers, xml); } return xml; }
MG.Xml.XmlNode.prototype.operaSerialize = function(nativeNode) { var xml = null; switch(nativeNode.nodeType) { case 1: { if(this.Name() === nativeNode.nodeName) xml = "<" + nativeNode.localName; else xml = "<" + nativeNode.tagName; var nsResolvers = null; var xmlnsAdded = false; for (var i = 0; i < nativeNode.attributes.length; i++) { var localName = nativeNode.attributes[i].localName; var name = nativeNode.attributes[i].name; var value = nativeNode.attributes[i].value; if(this.Name() === nativeNode.nodeName) { if(nativeNode.ownerDocument) { nsResolvers = nativeNode.ownerDocument.nsResolvers; if(nsResolvers && nativeNode.ownerDocument.nsResolvers.Contains(localName)) nsResolvers.Remove(localName); } else { nsResolvers = nativeNode.nsResolvers; if(nsResolvers && nsResolvers.Contains(name)) nsResolvers.Remove(name); } } if(name === "xmlns") xmlnsAdded = true; xml += " " + name + "=\"" + value + "\""; } if(this.Name() === nativeNode.nodeName) { if(!nsResolvers) { if(nativeNode.ownerDocument) nsResolvers = nativeNode.ownerDocument.nsResolvers; else nsResolvers = nativeNode.nsResolvers; } if(nsResolvers) { var item = nsResolvers.Item("xmlns"); if(item) xml += " " + "xmlns" + "=\"" + item + "\""; else if(!xmlnsAdded) xml += " " + "xmlns" + "=\"" + "http://tempuri.org/" + "\""; xml = this.fixNameSpaces(nativeNode, nsResolvers, xml); } } xml += ">"; for (var i = 0; i < nativeNode.childNodes.length; i++) xml += this.operaSerialize(nativeNode.childNodes[i]); if(this.Name() === nativeNode.nodeName) xml += "</" + nativeNode.localName + ">"; else xml += "</" + nativeNode.tagName + ">"; } break; case 3: xml = nativeNode.nodeValue; break; case 4: xml = "<![CDATA[" + nativeNode.nodeValue + "]]>"; break; case 7: xml = "<?" + nativeNode.nodevalue + "?>"; break; case 8: xml = "<!--" + nativeNode.nodevalue + "-->"; break; case 9: { for (var i = 0; i < nativeNode.childNodes.length; i++) xml += this.operaSerialize(nativeNode.childNodes[i]); } break; } return xml; };
MG.Xml.XmlNode.prototype.ChildNodes = function(index) { if(this.NativeChildNodes) { if(arguments.length === 0) return new MG.Xml.XmlNodes(this.NativeChildNodes); else { var nativeNode = this.NativeChildNodes[index]; return (new MG.Xml.XmlNode(nativeNode)); } } return null; }; MG.Xml.XmlNode.prototype.NextSibling = function() { if(this.NativeNode) return new MG.Xml.XmlNode(this.NativeNode.nextSibling); return null; }; MG.Xml.XmlNode.prototype.FirstChild = function() { if(this.NativeNode) return new MG.Xml.XmlNode(this.NativeNode.firstChild); return null; }; MG.Xml.XmlNode.prototype.Name = function() { if(this.NativeNode) { var browser = MG.Browser.getInstance(); if(browser.NS || browser.OPERA) return this.NativeNode.nodeName; else if(browser.IE) return this.NativeNode.nodeName; } return null; }; MG.Xml.XmlNode.prototype.LocalName = function() { if(this.NativeNode) { var browser = MG.Browser.getInstance(); if(browser.NS || browser.OPERA) return this.NativeNode.localName; else if(browser.IE) return this.NativeNode.baseName; } return null; }; MG.Xml.XmlNode.prototype.Text = function() { if(this.NativeNode) { var browser = MG.Browser.getInstance(); if(arguments.length === 1) { if(browser.NS || browser.OPERA) return this.NativeNode.textContent = arguments[0]; else if(browser.IE) return this.NativeNode.text = arguments[0]; } else if(arguments.length === 0) { if(browser.NS || browser.OPERA) return this.NativeNode.textContent; else if(browser.IE) return this.NativeNode.text; } else throw("Only one parameter is expected."); } return null; }; MG.Xml.XmlNode.prototype.Value = function() { if(this.NativeNode) { if(arguments.length === 1) this.NativeNode.nodeValue = arguments[0]; else if(arguments.length === 0) return this.NativeNode.nodeValue; else throw("Only one parameter is expected."); } }; MG.Xml.XmlNode.prototype.Xml = function() { if(this.NativeNode) { var browser = MG.Browser.getInstance(); if(browser.NS || browser.IE) return this.NativeNode.xml; else if(browser.OPERA) return this.NativeNode.xml; } return null; }; MG.Xml.XmlNode.prototype.SelectSingleNode = function(xpathExpression) { if(this.NativeNode) { var nativeNode = null; var browser = MG.Browser.getInstance(); if(browser.NS || browser.OPERA) { var result = this.mdcXPath(this.NativeNode, xpathExpression, XPathResult.FIRST_ORDERED_NODE_TYPE); nativeNode = result ? result.singleNodeValue : null; } else if(browser.IE) nativeNode = this.NativeNode.selectSingleNode(xpathExpression); if(nativeNode) return new MG.Xml.XmlNode(nativeNode); } return null; }; MG.Xml.XmlNode.prototype.SelectNodes = function(xpathExpression) { if(this.NativeNode) { var nativeNodes = null; var browser = MG.Browser.getInstance(); if(browser.NS || browser.OPERA) { var result = this.mdcXPath(this.NativeNode, xpathExpression, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE); if(result) { var pseudoNodes = new MG.Collections.ArrayList(); for(var index = 0; index < result.snapshotLength; index++) pseudoNodes.Add(new MG.Xml.XmlNode(result.snapshotItem(index))); nativeNodes = pseudoNodes; } } else if(browser.IE) nativeNodes = this.NativeNode.selectNodes(xpathExpression); if(nativeNodes) return new MG.Xml.XmlNodes(nativeNodes); } return null; }; MG.Xml.XmlNode.prototype.CreateNode = function(type, name, namespaceURI) { if(this.NativeNode) { var nativeNode = this.NativeNode.createNode(type, name, namespaceURI); if(nativeNode) return new MG.Xml.XmlNode(nativeNode); } return null; }; MG.Xml.XmlNode.prototype.AppendChild = function(node) { if(this.NativeNode) this.NativeNode.appendChild(node.NativeNode); }; MG.Xml.XmlNode.prototype.RemoveChild = function(node) { if(this.NativeNode) this.NativeNode.removeChild(node.NativeNode); }; MG.Xml.XmlNode.prototype.ReplaceChild = function(newNode, oldNode) { if(this.NativeNode) this.NativeNode.replaceChild(newNode.NativeNode, oldNode.NativeNode); }; MG.Xml.XmlNode.prototype.ParentNode = function() { if(this.NativeNode) return new MG.Xml.XmlNode(this.NativeNode.parentNode); return null; }; MG.Xml.XmlNode.prototype.Prefix = function() { if(this.NativeNode) return this.NativeNode.prefix; return null; }; MG.Xml.XmlNode.prototype.LoadXML = function(xmlString) { this.NativeNode.loadXML(xmlString); }; MG.Xml.XmlNode.prototype.SetAttributeNode = function(attributeNode) { if(this.NativeNode) this.NativeNode.setAttributeNode(attributeNode.NativeAttribute); }; MG.Xml.XmlNode.prototype.SetAttribute = function(name, value) { if(this.NativeNode) this.NativeNode.setAttribute(name, value); }; MG.Xml.XmlNode.prototype.Attributes = function() { if(this.NativeAttributes) return new MG.Xml.Attributes(this.NativeAttributes); return null; }; MG.Xml.Attributes = function(nativeAttributes) { this.NativeAttributes = nativeAttributes; }; MG.Xml.Attributes.prototype.GetNamedItem = function(itemName) { if(this.NativeAttributes) return new MG.Xml.Attribute(this.NativeAttributes.getNamedItem(itemName)); return null; }; MG.Xml.Attributes.prototype.Item = function(index) { if(this.NativeAttributes) return new MG.Xml.Attribute(this.NativeAttributes[index]); return null; }; MG.Xml.Attributes.prototype.Length = function() { if(this.NativeAttributes) return this.NativeAttributes.length; return null; }; MG.Xml.Attribute = function(nativeAttribute) { this.NativeAttribute = nativeAttribute; }; MG.Xml.Attribute.prototype.Value = function() { if(this.NativeAttribute) return this.NativeAttribute.value; }; MG.Xml.Attribute.prototype.Name = function() { if(this.NativeAttribute) return this.NativeAttribute.name; }; MG.Xml.XmlNodes = function(nativeNodes) { var isPseudo = false; var browser = MG.Browser.getInstance(); if(browser.NS || browser.OPERA) { if(nativeNodes.constructor === MG.Collections.ArrayList.constructor) isPseudo = true; } else if(browser.IE) { if(nativeNodes.constructor === MG.Collections.ArrayList) isPseudo = true; } if(!isPseudo) { this.NativeNodes = new MG.Collections.ArrayList(); for(var index = 0; index < nativeNodes.length; index++) this.NativeNodes.Add(new MG.Xml.XmlNode(nativeNodes[index])); } else this.NativeNodes = nativeNodes; }; MG.Xml.XmlNodes.prototype.Length = function() { if(this.NativeNodes) { var browser = MG.Browser.getInstance(); if(browser.NS || browser.OPERA) { if(this.NativeNodes.constructor === MG.Collections.ArrayList.constructor) return this.NativeNodes.Count(); else return this.NativeNodes.length; } else if(browser.IE) { if(this.NativeNodes.constructor === MG.Collections.ArrayList) return this.NativeNodes.Count(); else return this.NativeNodes.length; } } return null; }; MG.Xml.XmlNodes.prototype.Item = function(index) { if(this.NativeNodes) return this.NativeNodes.Item(index); return null; };
October 1, 2010 at 3:53:00 PM PDT
Very nice looking library code, unfortunately the download link is not working. Any chance that you can fix it, I'd love to work with this.
November 17, 2010 at 11:37:00 PM PST
I have fixed the link so you can get the source code of the lib.