私の第5世代セレクタIcarus

59781 ワード

Icarusは私の現在のマッチング精度が最も高く(470ユニットのテストで精度を保証)、速度が最も速い(IE 67でjQueryを押して、他のブラウザはquerySelectorAllを使って上下を区別しない)セレクタで、CSS 3のすべての新しい擬似クラスを全面的にサポートして、jQueryが持っているカスタム擬似クラスをサポートして、XMLの検索をサポートして、XMLネーミングスペース付き要素の検索をサポートします(jQueryはネーミングスペースなし、間違いを報告しやすいのみをサポートします).
IcarusとjQuery 1.7 slickspeedでのスピード試合の結果(数値の最大代表が遅いほど):
Icarus
jQuery1.7
ひれい
IE7
443
657
1.5
IE6
975
1570
1.6
初期のjQueryと比較すると42は言うまでもなく、その2倍以上です.
Icarusの最大のハイライトはXMLの完璧なサポートです.そのため、xpathとgetElementsByTagNameを使用します.ネーミングスペースのサポートについては、「aaa\::bbb」を使用して検索してください.
以下は、IcarusがオリジナルのAPIを検索するために使用したものです.
  • getElementById
  • getElementsByTagName
  • getElementsByTagNameNS
  • getElementsByClassName
  • evaluate (xpath)
  • selectNodes (xpath)
  • querySelectorAll

  • Icarusの符号量は930行(domに依存しない他のモジュール)、jQueryのSizzleは1500行である.
    Icarus対CSS 3擬似クラスはW 3 Cの仕様で検索されます.例えば、not逆選択擬似クラスは、div:not(.a)のような単一の式のみをサポートし、div:not(.a.b)は使用できません.使用するには複数の逆選択が必要です.div:not(.a):not(.b).
    IcarusはjQueryのカスタム擬似クラスをサポートしているが、位置擬似クラス(:first,:last,:even,:odd,:eq...)などの使用は提唱されていない.(last-child,:first-child,:nth-child(even)...)の代わりに、標準的なサブエレメントを使用して擬似クラスをフィルタリングすることができます.jQueryのカスタムフォーム擬似クラス(:text,:radio....)について、(input[type=text],input[type=radio]...)の代わりに属性セレクタを使用することもできます.とにかく、標準的でないものは長く生きられないので、覚えておいてほしい.
    
    //dom.query v5     Icarus
    (function(global,DOC){
        var dom = global[DOC.URL.replace(/(#.+|\W)/g,'')];
        dom.define("query", function(){
            dom.mix(dom,{
                //http://www.cnblogs.com/rubylouvre/archive/2010/03/14/1685360.
                isXML : function(el){
                    var doc = el.ownerDocument || el
                    return doc.createElement("p").nodeName !== doc.createElement("P").nodeName;
                },
                //               
                contains:function(a, b){
                    if(a.compareDocumentPosition){
                        return !!(a.compareDocumentPosition(b) & 16);
                    }else if(a.contains){
                        return a !== b && (a.contains ? a.contains(b) : true);
                    }
                    while ((b = b.parentNode))
                        if (a === b) return true;
                    return false;
                },
                //         ,          ,   childNodes     ,
                //              ,        ,       innerText textContent
                getText : function() {
                    return function getText( nodes ) {
                        for ( var i = 0, ret = "",node; node = nodes[i++];  ) {
                            //        CDATA   
                            if ( node.nodeType === 3 || node.nodeType === 4 ) {
                                ret += node.nodeValue;
                            //         
                            } else if ( node.nodeType !== 8 ) {
                                ret += getText( node.childNodes );
                            }
                        }
                        return ret;
                    }
                }(),
         
                unique :function(nodes){
                    if(nodes.length < 2){
                        return nodes;
                    }
                    var result = [], array = [], uniqResult = {}, node = nodes[0],index, ri = 0
                    //    sourceIndex              
                    //http://www.cnblogs.com/jkisjk/archive/2011/01/28/array_quickly_sortby.html
                    if(node.sourceIndex){//IE opera
                        for(var i = 0 , n = nodes.length; i< n; i++){
                            node = nodes[i];
                            index = node.sourceIndex+1e8;
                            if(!uniqResult[index]){
                                (array[ri++] = new String(index))._ = node;
                                uniqResult[index] = 1
                            }
                        }
                        array.sort();
                        while( ri )
                            result[--ri] = array[ri]._;
                        return result;
                    }else {
                        var sortOrder = node.compareDocumentPosition ? sortOrder1 : sortOrder2;
                        nodes.sort( sortOrder );
                        if (sortOrder.hasDuplicate ) {
                            for ( i = 1; i < nodes.length; i++ ) {
                                if ( nodes[i] === nodes[ i - 1 ] ) {
                                    nodes.splice( i--, 1 );
                                }
                            }
                        }
                        sortOrder.hasDuplicate = false;
                        return nodes;
                    }
                }
            });
            var reg_combinator  = /^\s*([>+~,\s])\s*(\*|(?:[-\w*]|[^\x00-\xa0]|\\.)*)/
            var trimLeft = /^\s+/;
            var trimRight = /\s+$/;
            var reg_quick = /^(^|[#.])((?:[-\w]|[^\x00-\xa0]|\\.)+)$/;
            var reg_comma       = /^\s*,\s*/;
            var reg_sequence = /^([#\.:]|\[\s*)((?:[-\w]|[^\x00-\xa0]|\\.)+)/;
            var reg_pseudo        = /^\(\s*("([^"]*)"|'([^']*)'|[^\(\)]*(\([^\(\)]*\))?)\s*\)/;
            var reg_attrib      = /^\s*(?:(\S?=)\s*(?:(['"])(.*?)\2|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/
            var reg_attrval  = /\\([0-9a-fA-F]{2,2})/g;
            var reg_sensitive       = /^(title|id|name|class|for|href|src)$/
            var reg_backslash = /\\/g;
            var reg_tag  = /^((?:[-\w\*]|[^\x00-\xa0]|\\.)+)/;//   getElementsByTagName   CSS   
            if ( trimLeft.test( "\xA0" ) ) {
                trimLeft = /^[\s\xA0]+/;
                trimRight = /[\s\xA0]+$/;
            }
    
            var hash_operator   = {
                "=": 1, 
                "!=": 2, 
                "|=": 3,
                "~=": 4, 
                "^=": 5, 
                "$=": 6, 
                "*=": 7
            }
    
            function sortOrder1( a, b ) {
                if ( a === b ) {
                    sortOrder1.hasDuplicate = true;
                    return 0;
                }
                if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
                    return a.compareDocumentPosition ? -1 : 1;
                }
                return a.compareDocumentPosition(b) & 4 ? -1 : 1;
            };
    
            function sortOrder2( a, b ) {//           XML
                if ( a === b ) {
                    sortOrder2.hasDuplicate = true;
                    return 0;
                }
                var al, bl,
                ap = [],
                bp = [],
                aup = a.parentNode,
                bup = b.parentNode,
                cur = aup;
                //           ,        childNodes    
                if ( aup === bup ) {
                    return siblingCheck( a, b );
                // If no parents were found then the nodes are disconnected
                } else if ( !aup ) {
                    return -1;
    
                } else if ( !bup ) {
                    return 1;
                }
                // Otherwise they're somewhere else in the tree so we need
                // to build up a full list of the parentNodes for comparison
                while ( cur ) {
                    ap.unshift( cur );
                    cur = cur.parentNode;
                }
    
                cur = bup;
    
                while ( cur ) {
                    bp.unshift( cur );
                    cur = cur.parentNode;
                }
    
                al = ap.length;
                bl = bp.length;
    
                // Start walking down the tree looking for a discrepancy
                for ( var i = 0; i < al && i < bl; i++ ) {
                    if ( ap[i] !== bp[i] ) {
                        return siblingCheck( ap[i], bp[i] );
                    }
                }
                // We ended someplace up the tree so do a sibling check
                return i === al ?
                siblingCheck( a, bp[i], -1 ) :
                siblingCheck( ap[i], b, 1 );
            };
            function siblingCheck( a, b, ret ) {
                if ( a === b ) {
                    return ret;
                }
                var cur = a.nextSibling;
    
                while ( cur ) {
                    if ( cur === b ) {
                        return -1;
                    }
                    cur = cur.nextSibling;
                }
                return 1;
            };
            var slice = Array.prototype.slice;
            function makeArray( nodes, result, flag_multi ) {  
                nodes = slice.call( nodes, 0 );
                if ( result ) {
                    result.push.apply( result, nodes );
                }else{
                    result = nodes;
                }
                return  flag_multi ? dom.unique(result) : result;
            };
            //IE56789              
            try {
                slice.call( dom.html.childNodes, 0 )[0].nodeType;
            } catch( e ) {
                function makeArray( nodes, result ,flag_multi) {
                    var ret = result || [], ri = ret.length;
                    for(var i = 0,el ; el = nodes[i++];){
                        ret[ri++] = el
                    }
                    return flag_multi ? dom.unique(ret) : ret;
                }
            }
            function _toHex(x, y) {
                return String.fromCharCode(parseInt(y, 16));
            }
            function parse_nth(expr) {
                var orig = expr
                expr = expr.replace(/^\+|\s*/g, '');//       
                var match = (expr === "even" && "2n" || expr === "odd" && "2n+1" || !/\D/.test(expr) && "0n+" + expr || expr).match(/(-?)(\d*)n([-+]?\d*)/);
                return parse_nth[ orig ] = {
                    a: (match[1] + (match[2] || 1)) - 0, 
                    b: match[3] - 0
                };
            }
            function getElementsByTagName(tagName, els, flag_xml) {
                var method = "getElementsByTagName", elems = [], uniqResult = {}, prefix
                if(flag_xml && tagName.indexOf(":") > 0 && els.length && els[0].lookupNamespaceURI){
                    var arr = tagName.split(":");
                    prefix = arr[0];
                    tagName = arr[1];
                    method = "getElementsByTagNameNS";
                    prefix = els[0].lookupNamespaceURI(prefix);
                }
                switch (els.length) {
                    case 0:
                        return elems;
                    case 1:
                        // IE67 ,      name length input  ,   all.length     ,      
                        var all =  prefix ? els[0][method](prefix,tagName) : els[0][method](tagName);
                        for(var i = 0, ri = 0, el; el = all[i++];){
                            if(el.nodeType === 1){//        
                                elems[ri++] = el
                            }
                        }
                        return elems;
                    default:
                        for(i = 0, ri = 0; el = els[i++];){
                            var nodes = prefix ? el[method](prefix,tagName) : el[method](tagName)
                            for (var j = 0, node; node = nodes[j++];) {
                                var uid = dom.getUid(node);
                               
                                if (!uniqResult[uid]) {
                                    uniqResult[uid] = elems[ri++] = node;
                                }
                            }
                        }
                        return elems;
                }
            }
            //IE9    XML             
            var attrURL = dom.oneObject('action,cite,codebase,data,href,longdesc,lowsrc,src,usemap', 2);
            var bools = dom["@bools"] = "autofocus,autoplay,async,checked,controls,declare,disabled,defer,defaultChecked,"+
            "contentEditable,ismap,loop,multiple,noshade,open,noresize,readOnly,selected"
            var boolOne = dom.oneObject(bools.toLowerCase() ); 
            var getHTMLText = new Function("els","return els[0]."+ (dom.html.textContent ? "textContent" : "innerText") );
            //    BUG(fixGetAttribute,fixHasAttribute,fixById,fixByTag)
            var fixGetAttribute,fixHasAttribute,fixById,fixByTag;
            new function(){
                var select = DOC.createElement("select");
                var option = select.appendChild( DOC.createElement("option") );
                option.setAttribute("selected","selected")
                option.className ="x"
                fixGetAttribute = option.getAttribute("class") != "x";
                select.appendChild( DOC.createComment("") );
                fixByTag = select.getElementsByTagName("*").length == 2
                var all = DOC.getElementsByTagName("*"), node, nodeType, comments = [], i = 0, j = 0;
                while ( (node = all[i++]) ) {  
                    nodeType = node.nodeType;
                    nodeType === 1 ? dom.getUid(node) : 
                    nodeType === 8 ? comments.push(node) : 0;  
                }
                while ( (node = comments[j++]) ) {   
                    node.parentNode.removeChild(node);
                }
                fixHasAttribute = select.hasAttribute ? !option.hasAttribute('selected') :true;
            
                var form = DOC.createElement("div"),
                id = "fixId" + (new Date()).getTime(),
                root = dom.html;
                form.innerHTML = "<a name='" + id + "'/>";
                root.insertBefore( form, root.firstChild );
                fixById = !!DOC.getElementById( id ) ;
                root.removeChild(form )
            };
    
            //http://www.atmarkit.co.jp/fxml/tanpatsu/24bohem/01.html
            //http://msdn.microsoft.com/zh-CN/library/ms256086.aspx
            //https://developer.mozilla.org/cn/DOM/document.evaluate
            //http://d.hatena.ne.jp/javascripter/20080425/1209094795
            function getElementsByXPath(xpath,context,doc) {
                var result = [];
                try{
                    if(global.DOMParser){//IE9  DOMParser,       doc.evaluate!global.DOMParser
                        var nodes = doc.evaluate(xpath, context, null, 7, null);
                        for (var i = 0, n = nodes.snapshotLength; i < n; i++){
                            result[i] =  nodes.snapshotItem(i)
                        } 
                    }else{
                        nodes = context.selectNodes(xpath);
                        for (i = 0, n = nodes.length; i < n; i++){
                            result[i] =  nodes[i]
                        } 
                    }
                }catch(e){
                    return false;
                }
                return result;
            };
            /**
             *    
             * @param {String} expr CSS   
             * @param {Node}   context    (  )
             * @param {Array}  result     (    )
             * @param {Array}  lastResult        (    )
             * @param {Boolean}flag_xml    XML  (    )
             * @param {Boolean}flag_multi          (    )
             * @param {Boolean}flag_dirty           (    )
             * @return {Array} result
             */
            //http://webbugtrack.blogspot.com/
            var Icarus = dom.query = function(expr, contexts, result, lastResult, flag_xml,flag_multi,flag_dirty){
                result = result || [];
                contexts = contexts || DOC;
                var pushResult = makeArray;
                if(!contexts.nodeType){//          
                    contexts = pushResult(contexts);
                    if(!contexts.length)
                        return result
                }else{
                    contexts = [contexts];
                }
                var rrelative = reg_combinator,//        
                rquick = reg_quick,
                rBackslash = reg_backslash, rcomma = reg_comma,//         
                context = contexts[0],
                doc = context.ownerDocument || context,
                rtag = reg_tag,
                flag_all, uniqResult, elems, nodes, tagName, last, ri, uid;
                //                 
                //              
                expr = expr.replace(trimLeft, "").replace(trimRight, "");  
                flag_xml = flag_xml !== void 0 ? flag_xml : dom.isXML(doc);
           
                if (!flag_xml && doc.querySelectorAll2) {
                    var query = expr;
                    if(contexts.length > 2 || doc.documentMode == 8  && context.nodeType == 1  ){
                        if(contexts.length > 2 )
                            context = doc;
                        query = ".fix_icarus_sqa "+query;//IE8            
                        for(var i = 0, node; node = contexts[i++];){
                            if(node.nodeType === 1){
                                node.className = "fix_icarus_sqa " + node.className;
                            }
                        }
                    }
                    if(doc.documentMode !== 8  || context.nodeName.toLowerCase() !== "object"){
                        try{
                            return pushResult( context.querySelectorAll(query), result, flag_multi);
                        }catch(e){
                        }finally{
                            if(query.indexOf(".fix_icarus_sqa") === 0 ){//           ,      
                                for(i = 0; node = contexts[i++];){
                                    if(node.nodeType === 1){
                                        node.className =  node.className.replace("fix_icarus_sqa ","");
                                    }
                                }
                            }
                        }
                    }
                }
                var match = expr.match(rquick);
                if(match ){//       ,   ID        
                    var value = match[2].replace(rBackslash,""), key = match[1];
                    if (  key == "") {//tagName;
                        nodes = getElementsByTagName(value,contexts,flag_xml);
                    } else if ( key === "." && contexts.length === 1 ) {//className,       1 
                        if(flag_xml){//  XPATH    ,      ,              
                            nodes = getElementsByXPath("//*[@class='"+value+"']", context, doc);
                        }else if(context.getElementsByClassName){
                            nodes = context.getElementsByClassName( value );
                        }
                    }else if ( key === "#" && contexts.length === 1){//ID,       1 
                        if( flag_xml){
                            nodes = getElementsByXPath("//*[@id='"+value+"']", context, doc);
                        //  document        ,              DOM ,  dom("<div id=\"A'B~C.D[E]\"><p>foo</p></div>").find("p")
                        }else if(context.nodeType == 9){
                            node = doc.getElementById(value);
                            //IE67 opera      ,object     ID NAME
                            //http://webbugtrack.blogspot.com/2007/08/bug-152-getelementbyid-returns.html
                            nodes = !node ? [] : !fixById ? [node] : node.getAttributeNode("id").nodeValue === value ? [node] : false;
                        }
                    }
                    if(nodes ){
                        return pushResult( nodes, result, flag_multi );
                    }
                }
                //               
                lastResult = contexts;
                if(lastResult.length){
                    loop:
                    while (expr && last !== expr) {
                        flag_dirty = false;
                        elems = null;
                        uniqResult = {};
                        //            (                     )
                        if (match = expr.match(rrelative)) {
                            expr = RegExp.rightContext;
                            elems = [];
                            tagName = (flag_xml ? match[2] : match[2].toUpperCase()).replace(rBackslash,"") || "*";
                            i = 0;
                            ri = 0;
                            flag_all = tagName === "*";//       tagName
                            switch (match[1]) {//             ,       
                                case " "://     
                                    if(expr.length || match[2]){//                   
                                        elems = getElementsByTagName(tagName, lastResult, flag_xml);
                                    }else{
                                        elems = lastResult;
                                        break loop
                                    }
                                    break;
                                case ">"://     
                                    while((node = lastResult[i++])){
                                        for (node = node.firstChild; node; node = node.nextSibling){
                                            if (node.nodeType === 1 && (flag_all || tagName === node.nodeName)){
                                                elems[ri++] = node;
                                            }
                                        }
                                    }
                                    break;
                                case "+"://     
                                    while((node = lastResult[i++])){
                                        while((node = node.nextSibling)){
                                            if (node.nodeType === 1) {
                                                if (flag_all || tagName === node.nodeName)
                                                    elems[ri++] = node;
                                                break;
                                            }
                                        }
                                    }
                                    break;
                                case "~"://     
                                    while((node = lastResult[i++])){
                                        while((node = node.nextSibling)){
                                            if (node.nodeType === 1 && (flag_all || tagName === node.nodeName)) {
                                                uid = dom.getUid(node);
                                                if (uniqResult[uid]){
                                                    break;
                                                }else {
                                                    uniqResult[uid] = elems[ri++] = node;
                                                }
                                            }
                                        }
                                    }
                                    elems = dom.unique(elems);
                                    break;
                            }
                        }else if(match = expr.match(rtag)){//                          
                            expr = RegExp.rightContext;
                            elems = getElementsByTagName(match[1].replace(rBackslash,""), lastResult, flag_xml);
                        }
                       
                        if(expr){
                            var arr = Icarus.filter(expr, elems, lastResult, doc, flag_xml);
                            expr = arr[0];
                            elems = arr[1];
                            if (!elems) {
                                flag_dirty = true;
                                elems = getElementsByTagName("*", lastResult, flag_xml);
                            }
                            if (match = expr.match(rcomma)) {
                                expr = RegExp.rightContext;
                                pushResult(elems, result);
                                return Icarus(expr, contexts, result, [], flag_xml, true, flag_dirty);
                            }else{
                                lastResult = elems;
                            }
                        }
                        
                    }
                }
                if (flag_multi) {
                    if (elems.length){
                        return pushResult(elems, result,flag_multi);
                    }
                }else if (DOC !== doc || fixByTag && flag_dirty) {
                    for (result = [], ri = 0, i = 0; node = elems[i++]; )
                        if (node.nodeType === 1)
                            result[ri++] = node;
                    return result
                }
                return elems;
            }
            var onePosition = dom.oneObject("eq|gt|lt|first|last|even|odd".split("|"));
    
            dom.mix(Icarus, {
                //getAttribute       
                //http://reference.sitepoint.com/javascript/Element/getAttribute
                getAttribute : !fixGetAttribute ?
                function(elem, name) {
                    return elem.getAttribute(name) || '';
                } :
                function(elem, name, flag_xml) {
                    if(flag_xml)
                        return elem.getAttribute(name) || '';
                    name = name.toLowerCase();
                    //http://jsfox.cn/blog/javascript/get-right-href-attribute.html
                    if(attrURL[name]){//  href       ,        、         
                        return  elem.getAttribute(name, 2) || ''
                    }
                    if(elem.tagName === "INPUT" && name == "type"){
                        return elem.getAttribute("type") || elem.type;//IE67    HTML5     input  , input[type=search],    el.type el.getAttributeNode  。
                    }
                    //    ,   true        ,        ,      getAttributeNode
                    var attr = boolOne[name] ? (elem.getAttribute(name) ? name : '') :
                    (elem = elem.getAttributeNode(name)) && elem.value || '';
                    return reg_sensitive.test(name)? attr :attr.toLowerCase();
                },
                hasAttribute : !fixHasAttribute ?
                function(elem, name, flag_xml) {
                    return flag_xml ?  !!elem.getAttribute(name) :elem.hasAttribute(name);
                } :
                function(elem, name) {
                    //http://help.dottoro.com/ljnqsrfe.php
                    name = name.toLowerCase();
                    //            "",   outerHTML       
                    elem = elem.getAttributeNode(name);
                    return !!(elem && (elem.specified || elem.nodeValue));
                },
                filter : function(expr, elems, lastResult, doc, flag_xml, flag_get){
                    var rsequence = reg_sequence,
                    rattrib = reg_attrib ,
                    rpseudo = reg_pseudo,
                    rBackslash = reg_backslash,
                    rattrval  = reg_attrval,
                    pushResult = makeArray,
                    toHex = _toHex,
                    _hash_op  = hash_operator,
                    parseNth = parse_nth,
                    match ,key, tmp;
                    while ( match = expr.match(rsequence)) {//   
                        expr = RegExp.rightContext;     
                        key = ( match[2]|| "").replace(rBackslash,"");
                        if (!elems) {//         
                            if (lastResult.length === 1 && lastResult[0] === doc){
                                switch (match[1]) {
                                    case "#":
                                        if (!flag_xml) {//FF chrome opera XML      getElementById,    
                                            tmp = doc.getElementById(key);
                                            if (!tmp) {
                                                elems = [];
                                                continue;
                                            }
                                            //    name  "id"    form  
                                            if (fixById ? tmp.id === key : tmp.getAttributeNode("id").nodeValue === key) {
                                                elems = [tmp];
                                                continue;
                                            }
                                        }
                                        break;
                                    case ":":
                                        switch (key) {
                                            case "root":
                                                elems = [doc.documentElement];
                                                continue;
                                            case "link":
                                                elems = pushResult(doc.links || []);
                                                continue;
                                        }
                                        break;
                                }
                            }
                            elems = getElementsByTagName("*", lastResult, flag_xml);//     
                        }
                        //         ,       
                        var filter = 0, flag_not = false, args; 
                        switch (match[1]) {
                            case "#"://ID   
                                filter = ["id", "=", key];
                                break;
                            case "."://    
                                filter = ["class", "~=", key];
                                break;
                            case ":"://     
                                tmp = Icarus.pseudoAdapter[key];
                                if (match = expr.match(rpseudo)) {
                                    expr = RegExp.rightContext;
                                    if(!!~key.indexOf("nth")){
                                        args = parseNth[match[1]] || parseNth(match[1]);
                                    }else{
                                        args = match[3] || match[2] || match[1]
                                    }
                                }
                                if (tmp){
                                    filter = tmp;
                                }else if (key === "not") {
                                    flag_not = true;
                                    if (args === "*"){//              
                                        elems = [];
                                    }else if(reg_tag.test(args)){//             
                                        tmp = [];
                                        match = flag_xml ? args : args.toUpperCase();
                                        for (var i = 0, ri = 0, elem; elem = elems[i++];)
                                            if (match !== elem.nodeName)
                                                tmp[ri++] = elem;
                                        elems = tmp;
                                    }else{
                                        var obj =  Icarus.filter(args, elems, lastResult, doc, flag_xml, true) ;
                                        filter = obj.filter;
                                        args   = obj.args;
                                    }
                                }
                                else{
                                    throw 'An invalid or illegal string was specified : "'+ key+'"!'
                                }
                                break
                            default:
                                filter = [key.toLowerCase()];  
                                if (match = expr.match(rattrib)) {
                                    expr = RegExp.rightContext;
                                    if (match[1]) {
                                        filter[1] = match[1];//op
                                        filter[2] = match[3] || match[4];//      
                                        filter[2] = filter[2] ? filter[2].replace(rattrval, toHex).replace(rBackslash,"") : "";
                                    }
                                }
                                break;
                        }
                        if(flag_get){
                            return {
                                filter:filter,
                                args:args
                            }
                        }
                        //       ,        
                        if (elems.length && filter) {
                            tmp = [];
                            i = 0;
                            ri = 0;
                            if (typeof filter === "function") {//          
                                if(onePosition[key]){
                                    //  args void             ,   exp     
                                    args =  args === void 0 ? elems.length - 1 : ~~args;
                                    for (; elem = elems[i];){
                                        if(filter(i++, args) ^ flag_not)
                                            tmp[ri++] = elem;
                                    }
                                }else{
                                    while((elem = elems[i++])){
                                        if ((!!filter(elem, args)) ^ flag_not)
                                            tmp[ri++] = elem;
                                    }
                                }
                            }else if (typeof filter.exec === "function"){//          
                                tmp = filter.exec({
                                    not: flag_not, 
                                    xml: flag_xml
                                }, elems, args, doc);
                            } else {
                                var name = filter[0], op = _hash_op[filter[1]], val = filter[2]||"", flag, attr;
                                if (!flag_xml && name === "class" && op === 4) {//     
                                    val = " " + val + " ";
                                    while((elem = elems[i++])){
                                        var className = elem.className;
                                        if (!!(className && (" " + className + " ").indexOf(val) > -1) ^ flag_not){
                                            tmp[ri++] = elem;
                                        }
                                    }
                                } else {
                                    if(!flag_xml && op && val && !reg_sensitive.test(name)){
                                        val = val.toLowerCase();
                                    }
                                    if (op === 4){
                                        val = " " + val + " ";
                                    }
                                    while((elem = elems[i++])){
                                        if(!op){
                                            flag = Icarus.hasAttribute(elem,name,flag_xml);//[title]
                                        }else if(val === "" && op > 3){
                                            flag = false
                                        }else{
                                            attr = Icarus.getAttribute(elem,name,flag_xml);
                                            switch (op) {
                                                case 1:// =          
                                                    flag = attr === val;
                                                    break;
                                                case 2://!=    ,         
                                                    flag = attr !== val;
                                                    break;
                                                case 3://|=     “-”      ,          ,       
                                                    flag = attr === val || attr.substr(0, val.length + 1) === val + "-";
                                                    break;
                                                case 4://~=         ,        。
                                                    flag = attr  && (" " + attr + " ").indexOf(val) >= 0;
                                                    break;
                                                case 5://^=          
                                                    flag = attr  && attr.indexOf(val) === 0 ;
                                                    break;
                                                case 6://$=          
                                                    flag = attr  &&attr.substr(attr.length - val.length) === val;
                                                    break;
                                                case 7://*=         
                                                    flag = attr  && attr.indexOf(val) >= 0;
                                                    break;
                                            }
                                        }
                                        if (flag ^ flag_not)
                                            tmp[ri++] = elem;
                                    }
                                }
                            }
                            elems = tmp;
                        }
                    }
                    return [expr, elems];
                }
            });
    
            //===================          =====================
            var filterPseudoHasExp = function(strchild,strsibling, type){
                return {
                    exec:function(flags,lastResult,args){
                        var result = [], flag_not = flags.not,child = strchild, sibling = strsibling,
                        ofType = type, cache = {},lock = {},a = args.a, b = args.b, i = 0, ri = 0, el, found ,diff,count;
                        if(!ofType && a === 1 && b === 0 ){
                            return flag_not ? [] : lastResult;
                        }
                        var checkName = ofType ? "nodeName" : "nodeType";
                        for (; el = lastResult[i++];) {
                            var parent = el.parentNode;
                            var pid =  dom.getUid(parent);
                            if (!lock[pid]){
                                count = lock[pid] = 1;
                                var checkValue = ofType ? el.nodeName : 1;
                                for(var node = parent[child];node;node = node[sibling]){
                                    if(node[checkName] === checkValue){
                                        pid = dom.getUid(node);
                                        cache[pid] = count++;
                                    }
                                }
                            }
                            diff = cache[dom.getUid(el)] - b;
                            found =  a === 0 ? diff === 0 : (diff % a === 0 && diff / a >= 0 );
                            (found ^ flag_not) && (result[ri++] = el);
                        }
                        return  result;
                    }
                };
            };
            function filterPseudoNoExp(name, isLast, isOnly) {
                var A = "var result = [], flag_not = flags.not, node, el, tagName, i = 0, ri = 0, found = 0; for (; node = el = lastResult[i++];found = 0) {"
                var B = "{0} while (!found && (node=node.{1})) { (node.{2} === {3})  && ++found;  }";
                var C = " node = el;while (!found && (node = node.previousSibling)) {  node.{2} === {3} && ++found;  }";
                var D =  "!found ^ flag_not && (result[ri++] = el);  }   return result";
    
                var start = isLast ? "nextSibling" : "previousSibling";
                var fills = {
                    type: [" tagName = el.nodeName;", start, "nodeName", "tagName"],
                    child: ["", start, "nodeType", "1"]
                }
                [name];
                var body = A+B+(isOnly ? C: "")+D;
                var fn = new Function("flags","lastResult",body.replace(/{(\d)}/g, function ($, $1) {
                    return fills[$1];
                }));
                return {
                    exec:fn
                }
            }
    
            function filterProp(str_prop, flag) {
                return {
                    exec: function (flags, elems) {
                        var result = [], prop = str_prop, flag_not = flag ? flags.not : !flags.not;
                        for (var i = 0,ri = 0, elem; elem = elems[i++];)
                            if ( elem[prop] ^ flag_not)
                                result[ri++] = elem;//&& ( !flag || elem.type !== "hidden" )
                        return result;
                    }
                };
            };
            Icarus.pseudoAdapter = {
                root: function (el) {//  
                    return el === (el.ownerDocument || el.document).documentElement;
                },
                target: {//  
                    exec: function (flags, elems,_,doc) {
                        var result = [], flag_not = flags.not;
                        var win = doc.defaultView || doc.parentWindow;
                        var hash = win.location.hash.slice(1);       
                        for (var i = 0,ri = 0, elem; elem = elems[i++];)
                            if (((elem.id || elem.name) === hash) ^ flag_not)
                                result[ri++] = elem;
                        return result;
                    }
                },
                "first-child"    : filterPseudoNoExp("child", false, false),
                "last-child"     : filterPseudoNoExp("child", true,  false),
                "only-child"     : filterPseudoNoExp("child", true,  true),
                "first-of-type"  : filterPseudoNoExp("type",  false, false),
                "last-of-type"   : filterPseudoNoExp("type",  true,  false),
                "only-of-type"   : filterPseudoNoExp("type",  true,  true),//name, isLast, isOnly
                "nth-child"       : filterPseudoHasExp("firstChild", "nextSibling",     false),//  
                "nth-last-child"  : filterPseudoHasExp("lastChild",  "previousSibling", false),//  
                "nth-of-type"     : filterPseudoHasExp("firstChild", "nextSibling",     true),//  
                "nth-last-of-type": filterPseudoHasExp("lastChild",  "previousSibling", true),//  
                empty: {//  
                    exec: function (flags, elems) {   
                        var result = [], flag_not = flags.not, check
                        for (var i = 0, ri = 0, elem; elem = elems[i++];) {
                            if(elem.nodeType == 1){
                                if (!elem.firstChild ^ flag_not)
                                    result[ri++] = elem;
                            }
                        }
                        return result;
                    }
                },
                link: {//  
                    exec: function (flags, elems) {
                        var links = (elems[0].ownerDocument || elems[0].document).links;
                        if (!links) return [];
                        var result = [],
                        checked = {},
                        flag_not = flags.not;
                        for (var i = 0, ri = 0,elem; elem = links[i++];)
                            checked[dom.getUid(elem) ] = 1;
                        for (i = 0; elem = elems[i++]; )
                            if (checked[dom.getUid(elem)] ^ flag_not)
                                result[ri++] = elem;
                        return result;
                    }
                },
                lang: {//   CSS2    
                    exec: function (flags, elems, arg) {
                        var result = [], reg = new RegExp("^" + arg, "i"), flag_not = flags.not;
                        for (var i = 0, ri = 0, elem; elem = elems[i++]; ){
                            var tmp = elem;
                            while (tmp && !tmp.getAttribute("lang"))
                                tmp = tmp.parentNode;
                            tmp = !!(tmp && reg.test(tmp.getAttribute("lang")));
                            if (tmp ^ flag_not)
                                result[ri++] = elem;
                        }
                        return result;
                    }
                },
                active: function(el){
                    return el === el.ownerDocument.activeElement;
                },
                focus:function(el){
                    return (el.type|| el.href) && el === el.ownerDocument.activeElement;
                },
                indeterminate : function(node){//  
                    return node.indeterminate === true && node.type === "checkbox"
                },
                //http://www.w3.org/TR/css3-selectors/#UIstates
                enabled:  filterProp("disabled", false),//  
                disabled: filterProp("disabled", true),//  
                checked:  filterProp("checked", true),//  
                contains: {
                    exec: function (flags, elems, arg) {
                        var res = [], elem = elems[0], fn = flags.xml ? dom.getText: getHTMLText,
                        flag_not = flags.not;
                        for (var i = 0, ri = 0, elem; elem = elems[i++]; ){
                            if ((!!~fn( [elem] ).indexOf(arg)) ^ flag_not)
                                res[ri++] = elem;
                        }
                        return res;
                    }
                },
                //     
                selected : function(el){
                    el.parentNode.selectedIndex;//  safari bug
                    return el.selected === true;
                },
                header : function(el){
                    return /h\d/i.test( el.nodeName );
                },
                button : function(el){
                    return "button" === el.type || el.nodeName === "BUTTON";
                },
                input: function(el){
                    return /input|select|textarea|button/i.test(el.nodeName);
                },
                parent : function( el ) {
                    return !!el.firstChild;
                },
                has : function(el, expr){//         expr   
                    return !!dom.query(expr,[el]).length;
                },
                //         
                first: function(index){
                    return index === 0;
                },
                last: function(index, num){
                    return index === num;
                },
                even: function(index){
                    return index % 2 === 0;
                },
                odd: function(index){
                    return index % 2 === 1;
                },
                lt: function(index, num){
                    return index < num;
                },
                gt: function(index, num){
                    return index > num;
                },
                eq: function(index, num){
                    return index ===  num;
                },
                hidden : function( el ) {
                    return el.type === "hidden" || (!el.offsetWidth && !el.offsetHeight) || (el.currentStyle && el.currentStyle.display === "none") ;
                }
            }
            Icarus.pseudoAdapter.visible = function(el){
                return  !Icarus.pseudoAdapter.hidden(el);
            }
    
            "text,radio,checkbox,file,password,submit,image,reset".replace(dom.rword, function(name){
                Icarus.pseudoAdapter[name] = function(el){
                    return (el.getAttribute("type") || el.type) === name;//  HTML5       BUG,     el.type === name;
                }
            });
           
        });
    
    })(this,this.document);
    //2011.10.25  dom.unique
    //2011.10.26     name  id           ,  labed  ,              
    //2011.10.30                         , ‘input[name=brackets\\[5\\]\\[\\]]’
    //2011.10.31              ,  hasAttribute              ,   checked, selected, disabled     
    //2011.10.31         ,          switch   
    //2011.11.1                 filterPseudoHasExp filterPseudoNoExp
    //2011.11.2 FIX   -of-type   BUG
    //2011.11.3   getAttribute hasAttribute API
    //2011.11.4                          
    //2011.11.5   getElementsByXpath    XML   
    //2011.11.6   getElementsByTagName         tagName
    //2011.11.6   IE67 opera9 getElementById  BUG
    //2011.11.7       , IE678         ,  querySelectorAll   
    //2011.11.8     nth-child   BUG,  IE67 getAttribute input[type=search]   ,  sortOrder        
    //  swich...case         ,  reg_sequence    "[  "   ,       ,    default
    //       $=   ,  attr.indexOf(val) == attr.length - val.length,   "PWD".indexOf("bar]")  true
    //2011.11.9   getText    getElementById   ID  
    //2011.11.10 exec    match, parseNth       
    
    
    
    

    以下はIcarusのネーミングスペースのサポートプレゼンテーションです.例はinline SVGです.IE 9はサポートされていませんので、高バージョンの標準ブラウザで見てください.IE 10がSVGをサポートすると、SVGのアプリケーションが大幅に増加するため、ネーミングスペースのサポートが必要になります.
    
    
     <html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 
            <head>
                <title>icarus svg by     </title>
                <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
                <script src="http://files.cnblogs.com/rubylouvre/icarus.js"></script>
                <script>
                
                    window.onload = function(){
                        alert(dom.query("svg\\:feOffset:first")[0].tagName)
                    }
                </script>
            </head>
            <body>
            <svg:svg height="0">
                <!-- Create the filter. Make sure it uses the sRGB colorspace or you're in for some nasty surprises. -->
                <svg:filter color-interpolation-filters="sRGB" id="perspDisp" filterUnits="userSpaceOnUse" x="0%" y="0%" width="512" height="512"  >
                    <!-- Move the video 128px to the bottom/right so that the displacement filter can reach 128px to the top/left without reaching beyond the image -->
                    <svg:feOffset
                        x="128" y="128" width="256" height="256"
                        dx="128" dy="128"
                        result="displacement"
                        />
                    <!-- This actually loads our texture-->
                    <svg:feImage
                        id="textureLoader"
                        x="0" y="0" width="256" height="256"
                        xlink:href="texture.tinman.png"
                        />
                    <!-- Tile the texture to fill the whole viewport so that the displacement filter can also reach 128px to the bottom/right without leaving the texture -->
                    <svg:feTile
                        x="0" y="0" width="512" height="512"
                        result="texture"
                        />
                    <!-- Apply the displacement -->
                    <svg:feDisplacementMap
                        x="128" y="128" width="256" height="256"
                        in="texture"  in2="displacement"
                        scale="255"
                        xChannelSelector="R" yChannelSelector="G"
                        />
                    <!-- Apply the alpha of the displacement map to the final image, so that whatever is transparent in the map is also transparent in the final image -->
                    <svg:feComposite
                        in2="displacement"
                        operator="in"
                        />
                    <!-- Move the image back to the top/left -->
                    <svg:feOffset
                        x="0" y="0" width="256" height="256"
                        dx="-128" dy="-128"
                        />
                </svg:filter>
            </svg:svg>
    
    
        </body>
    </html>
    
    




    icarus svg by司徒正美



    window.onload = function(){
    alert(dom.query("svg\\:feOffset:first")[0].tagName)
    }







    x="128"y="128"width="256"height="256"
    dx="128"dy="128"
    result="displacement"
    />

    id="textureLoader"
    x="0"y="0"width="256"height="256"
    xlink:href="texture.tinman.png"
    />

    x="0"y="0"width="512"height="512"
    result="texture"
    />

    x="128"y="128"width="256"height="256"
    in="texture" in2="displacement"
    scale="255"
    xChannelSelector="R"yChannelSelector="G"
    />

    in2="displacement"
    operator="in"
    />

    x="0"y="0"width="256"height="256"
    dx="-128"dy="-128"
    />




    実行コード
    後にjavascriptのセレクタは基本的にIE 678(IE 8のquerySelectoAllサポートの種類が少なすぎる)と互換性があるため、以降のセレクタは基本的にquerySelectorAllとevaluateとmatchesSelectorで書かれており、CSS 4もすぐに到来し、より多くの擬似クラスをもたらすため、jQueryのカスタム擬似クラスはほとんど存在しない必要がある.
    関連リンク:
    第1世代セレクタ
    第2世代セレクタ
    第3世代セレクタ
    第4世代セレクタ
    スピード?ゲーム