Bug Tracker

Ticket #1826 (new feature)

Opened 14 months ago

Last modified 6 months ago

namespaces handling for XMLs

Reported by: Orange Owned by:
Priority: minor Milestone: 1.2.2
Component: core Version: 1.2.1
Keywords: Cc:
Needs: Review

Description

Actual jQuery does return wrong results as soon as the user uses namespaces in an xml, because IE does not handle namespaces the same way as other browsers does.

In jQuery, this concerns the use of "nodeName" which returns "prefix:tagName" instead of "tagName". This concerns the following lines in jQuery-1.2.1.js which should be corrected with the following, in order to hide namespaces :

line 1260: c.nodeName.replace(/^.*:/,'').toUpperCase() instead of c.nodeName.toUpperCase()

line 1284: n.nodeName.replace(/^.*:/,'').toUpperCase() instead of n.nodeName.toUpperCase()

An other element that causes wrong behavior is "getElementsByTagName" which has to be used in IE with "prefix:tagName". This could be corrected by the following change :

line 1362: r = jQuery.merge( r, ret[i].getElementsByTagName( tag )); should be changed in :

// getElementsByTagName will not work with IE & namespaces
var retour = [];
if (jQuery.browser.msie && (ret[i].namespaces!=null) && (ret[i].namespaces.length>0)) {
	retour = jQuery.merge(retour,ret[i].getElementsByTagName(tag));
	for(var nsIndex = 0; nsIndex<ret[i].namespaces.length; nsIndex++) {
		var ns = "xmlns:ns='"+ret[i].namespaces(nsIndex)+"'";
		ret[i].setProperty("SelectionNamespaces", ns);
		var IeReturn = ret[i].selectNodes("ns:"+tag);
		retour = jQuery.merge(retour, IeReturn);
	}
} else {
	retour = ret[i].getElementsByTagName(tag);
}
r = jQuery.merge(r, retour);

Changes have been tested on IE6/7, Mozilla, Safari & Opera. They may be easier way to perform it, but this one works.

Change History

Changed 14 months ago by Orange

Error in suggested solution for line 1362 :

var IeReturn = ret[i].selectNodes("ns:"+tag); should be var IeReturn = ret[i].selectNodes("//ns:"+tag);

Changed 6 months ago by IvanTheBearable

This is similar to the solution suggested in ticket 155 but this avoids the potentially slow string searching that does with regular expressions. However, his only works when the context is the document node (IXMLDocument2). If the context is a node from within the document (IXMLDOMElement) then this fails because IXMLDOMElement does not have a namespaces property. In addition, the XPath used in selectNodes returns all matching nodes in the document rather than descendants of the context node.

To get around these issues you need to look at the ownerDocument and tweak the XPath. Something like this:

// getElementsByTagName will not work with IE & namespaces
var tags = [];
if (jQuery.browser.msie && ret[i].xml !== undefined && tag != '*') {
	var od = (ret[i].ownerDocument) ? ret[i].ownerDocument : ret[i];
	var ns = od.namespaces;
	if ((ns!=null) && (ns.length>0)) {
		for (var nsIndex = 0; nsIndex<ns.length; nsIndex++) {
			od.setProperty("SelectionNamespaces", "xmlns:ns='" + ns(nsIndex) + "'");
			var IeReturn = ret[i].selectNodes(".//ns:"+tag);
			tags = jQuery.merge(tags, IeReturn);
		}
	}
}
tags = jQuery.merge(tags,ret[i].getElementsByTagName(tag));
r = jQuery.merge(r, tags);

This is really only a partial solution to the issue. What's really needed is a way to specify a namespace in the selector. I've seen a suggestion that the | character be used for that. So, "ns|tag" would return all tags of the form <ns:tag>. But the prefix should not be hard coded in a selector. The whole point of it is that the prefix should be able to be changed to avoid conflicts without affecting code that processes the document.

So, either we include the whole namespace URL in the selector, or we have a way to map another namespace prefix to the URI:

.find(selector, context, nsPrefix, nsURI)

(for example)

Changed 6 months ago by IvanTheBearable

And, while I think of it, the first two fixes (adding the replace to the nodeName comparisons in the section that handles child selectors) more-or-less get the job done, but they also have a problem. XML is case sensitive. Converting everything to uppercase to do a comparison might be appropriate for HTML documents but not for XML documents.

Note: See TracTickets for help on using tickets.