1 /* 2 * jQuery CURIE @VERSION 3 * 4 * Copyright (c) 2008,2009 Jeni Tennison 5 * Licensed under the MIT (MIT-LICENSE.txt) 6 * 7 * Depends: 8 * jquery.uri.js 9 */ 10 /** 11 * @fileOverview XML Namespace processing 12 * @author <a href="mailto:jeni@jenitennison.com">Jeni Tennison</a> 13 * @copyright (c) 2008,2009 Jeni Tennison 14 * @license MIT license (MIT-LICENSE.txt) 15 * @version 1.0 16 * @requires jquery.uri.js 17 */ 18 19 /*global jQuery */ 20 (function ($) { 21 22 var 23 xmlNs = 'http://www.w3.org/XML/1998/namespace', 24 xmlnsNs = 'http://www.w3.org/2000/xmlns/', 25 26 xmlnsRegex = /\sxmlns(?::([^ =]+))?\s*=\s*(?:"([^"]*)"|'([^']*)')/g, 27 28 ncNameChar = '[-A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u10000-\uEFFFF\.0-9\u00B7\u0300-\u036F\u203F-\u2040]', 29 ncNameStartChar = '[\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u0131\u0134-\u013E\u0141-\u0148\u014A-\u017E\u0180-\u01C3\u01CD-\u01F0\u01F4-\u01F5\u01FA-\u0217\u0250-\u02A8\u02BB-\u02C1\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03CE\u03D0-\u03D6\u03DA\u03DC\u03DE\u03E0\u03E2-\u03F3\u0401-\u040C\u040E-\u044F\u0451-\u045C\u045E-\u0481\u0490-\u04C4\u04C7-\u04C8\u04CB-\u04CC\u04D0-\u04EB\u04EE-\u04F5\u04F8-\u04F9\u0531-\u0556\u0559\u0561-\u0586\u05D0-\u05EA\u05F0-\u05F2\u0621-\u063A\u0641-\u064A\u0671-\u06B7\u06BA-\u06BE\u06C0-\u06CE\u06D0-\u06D3\u06D5\u06E5-\u06E6\u0905-\u0939\u093D\u0958-\u0961\u0985-\u098C\u098F-\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09DC-\u09DD\u09DF-\u09E1\u09F0-\u09F1\u0A05-\u0A0A\u0A0F-\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32-\u0A33\u0A35-\u0A36\u0A38-\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8B\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2-\u0AB3\u0AB5-\u0AB9\u0ABD\u0AE0\u0B05-\u0B0C\u0B0F-\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32-\u0B33\u0B36-\u0B39\u0B3D\u0B5C-\u0B5D\u0B5F-\u0B61\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99-\u0B9A\u0B9C\u0B9E-\u0B9F\u0BA3-\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C60-\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CDE\u0CE0-\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D60-\u0D61\u0E01-\u0E2E\u0E30\u0E32-\u0E33\u0E40-\u0E45\u0E81-\u0E82\u0E84\u0E87-\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA-\u0EAB\u0EAD-\u0EAE\u0EB0\u0EB2-\u0EB3\u0EBD\u0EC0-\u0EC4\u0F40-\u0F47\u0F49-\u0F69\u10A0-\u10C5\u10D0-\u10F6\u1100\u1102-\u1103\u1105-\u1107\u1109\u110B-\u110C\u110E-\u1112\u113C\u113E\u1140\u114C\u114E\u1150\u1154-\u1155\u1159\u115F-\u1161\u1163\u1165\u1167\u1169\u116D-\u116E\u1172-\u1173\u1175\u119E\u11A8\u11AB\u11AE-\u11AF\u11B7-\u11B8\u11BA\u11BC-\u11C2\u11EB\u11F0\u11F9\u1E00-\u1E9B\u1EA0-\u1EF9\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2126\u212A-\u212B\u212E\u2180-\u2182\u3041-\u3094\u30A1-\u30FA\u3105-\u312C\uAC00-\uD7A3\u4E00-\u9FA5\u3007\u3021-\u3029_]', 30 ncNameRegex = new RegExp('^' + ncNameStartChar + ncNameChar + '*$'); 31 32 33 /** 34 * Returns the namespaces declared in the scope of the first selected element, or 35 * adds a namespace declaration to all selected elements. Pass in no parameters 36 * to return all namespaces bindings on the first selected element. If only 37 * the prefix parameter is specified, this method will return the namespace 38 * URI that is bound to the specified prefix on the first element in the selection 39 * If the prefix and uri parameters are both specified, this method will 40 * add the binding of the specified prefix and namespace URI to all elements 41 * in the selection. 42 * @methodOf jQuery# 43 * @name jQuery#xmlns 44 * @param {String} [prefix] Restricts the namespaces returned to only the namespace with the specified namespace prefix. 45 * @param {String|jQuery.uri} [uri] Adds a namespace declaration to the selected elements that maps the specified prefix to the specified namespace. 46 * @param {Object} [inherited] A map of inherited namespace bindings. 47 * @returns {Object|jQuery.uri|jQuery} 48 * @example 49 * // Retrieve all of the namespace bindings on the HTML document element 50 * var nsMap = $('html').xmlns(); 51 * @example 52 * // Retrieve the namespace URI mapped to the 'dc' prefix on the HTML document element 53 * var dcNamespace = $('html').xmlns('dc'); 54 * @example 55 * // Create a namespace declaration that binds the 'dc' prefix to the URI 'http://purl.org/dc/elements/1.1/' 56 * $('html').xmlns('dc', 'http://purl.org/dc/elements/1.1/'); 57 */ 58 $.fn.xmlns = function (prefix, uri, inherited) { 59 var 60 elem = this.eq(0), 61 ns = elem.data('xmlns'), 62 e = elem[0], a, p, i, 63 decl = prefix ? 'xmlns:' + prefix : 'xmlns', 64 value, 65 tag, found = false; 66 if (uri === undefined) { 67 if (prefix === undefined) { // get the in-scope declarations on the first element 68 if (!ns) { 69 ns = { 70 // xml: $.uri(xmlNs) 71 }; 72 if (e.attributes && e.attributes.getNamedItemNS) { 73 for (i = 0; i < e.attributes.length; i += 1) { 74 a = e.attributes[i]; 75 if (/^xmlns(:(.+))?$/.test(a.nodeName)) { 76 prefix = /^xmlns(:(.+))?$/.exec(a.nodeName)[2] || ''; 77 value = a.nodeValue; 78 if (prefix === '' || (value !== '' && value !== xmlNs && value !== xmlnsNs && ncNameRegex.test(prefix) && prefix !== 'xml' && prefix !== 'xmlns')) { 79 ns[prefix] = $.uri(a.nodeValue); 80 found = true; 81 } 82 } 83 } 84 } else { 85 tag = /<[^>]+>/.exec(e.outerHTML); 86 a = xmlnsRegex.exec(tag); 87 while (a !== null) { 88 prefix = a[1] || ''; 89 value = a[2] || a[3]; 90 if (prefix === '' || (value !== '' && value !== xmlNs && value !== xmlnsNs && ncNameRegex.test(prefix) && prefix !== 'xml' && prefix !== 'xmlns')) { 91 ns[prefix] = $.uri(a[2] || a[3]); 92 found = true; 93 } 94 a = xmlnsRegex.exec(tag); 95 } 96 xmlnsRegex.lastIndex = 0; 97 } 98 inherited = inherited || (e.parentNode.nodeType === 1 ? elem.parent().xmlns() : {}); 99 ns = found ? $.extend({}, inherited, ns) : inherited; 100 elem.data('xmlns', ns); 101 } 102 return ns; 103 } else if (typeof prefix === 'object') { // set the prefix mappings defined in the object 104 for (p in prefix) { 105 if (typeof prefix[p] === 'string' && ncNameRegex.test(p)) { 106 this.xmlns(p, prefix[p]); 107 } 108 } 109 this.find('*').andSelf().removeData('xmlns'); 110 return this; 111 } else { // get the in-scope declaration associated with this prefix on the first element 112 if (!ns) { 113 ns = elem.xmlns(); 114 } 115 return ns[prefix]; 116 } 117 } else { // set 118 this.find('*').andSelf().removeData('xmlns'); 119 return this.attr(decl, uri); 120 } 121 }; 122 123 /** 124 * Removes one or more XML namespace bindings from the selected elements. 125 * @methodOf jQuery# 126 * @name jQuery#removeXmlns 127 * @param {String|Object|String[]} prefix The prefix(es) of the XML namespace bindings that are to be removed from the selected elements. 128 * @returns {jQuery} The original jQuery object. 129 * @example 130 * // Remove the foaf namespace declaration from the body element: 131 * $('body').removeXmlns('foaf'); 132 * @example 133 * // Remove the foo and bar namespace declarations from all h2 elements 134 * $('h2').removeXmlns(['foo', 'bar']); 135 * @example 136 * // Remove the foo and bar namespace declarations from all h2 elements 137 * var namespaces = { foo : 'http://www.example.org/foo', bar : 'http://www.example.org/bar' }; 138 * $('h2').removeXmlns(namespaces); 139 */ 140 $.fn.removeXmlns = function (prefix) { 141 var decl, p, i; 142 if (typeof prefix === 'object') { 143 if (prefix.length === undefined) { // assume an object representing namespaces 144 for (p in prefix) { 145 if (typeof prefix[p] === 'string') { 146 this.removeXmlns(p); 147 } 148 } 149 } else { // it's an array 150 for (i = 0; i < prefix.length; i += 1) { 151 this.removeXmlns(prefix[i]); 152 } 153 } 154 } else { 155 decl = prefix ? 'xmlns:' + prefix : 'xmlns'; 156 this.removeAttr(decl); 157 } 158 this.find('*').andSelf().removeData('xmlns'); 159 return this; 160 }; 161 162 $.fn.qname = function (name) { 163 var m, prefix, namespace; 164 if (name === undefined) { 165 if (this[0].outerHTML === undefined) { 166 name = this[0].nodeName.toLowerCase(); 167 } else { 168 name = /<([^ >]+)/.exec(this[0].outerHTML)[1].toLowerCase(); 169 } 170 } 171 if (name === '?xml:namespace') { 172 // there's a prefix on the name, but we can't get at it 173 throw "XMLinHTML: Unable to get the prefix to resolve the name of this element"; 174 } 175 m = /^(([^:]+):)?([^:]+)$/.exec(name); 176 prefix = m[2] || ''; 177 namespace = this.xmlns(prefix); 178 if (namespace === undefined && prefix !== '') { 179 throw "MalformedQName: The prefix " + prefix + " is not declared"; 180 } 181 return { 182 namespace: namespace, 183 localPart: m[3], 184 prefix: prefix, 185 name: name 186 }; 187 }; 188 189 })(jQuery); 190