From 30a230c8894b87a16e3e836d5b59a949129b24ad Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Thu, 27 May 2010 22:53:34 +0000 Subject: [PATCH] added a pure javascript selector engine based in Sizzle, replaced EngineJS by EngineSizzle in gwt.xml, added tests units for dinamic and compiled selectors. --- .../java/com/google/gwt/query/Query.gwt.xml | 15 +- .../com/google/gwt/query/client/Function.java | 2 +- .../query/client/impl/SelectorEngineJS.java | 7 +- .../client/impl/SelectorEngineSizzle.java | 748 ++++++ .../client/impl/SelectorEngineXPath.java | 18 +- .../gwt/query/client/GQuerySelectorsTest.java | 2161 ++++++++++++++++- 6 files changed, 2897 insertions(+), 54 deletions(-) create mode 100644 gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineSizzle.java diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml b/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml index bf41a26d..bd9a76c3 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml +++ b/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml @@ -63,24 +63,11 @@ - + - - - - - - - - - - - diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Function.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Function.java index 333e537b..005b9d2a 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/Function.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Function.java @@ -52,7 +52,7 @@ public abstract class Function { * Override this method for bound event handlers. */ public boolean f(Event e) { - f(e.getCurrentTarget()); + f((Element)e.getCurrentEventTarget().cast()); return true; } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineJS.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineJS.java index b18c2759..a0788fba 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineJS.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineJS.java @@ -323,14 +323,14 @@ public class SelectorEngineJS extends SelectorEngineImpl { for (int r = 0, rlen = matchingElms.size(); r < rlen; r++) { Element current = matchingElms.getElement(r); boolean addElm = false; - for (int s = 0, sl = regExpAttributes.length, attributeRegExp; + for (int s = 0, sl = regExpAttributes.length; s < sl; s++) { addElm = false; - Regexp attributeRegExp2 = regExpAttributes[s]; + Regexp attributeRegexp = regExpAttributes[s]; String currentAttr = getAttr(current, regExpAttributesStr[s]); if (SelectorEngine.truth(currentAttr) && currentAttr.length() != 0) { - if (attributeRegExp2 == null || attributeRegExp2 + if (attributeRegexp == null || attributeRegexp .test(currentAttr)) { addElm = true; } @@ -427,7 +427,6 @@ public class SelectorEngineJS extends SelectorEngineImpl { JSArray prevParents = JSArray.create(); boolean previousDir = pseudoClass.startsWith("first") ? true : false; JSArray matchingElms = JSArray.create(); - Node prev, next, previous; if (SelectorEngine.eq("first-child", pseudoClass) || SelectorEngine .eq("last-child", pseudoClass)) { getFirstChildPseudo(previousMatch, previousDir, matchingElms); diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineSizzle.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineSizzle.java new file mode 100644 index 00000000..3149f3be --- /dev/null +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineSizzle.java @@ -0,0 +1,748 @@ +/* + * Copyright 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.query.client.impl; + +import java.util.HashSet; + +import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.core.client.JsArray; +import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.Node; +import com.google.gwt.dom.client.NodeList; + +/** + * Pure Javascript Selector Engine Implementation based on + * Sizzle CSS Selector Engine v1.0. + */ +public class SelectorEngineSizzle extends SelectorEngineImpl { + + public static native boolean contains(Object a, Object b) /*-{ + var ret = + document.compareDocumentPosition ? + (a.compareDocumentPosition(b) & 16): + a !== b && (a.contains ? a.contains(b) : true); + return ret ? true : false; + }-*/; + + public static native JavaScriptObject createExpr() /*-{ + var done = 0; + $wnd.Expr = { + order: [ "ID", "NAME", "TAG" ], + match: { + ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/, + CHUNKER: /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g + }, + leftMatch: {}, + attrMap: { + "class": "className", + "for": "htmlFor" + }, + attrHandle: { + href: function(elem){ + return elem.getAttribute("href"); + } + }, + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !/\W/.test(part), + isPartStrNotTag = isPartStr && !isTag; + if ( isTag ) { + part = part.toLowerCase(); + } + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + if ( isPartStrNotTag ) { + @com.google.gwt.query.client.impl.SelectorEngineSizzle::filter(Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;ZLjava/lang/Object;)( part, checkSet, true ); + } + }, + ">": function(checkSet, part){ + var isPartStr = typeof part === "string"; + if ( isPartStr && !/\W/.test(part) ) { + part = part.toLowerCase(); + + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + } else { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + if ( isPartStr ) { + @com.google.gwt.query.client.impl.SelectorEngineSizzle::filter(Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;ZLjava/lang/Object;)( part, checkSet, true ); + } + } + }, + "": function(checkSet, part){ + var doneName = done++; + if ( typeof part === "string" && !/\W/.test(part) ) { + checkFn = $wnd.dirNodeCheck; + @com.google.gwt.query.client.impl.SelectorEngineSizzle::dirNodeCheck(Ljava/lang/String;Ljava/lang/Object;ILjava/lang/Object;)("parentNode", part, doneName, checkSet); + } else { + @com.google.gwt.query.client.impl.SelectorEngineSizzle::dirCheck(Ljava/lang/String;Ljava/lang/Object;ILjava/lang/Object;)("parentNode", part, doneName, checkSet); + } + }, + "~": function(checkSet, part){ + var doneName = done++; + if ( typeof part === "string" && !/\W/.test(part) ) { + @com.google.gwt.query.client.impl.SelectorEngineSizzle::dirNodeCheck(Ljava/lang/String;Ljava/lang/Object;ILjava/lang/Object;)("previousSibling", part, doneName, checkSet); + } else { + @com.google.gwt.query.client.impl.SelectorEngineSizzle::dirCheck(Ljava/lang/String;Ljava/lang/Object;ILjava/lang/Object;)("previousSibling", part, doneName, checkSet); + } + } + }, + find: { + ID: function(match, context){ + if ( typeof context.getElementById !== "undefined") { + var m = context.getElementById(match[1]); + return m ? [m] : []; + } + }, + NAME: function(match, context){ + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], results = context.getElementsByName(match[1]); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + return ret.length === 0 ? null : ret; + } + }, + TAG: function(match, context){ + return context.getElementsByTagName(match[1]); + } + }, + preFilter: { + CLASS: function(match, curLoop, inplace, result, not){ + match = " " + match[1].replace(/\\/g, "") + " "; + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + return false; + }, + ID: function(match){ + return match[1].replace(/\\/g, ""); + }, + TAG: function(match, curLoop){ + return match[1].toLowerCase(); + }, + CHILD: function(match){ + if ( match[1] === "nth" ) { + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + match[0] = done++; + return match; + }, + ATTR: function(match, curLoop, inplace, result, not){ + var name = match[1].replace(/\\/g, ""); + if ($wnd.Expr.attrMap[name] ) { + match[1] = $wnd.Expr.attrMap[name]; + } + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + return match; + }, + PSEUDO: function(match, curLoop, inplace, result, not){ + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( $wnd.Expr.match.CHUNKER.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = @com.google.gwt.query.client.impl.SelectorEngineSizzle::select(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;Lcom/google/gwt/core/client/JsArray;Lcom/google/gwt/core/client/JsArray;)(match[3], null, null, curLoop); + } else { + var ret = @com.google.gwt.query.client.impl.SelectorEngineSizzle::filter(Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;ZLjava/lang/Object;)(match[3], curLoop, inplace, true ^ not); + if ( !inplace ) { + result.push.apply( result, ret ); + } + return false; + } + } else if ( $wnd.Expr.match.POS.test( match[0] ) || $wnd.Expr.match.CHILD.test( match[0] ) ) { + return true; + } + return match; + }, + POS: function(match){ + match.unshift( true ); + return match; + } + }, + filters: { + enabled: function(elem){ + return elem.disabled === false && elem.type !== "hidden"; + }, + disabled: function(elem){ + return elem.disabled === true; + }, + checked: function(elem){ + return elem.checked === true; + }, + selected: function(elem){ + // Accessing this property makes selected-by-default + // options in Safari work properly + elem.parentNode.selectedIndex; + return elem.selected === true; + }, + parent: function(elem){ + return !!elem.firstChild; + }, + empty: function(elem){ + return !elem.firstChild; + }, + has: function(elem, i, match){ + return !!@com.google.gwt.query.client.impl.SelectorEngineSizzle::select(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;Lcom/google/gwt/core/client/JsArray;Lcom/google/gwt/core/client/JsArray;)(match[3], elem, null, null).length; + }, + header: function(elem){ + return /h\d/i.test( elem.nodeName ); + }, + text: function(elem){ + return "text" === elem.type; + }, + radio: function(elem){ + return "radio" === elem.type; + }, + checkbox: function(elem){ + return "checkbox" === elem.type; + }, + file: function(elem){ + return "file" === elem.type; + }, + password: function(elem){ + return "password" === elem.type; + }, + submit: function(elem){ + return "submit" === elem.type; + }, + image: function(elem){ + return "image" === elem.type; + }, + reset: function(elem){ + return "reset" === elem.type; + }, + button: function(elem){ + return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; + }, + input: function(elem){ + return /input|select|textarea|button/i.test(elem.nodeName); + } + }, + setFilters: { + first: function(elem, i){ + return i === 0; + }, + last: function(elem, i, match, array){ + return i === array.length - 1; + }, + even: function(elem, i){ + return i % 2 === 0; + }, + odd: function(elem, i){ + return i % 2 === 1; + }, + lt: function(elem, i, match){ + return i < match[3] - 0; + }, + gt: function(elem, i, match){ + return i > match[3] - 0; + }, + nth: function(elem, i, match){ + return match[3] - 0 === i; + }, + eq: function(elem, i, match){ + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function(elem, match, i, array){ + var name = match[1], filter = $wnd.Expr.filters[ name ]; + if ( filter ) { + return filter( elem, i, match, array ); + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || @com.google.gwt.query.client.impl.SelectorEngineSizzle::getText(Ljava/lang/Object;)([ elem ]) || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { + var not = match[3]; + + for ( var i = 0, l = not.length; i < l; i++ ) { + if ( not[i] === elem ) { + return false; + } + } + return true; + } else { + @com.google.gwt.query.client.impl.SelectorEngineSizzle::error(Ljava/lang/String;)("Syntax error, unrecognized expression: " + name); + } + }, + CHILD: function(elem, match){ + var type = match[1], node = elem; + switch (type) { + case 'only': + case 'first': + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + if ( type === "first" ) { + return true; + } + node = elem; + case 'last': + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + return true; + case 'nth': + var first = match[2], last = match[3]; + if ( first === 1 && last === 0 ) { + return true; + } + var doneName = match[0], + parent = elem.parentNode; + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + parent.sizcache = doneName; + } + var diff = elem.nodeIndex - last; + if ( first === 0 ) { + return diff === 0; + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + ID: function(elem, match){ + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + TAG: function(elem, match){ + return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; + }, + CLASS: function(elem, match){ + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + ATTR: function(elem, match){ + var name = match[1], + result = $wnd.Expr.attrHandle[ name ] ? + $wnd.Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + POS: function(elem, match, i, array){ + var name = match[2], filter = $wnd.Expr.setFilters[ name ]; + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } + }; + + for ( var type in $wnd.Expr.match ) { + $wnd.Expr.match[ type ] = new RegExp( $wnd.Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); + $wnd.Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + $wnd.Expr.match[ type ].source.replace(/\\(\d+)/g, function(all, num){ + return "\\" + (num - 0 + 1); + })); + } + + return $wnd.Expr; + }-*/; + + public static native void dirCheck(String dir, Object cur, int doneName, Object checkSet) /*-{ + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + elem = elem[dir]; + var match = false; + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + if ( elem.nodeType === 1 ) { + elem.sizcache = doneName; + elem.sizset = i; + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + } else if ( @com.google.gwt.query.client.impl.SelectorEngineSizzle::filter(Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;ZLjava/lang/Object;)( cur, [elem], false ).length > 0 ) { + match = elem; + break; + } + } + elem = elem[dir]; + } + checkSet[i] = match; + } + } + }-*/; + + public static native void dirNodeCheck(String dir, Object cur, int doneName, Object checkSet) /*-{ + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + elem = elem[dir]; + var match = false; + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + if ( elem.nodeType === 1){ + elem.sizcache = doneName; + elem.sizset = i; + } + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + elem = elem[dir]; + } + checkSet[i] = match; + } + } + }-*/; + + public static void error(String msg) { + throw new IllegalArgumentException("Syntax error, unrecognized expression: " + msg); + } + + public static native JsArray filter(String expr, JsArray set, boolean inplace, Object not) /*-{ + var old = expr, result = [], curLoop = set, match, anyFound; + while ( expr && set.length ) { + for ( var type in $wnd.Expr.filter ) { + if ( (match = $wnd.Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + var filter = $wnd.Expr.filter[ type ], found, item, left = match[1]; + anyFound = false; + match.splice(1,1); + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + if ( curLoop === result ) { + result = []; + } + if ( $wnd.Expr.preFilter[ type ] ) { + match = $wnd.Expr.preFilter[ type ]( match, curLoop, inplace, result, not); + if ( !match ) { + anyFound = found = true; + } else if ( match === true ) { + continue; + } + } + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + } else { + curLoop[i] = false; + } + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + expr = expr.replace( $wnd.Expr.match[ type ], "" ); + if ( !anyFound ) { + return []; + } + break; + } + } + } + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + @com.google.gwt.query.client.impl.SelectorEngineSizzle::error(Ljava/lang/String;)(expr); + } else { + break; + } + } + old = expr; + } + return curLoop; + }-*/; + + public static native JavaScriptObject find(String expr, Node context) /*-{ + var set, match; + if ( !expr ) { + return []; + } + for ( var i = 0, l = $wnd.Expr.order.length; i < l; i++ ) { + var type = $wnd.Expr.order[i], match; + + if ( (match = $wnd.Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice(1,1); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace(/\\/g, ""); + set = $wnd.Expr.find[ type ]( match, context); + if ( set != null ) { + expr = expr.replace( $wnd.Expr.match[ type ], "" ); + break; + } + } + } + } + if ( !set ) { + set = context.getElementsByTagName("*"); + } + return {set: set, expr: expr}; + }-*/; + + public static native String getText(Object elems) /*-{ + var ret = "", elem; + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += @com.google.gwt.query.client.impl.SelectorEngineSizzle::getText(Ljava/lang/Object;)(elem.childNodes); + } + } + return ret; + }-*/; + + public static native JsArray makeArray(NodeList array, JsArray results) /*-{ + var ret = results || []; + if ( Object.prototype.toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + } else { + if ( typeof array.length === "number" ) { + for ( var i = 0, l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + } else { + for ( var i = 0; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + return ret; + }-*/; + + public static native JsArray posProcess(String selector, Node context) /*-{ + var tmpSet = [], later = "", match, root = context.nodeType ? [context] : context; + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = $wnd.Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace($wnd.Expr.match.PSEUDO, "" ); + } + selector = $wnd.Expr.relative[selector] ? selector + "*" : selector; + for ( var i = 0, l = root.length; i < l; i++ ) { + @com.google.gwt.query.client.impl.SelectorEngineSizzle::select(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;Lcom/google/gwt/core/client/JsArray;Lcom/google/gwt/core/client/JsArray;)(selector, root[i], tmpSet, null); + } + return @com.google.gwt.query.client.impl.SelectorEngineSizzle::filter(Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;ZLjava/lang/Object;)( later, tmpSet, false ); + }-*/; + + public static JsArray unique(JsArray a) { + JsArray ret = JavaScriptObject.createArray().cast(); + HashSet f = new HashSet(); + for (int i = 0; i < a.length(); i++) { + Element e = a.get(i); + if (!f.contains(e.hashCode())) { + f.add(e.hashCode()); + ret.push(e); + } + } + return ret; + } + + private static native JsArray select(String selector, Node context, JsArray results, JsArray seed) /*-{ + results = results || []; + var origContext = context = context || document; + var parts = [], m, set, checkSet, extra, prune = true, soFar = selector; + // Reset the position of the chunker regexp (start from head) + while ( ($wnd.Expr.match.CHUNKER.exec(""), m = $wnd.Expr.match.CHUNKER.exec(soFar)) !== null ) { + soFar = m[3]; + parts.push( m[1] ); + if ( m[2] ) { + extra = m[3]; + break; + } + } + if ( parts.length > 1 && $wnd.Expr.match.POS.exec( selector ) ) { + if ( parts.length === 2 && $wnd.Expr.relative[ parts[0] ] ) { + set = @com.google.gwt.query.client.impl.SelectorEngineSizzle::posProcess(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;)(parts[0] + parts[1], context); + } else { + set = $wnd.Expr.relative[ parts[0] ] ? + [ context ] : + @com.google.gwt.query.client.impl.SelectorEngineSizzle::select(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;Lcom/google/gwt/core/client/JsArray;Lcom/google/gwt/core/client/JsArray;)(parts.shift(), context, null, null); + while ( parts.length ) { + selector = parts.shift(); + if ( $wnd.Expr.relative[ selector ] ) { + selector += parts.shift(); + } + set = @com.google.gwt.query.client.impl.SelectorEngineSizzle::posProcess(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;)(selector, set); + } + } + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && + $wnd.Expr.match.ID.test(parts[0]) && !$wnd.Expr.match.ID.test(parts[parts.length - 1]) ) { + var ret = @com.google.gwt.query.client.impl.SelectorEngineSizzle::find(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;)( parts.shift(), context); + context = ret.expr ? @com.google.gwt.query.client.impl.SelectorEngineSizzle::filter(Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;ZLjava/lang/Object;)( ret.expr, ret.set, false )[0] : ret.set[0]; + } + if ( context ) { + var ret = seed ? + { expr: parts.pop(), set: @com.google.gwt.query.client.impl.SelectorEngineSizzle::makeArray(Lcom/google/gwt/dom/client/NodeList;Lcom/google/gwt/core/client/JsArray;)(seed, null) } : + @com.google.gwt.query.client.impl.SelectorEngineSizzle::find(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;)( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context); + set = ret.expr ? @com.google.gwt.query.client.impl.SelectorEngineSizzle::filter(Ljava/lang/String;Lcom/google/gwt/core/client/JsArray;ZLjava/lang/Object;)( ret.expr, ret.set, false ) : ret.set; + if ( parts.length > 0 ) { + checkSet = @com.google.gwt.query.client.impl.SelectorEngineSizzle::makeArray(Lcom/google/gwt/dom/client/NodeList;Lcom/google/gwt/core/client/JsArray;)(set, null); + } else { + prune = false; + } + while ( parts.length ) { + var cur = parts.pop(), pop = cur; + if ( !$wnd.Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + if ( pop == null ) { + pop = context; + } + $wnd.Expr.relative[ cur ]( checkSet, pop); + } + } else { + checkSet = parts = []; + } + } + if ( !checkSet ) { + checkSet = set; + } + if ( !checkSet ) { + @com.google.gwt.query.client.impl.SelectorEngineSizzle::error(Ljava/lang/String;)(cur || selector); + } + if ( Object.prototype.toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + } else if ( context && context.nodeType === 1 ) { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && @com.google.gwt.query.client.impl.SelectorEngineSizzle::contains(Ljava/lang/Object;Ljava/lang/Object;)(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + } else { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + } else { + @com.google.gwt.query.client.impl.SelectorEngineSizzle::makeArray(Lcom/google/gwt/dom/client/NodeList;Lcom/google/gwt/core/client/JsArray;)(checkSet, results); + } + if ( extra ) { + @com.google.gwt.query.client.impl.SelectorEngineSizzle::select(Ljava/lang/String;Lcom/google/gwt/dom/client/Node;Lcom/google/gwt/core/client/JsArray;Lcom/google/gwt/core/client/JsArray;)(extra, origContext, results, seed); + @com.google.gwt.query.client.impl.SelectorEngineSizzle::unique(Lcom/google/gwt/core/client/JsArray;)(results); + } + return results; + }-*/; + + public SelectorEngineSizzle() { + createExpr(); + } + + public NodeList select(String selector, Node context) { + JsArray results = JavaScriptObject.createArray().cast(); + return select(selector, context, results, null).cast(); + } +} diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineXPath.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineXPath.java index 0c2e9cc0..99cf50ef 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineXPath.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineXPath.java @@ -15,15 +15,15 @@ */ package com.google.gwt.query.client.impl; -import com.google.gwt.core.client.GWT; +import static com.google.gwt.query.client.SelectorEngine.eq; +import static com.google.gwt.query.client.SelectorEngine.truth; + import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Node; import com.google.gwt.dom.client.NodeList; import com.google.gwt.query.client.JSArray; import com.google.gwt.query.client.Regexp; import com.google.gwt.query.client.SelectorEngine; -import static com.google.gwt.query.client.SelectorEngine.eq; -import static com.google.gwt.query.client.SelectorEngine.truth; /** * Runtime selector engine implementation which translates selectors to XPath @@ -58,6 +58,8 @@ public class SelectorEngineXPath extends SelectorEngineImpl { private Regexp selectorSplitRegExp; private Regexp combinator; + + private SelectorEngineImpl jsEngine = null; public SelectorEngineXPath() { } @@ -115,7 +117,6 @@ public class SelectorEngineXPath extends SelectorEngineImpl { "[contains(concat(' ', @class, ' '), ' $1 ')]"); } if (truth(splitRule.allAttr)) { - GWT.log("AllAttr is " + splitRule.allAttr, null); xPathExpression += replaceAttr( SelectorEngine.or(splitRule.allAttr, "")); } @@ -139,7 +140,14 @@ public class SelectorEngineXPath extends SelectorEngineImpl { } } } - SelectorEngine.xpathEvaluate(xPathExpression, ctx, elm); + try { + SelectorEngine.xpathEvaluate(xPathExpression, ctx, elm).cast(); + } catch (Exception e) { + if (jsEngine == null) { + jsEngine = new SelectorEngineSizzle(); + } + return jsEngine.select(sel, ctx).cast(); + } } return elm; } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQuerySelectorsTest.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQuerySelectorsTest.java index 1d1f3c45..aabd8902 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQuerySelectorsTest.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQuerySelectorsTest.java @@ -18,21 +18,131 @@ package com.google.gwt.query.client; import static com.google.gwt.query.client.GQuery.$; import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Node; +import com.google.gwt.dom.client.NodeList; import com.google.gwt.junit.client.GWTTestCase; +import com.google.gwt.query.client.impl.SelectorEngineImpl; +import com.google.gwt.query.client.impl.SelectorEngineSizzle; +import com.google.gwt.query.client.impl.SelectorEngineXPath; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.RootPanel; +/** + * Test for selectors + */ public class GQuerySelectorsTest extends GWTTestCase { - public String getModuleName() { - return "com.google.gwt.query.Query"; + public interface AllSelectors extends Selectors { + // @Selector("h1[id]:contains(Selectors)") + // NodeList h1IdContainsSelectors(); + // @Selector("*:first") + // NodeList allFirst(); + // @Selector("div[class!=madeup]") + // NodeList divWithClassNotContainsMadeup(); + // @Selector("div, p a") + // NodeList divCommaPA(); + // @Selector("p:contains(selectors)") + // NodeList pContainsSelectors(); + @Selector("a[href][lang][class]") + NodeList aHrefLangClass(); + @Selector("*:checked") + NodeList allChecked(); + @Selector("body") + NodeList body(); + @Selector("body div") + NodeList bodyDiv(); + @Selector("div .example") + NodeList divExample(); + @Selector("div > div") + NodeList divGtP(); + @Selector("div:not(.example)") + NodeList divNotExample(); + @Selector("div p") + NodeList divP(); + @Selector("div p a") + NodeList divPA(); + @Selector("div + p") + NodeList divPlusP(); + @Selector("div[class^=exa][class$=mple]") + NodeList divPrefixExaSuffixMple(); + @Selector("div #title") + NodeList divSpaceTitle(); + @Selector("div ~ p") + NodeList divTildeP(); + @Selector("div[class]") + NodeList divWithClass(); + @Selector("div[class~=dialog]") + NodeList divWithClassContainsDialog(); + @Selector("div[class*=e]") + NodeList divWithClassContainsE(); + @Selector("div[class=example]") + NodeList divWithClassExample(); + @Selector("div[class~=dialog]") + NodeList divWithClassListContainsDialog(); + @Selector("div[class^=exa]") + NodeList divWithClassPrefixExa(); + @Selector("div[class$=mple]") + NodeList divWithClassSuffixMple(); + @Selector("p:first-child") + NodeList firstChild(); + @Selector("h1#title") + NodeList h1Title(); + @Selector("h1#title + em > span") + NodeList h1TitlePlusEmGtSpan(); + @Selector("p:last-child") + NodeList lastChild(); + @Selector(".note") + NodeList note(); + @Selector("p:nth-child(n)") + NodeList nthChild(); + @Selector("p:nth-child(2n)") + NodeList nThChild2n(); + @Selector("p:nth-child(2n+1)") + NodeList nThChild2nPlus1(); + @Selector("p:nth-child(even)") + NodeList nThChildEven(); + @Selector("p:nth-child(odd)") + NodeList nThChildOdd(); + @Selector("p:only-child") + NodeList onlyChild(); + @Selector("#title") + NodeList title(); + @Selector("#title,h1#title") + NodeList titleAndh1Title(); + @Selector("ul .tocline2") + NodeList ulTocline2(); + @Selector("ul.toc li.tocline2") + NodeList ulTocLiTocLine2(); + } + + public interface TestSelectors extends Selectors { + @Selector("*:checked") + public GQuery allChecked(); + @Selector("*:checked") + public GQuery allChecked(Node n); + @Selector(".branchA") + public GQuery branchA(); + @Selector(".branchA") + public GQuery branchA(Node n); + @Selector(".branchB") + public GQuery branchB(); + @Selector(".branchB") + public GQuery branchB(Node n); + @Selector(".target") + public GQuery target(); + @Selector(".target") + public GQuery target(Node n); } static Element e = null; static HTML testPanel = null; + public String getModuleName() { + return "com.google.gwt.query.Query"; + } + public void gwtSetUp() { if (e == null) { testPanel = new HTML(); @@ -44,52 +154,96 @@ public class GQuerySelectorsTest extends GWTTestCase { } } - public interface TestSelectors extends Selectors { - @Selector(".target") - public GQuery target(); + public void testAllSelectors() { + final AllSelectors sel = GWT.create(AllSelectors.class); + $(e).html(getTestContent()); - @Selector(".branchA") - public GQuery branchA(); + // TODO: fix these selectors + // sel.h1IdContainsSelectors().getLength() + // sel.allFirst().getLength() + // sel.divWithClassNotContainsMadeup().getLength() + // sel.divCommaPA().getLength() + // sel.pContainsSelectors().getLength() + // assertArrayContains(sel.title().getLength(), 1); - @Selector(".branchB") - public GQuery branchB(); - - @Selector(".target") - public GQuery target(Node n); + assertEquals(1, sel.body().getLength()); + assertEquals(53, sel.bodyDiv().getLength()); + sel.setRoot(e); + assertArrayContains(sel.aHrefLangClass().getLength(), 0, 1); + assertArrayContains(sel.allChecked().getLength(), 1); + assertArrayContains(sel.divExample().getLength(), 43); + assertArrayContains(sel.divGtP().getLength(), 51, 52); + assertArrayContains(sel.divNotExample().getLength(), 9, 10); + assertArrayContains(sel.divP().getLength(), 324); + assertArrayContains(sel.divPA().getLength(), 84); + assertArrayContains(sel.divPlusP().getLength(), 22); + assertArrayContains(sel.divPrefixExaSuffixMple().getLength(), 43); + assertArrayContains(sel.divSpaceTitle().getLength(), 1); + assertArrayContains(sel.divTildeP().getLength(), 183); + assertArrayContains(sel.divWithClass().getLength(), 51, 52); + assertArrayContains(sel.divWithClassContainsDialog().getLength(), 1); + assertArrayContains(sel.divWithClassContainsE().getLength(), 50); + assertArrayContains(sel.divWithClassExample().getLength(), 43); + assertArrayContains(sel.divWithClassListContainsDialog().getLength(), 1); + assertArrayContains(sel.divWithClassPrefixExa().getLength(), 43); + assertArrayContains(sel.divWithClassSuffixMple().getLength(), 43); + assertArrayContains(sel.firstChild().getLength(), 54); + assertArrayContains(sel.h1Title().getLength(), 1); + assertArrayContains(sel.h1TitlePlusEmGtSpan().getLength(), 1); + assertArrayContains(sel.lastChild().getLength(), 19); + assertArrayContains(sel.note().getLength(), 14); + assertArrayContains(sel.nthChild().getLength(), 324); + assertArrayContains(sel.nThChild2n().getLength(), 159); + assertArrayContains(sel.nThChild2nPlus1().getLength(), 165); + assertArrayContains(sel.nThChildEven().getLength(), 159); + assertArrayContains(sel.nThChildOdd().getLength(), 165); + assertArrayContains(sel.onlyChild().getLength(), 3); + assertArrayContains(sel.titleAndh1Title().getLength(), 0, 1); + assertArrayContains(sel.ulTocline2().getLength(), 12); + assertArrayContains(sel.ulTocLiTocLine2().getLength(), 12); + } - @Selector(".branchA") - public GQuery branchA(Node n); + public void testSelectorEngineDomAssistant() { + // This test runs very slow in chrome + // SelectorEngineImpl selEng = new SelectorEngineJS(); + // executeSelectorEngineTests(selEng); + } - @Selector(".branchB") - public GQuery branchB(Node n); - - @Selector("*:checked") - public GQuery allChecked(); - - @Selector("*:checked") - public GQuery allChecked(Node n); + public void testSelectorEngineSizzle() { + SelectorEngineImpl selEng = new SelectorEngineSizzle(); + executeSelectorEngineTests(selEng); } - + + public void testSelectorEngineXpath() { + SelectorEngineImpl selEng = new SelectorEngineXPath(); + executeSelectorEngineTests(selEng); + } + public void testSelectorsGeneratorNative() { - $(e).html( "1" - + "2"); - + $(e) + .html( + "1" + + "2"); + TestSelectors selectors = GWT.create(TestSelectors.class); assertEquals(1, selectors.allChecked().size()); } + public void testSelectorsWithContext() { - $(e).append("
branchA target
" - + "
branchB target
"); + $(e) + .append( + "
branchA target
" + + "
branchB target
"); TestSelectors selectors = GWT.create(TestSelectors.class); - + assertEquals(2, selectors.target().length()); Element branchA = selectors.branchA().get(0); Element branchB = selectors.branchB().get(0); assertNotNull(selectors.branchA().get(0)); assertNotNull(selectors.branchB().get(0)); - + assertEquals(2, selectors.target(RootPanel.getBodyElement()).length()); branchA = selectors.branchA(RootPanel.getBodyElement()).get(0); branchB = selectors.branchB(RootPanel.getBodyElement()).get(0); @@ -107,4 +261,1951 @@ public class GQuerySelectorsTest extends GWTTestCase { assertEquals("branchB target", selectors.target().text()); } + private void assertArrayContains(Object result, Object... array) { + assertArrayContains("", result, array); + } + private void assertArrayContains(String message, Object result, Object... array) { + String values = ""; + boolean done = false; + for (Object o : array) { + values += o.toString() + " "; + if (result.equals(o)){ + done = true; + } + } + message = message + ", value (" + result + ") not found in: " + values; + assertTrue(message, done); + } + + private void executeSelectorEngineTests(SelectorEngineImpl selEng) { + $(e).html(getTestContent()); + + assertArrayContains(selEng.select("body", Document.get()).getLength(), 1); + assertArrayContains(selEng.select("body div", Document.get()).getLength(), 53); + + assertArrayContains(selEng.select("h1[id]:contains(Selectors)", e).getLength(), 1); + assertArrayContains(selEng.select("*:first", e).getLength(), 1, 0); + assertArrayContains(selEng.select("div[class!=madeup]", e).getLength(), 52, 53); + assertArrayContains(selEng.select("div, p a", e).getLength(), 136, 137, 138); + assertArrayContains(selEng.select("p:contains(selectors)", e).getLength(), 54, 55); + assertArrayContains(selEng.select("a[href][lang][class]", e).getLength(), 1); + assertArrayContains(selEng.select("*:checked", e).getLength(), 1); + assertArrayContains(selEng.select("div .example", e).getLength(), 43); + assertArrayContains(selEng.select("div > div", e).getLength(), 51); + assertArrayContains(selEng.select("div:not(.example)", e).getLength(), 9, 10); + assertArrayContains(selEng.select("div p", e).getLength(), 324); + assertArrayContains(selEng.select("div p a", e).getLength(), 85, 84); + assertArrayContains(selEng.select("div + p", e).getLength(), 22); + assertArrayContains(selEng.select("div[class^=exa][class$=mple]", e).getLength(), 43); + assertArrayContains(selEng.select("div #title", e).getLength(), 1); + assertArrayContains(selEng.select("div ~ p", e).getLength(), 183); + assertArrayContains(selEng.select("div[class]", e).getLength(), 51, 52); + assertArrayContains(selEng.select("div[class~=dialog]", e).getLength(), 1); + assertArrayContains(selEng.select("div[class*=e]", e).getLength(), 50); + assertArrayContains(selEng.select("div[class=example]", e).getLength(), 43); + assertArrayContains(selEng.select("div[class~=dialog]", e).getLength(), 1); + assertArrayContains(selEng.select("div[class^=exa]", e).getLength(), 43); + assertArrayContains(selEng.select("div[class$=mple]", e).getLength(), 43); + assertArrayContains(selEng.select("p:first-child", e).getLength(), 54); + assertArrayContains(selEng.select("h1#title", e).getLength(), 1); + assertArrayContains(selEng.select("h1#title + em > span", e).getLength(), 1); + assertArrayContains(selEng.select("p:last-child", e).getLength(), 19, 22); + assertArrayContains(selEng.select(".note", e).getLength(), 14); + assertArrayContains(selEng.select("p:nth-child(n)", e).getLength(), 324); + assertArrayContains(selEng.select("p:nth-child(2n)", e).getLength(), 159); + assertArrayContains(selEng.select("p:nth-child(2n+1)", e).getLength(), 165); + assertArrayContains(selEng.select("p:nth-child(even)", e).getLength(), 159); + assertArrayContains(selEng.select("p:nth-child(odd)", e).getLength(), 165); + assertArrayContains(selEng.select("p:only-child", e).getLength(), 3); + assertArrayContains(selEng.select("#title", e).getLength(), 1); + assertArrayContains(selEng.select("#title, h1#title", e).getLength(), 2); + assertArrayContains(selEng.select("ul.toc li.tocline2", e).getLength(), 12); + assertArrayContains(selEng.select("h1[id]:contains(Selectors)", e).getLength(), 1); + } + + // This method is used to initialize a huge html String, because + // java 1.5 has a limitation in the size of static strings. + private String getTestContent() { + String test_content = ""; + test_content += "
"; + test_content += "
"; + test_content += "

W3C

"; + test_content += "

Selectors

"; + test_content += " ."; + test_content += "

W3C Working Draft 15 December 2005

"; + test_content += "
"; + test_content += "
This version:
"; + test_content += "
"; + test_content += " http://www.w3.org/TR/2005/WD-css3-selectors-20051215
"; + test_content += "
Latest version:"; + test_content += "
"; + test_content += " http://www.w3.org/TR/css3-selectors"; + test_content += "
Previous version:"; + test_content += "
"; + test_content += " http://www.w3.org/TR/2001/CR-css3-selectors-20011113"; + test_content += "
Editors:"; + test_content += "
Daniel Glazman (Invited"; + test_content += "
"; + test_content += "
Tantek Çelik"; + test_content += "
Ian"; + test_content += " Hickson (Google)"; + test_content += "
Peter Linss (former"; + test_content += " editor, Netscape/AOL)"; + test_content += "
John Williams (former editor, Quark, Inc.)"; + test_content += "
"; + test_content += "
"; + test_content += "
"; + test_content += "

Abstract

"; + test_content += "

Selectors are patterns that match against elements in a"; + test_content += " tree. Selectors have been optimized for use with HTML and XML, and"; + test_content += " are designed to be usable in performance-critical code.

"; + test_content += "

CSS (Cascading"; + test_content += " Style Sheets) is a language for describing the rendering of HTML and XML documents on"; + test_content += " screen, on paper, in speech, etc. CSS uses Selectors for binding"; + test_content += " describes extensions to the selectors defined in CSS level 2. These"; + test_content += " extended selectors will be used by CSS level 3."; + test_content += "

Selectors define the following function:

"; + test_content += "
expression ∗ element → boolean
"; + test_content += "

That is, given an element and a selector, this specification"; + test_content += " defines whether that element matches the selector.

"; + test_content += "

These expressions can also be used, for instance, to select a set"; + test_content += " subtree. STTS (Simple Tree Transformation Sheets), a"; + test_content += " language for transforming XML trees, uses this mechanism. [STTS]

"; + test_content += "

Status of this document

"; + test_content += "

This section describes the status of this document at the"; + test_content += " of this technical report can be found in the W3C technical reports index at"; + test_content += " http://www.w3.org/TR/.

"; + test_content += "

This document describes the selectors that already exist in CSS1 and CSS2, and"; + test_content += " also proposes new selectors for CSS3 and other languages that may need them.

"; + test_content += "

The CSS Working Group doesn't expect that all implementations of"; + test_content += " CSS3 will have to implement all selectors. Instead, there will"; + test_content += " will include all of the selectors.

"; + test_content += "

This specification is a last call working draft for the the CSS Working Group"; + test_content += " (Style Activity). This"; + test_content += " document is a revision of the Candidate"; + test_content += " Recommendation dated 2001 November 13, and has incorporated"; + test_content += " be demonstrable.

"; + test_content += "

All persons are encouraged to review and implement this"; + test_content += " specification and return comments to the (archived)"; + test_content += " public mailing list www-style"; + test_content += " (see instructions). W3C"; + test_content += " The deadline for comments is 14 January 2006.

"; + test_content += "

This is still a draft document and may be updated, replaced, or"; + test_content += "

This document may be available in translation."; + test_content += "

"; + test_content += "

Table of contents

"; + test_content += " "; + test_content += "
"; + test_content += "

1. Introduction

"; + test_content += "

1.1. Dependencies

"; + test_content += "

Some features of this specification are specific to CSS, or have"; + test_content += " specification, these have been described in terms of CSS2.1. [CSS21]

"; + test_content += "

1.2. Terminology

"; + test_content += "

All of the text of this specification is normative except"; + test_content += " non-normative.

"; + test_content += "

1.3. Changes from CSS2

"; + test_content += "

This section is non-normative.

"; + test_content += "

The main differences between the selectors in CSS2 and those in"; + test_content += " Selectors are:"; + test_content += "

    "; + test_content += "
  • the list of basic definitions (selector, group of selectors,"; + test_content += " of simple selectors, and the term 'simple selector' is now used for"; + test_content += "
  • "; + test_content += "
  • an optional namespace component is now allowed in type element"; + test_content += " selectors, the universal selector and attribute selectors"; + test_content += "
  • "; + test_content += "
  • a new combinator has been"; + test_content += "
  • "; + test_content += "
  • new simple selectors including substring matching attribute"; + test_content += " selectors, and new pseudo-classes"; + test_content += "
  • "; + test_content += "
  • new pseudo-elements, and introduction of the '::' convention"; + test_content += "
  • "; + test_content += "
  • the grammar has been rewritten
  • "; + test_content += "
  • profiles to be added to specifications integrating Selectors"; + test_content += " and defining the set of selectors which is actually supported by"; + test_content += "
  • "; + test_content += "
  • Selectors are now a CSS3 Module and an independent"; + test_content += "
  • "; + test_content += "
  • the specification now has its own test suite
  • "; + test_content += "
"; + test_content += "

2. Selectors

"; + test_content += "

This section is non-normative, as it merely summarizes the"; + test_content += " following sections.

"; + test_content += "

A Selector represents a structure. This structure can be used as a"; + test_content += " HTML or XML fragment corresponding to that structure.

"; + test_content += "

Selectors may range from simple element names to rich contextual"; + test_content += " representations.

"; + test_content += "

The following table summarizes the Selector syntax:

"; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += "
PatternMeaningDescribed in sectionFirst defined in CSS level
*any elementUniversal"; + test_content += " selector2
Ean element of type EType selector1
E[foo]an E element with a 'foo' attributeAttribute"; + test_content += " selectors2
E[foo='bar']an E element whose 'foo' attribute value is exactly"; + test_content += " Attribute"; + test_content += " selectors2
E[foo~='bar']an E element whose 'foo' attribute value is a list of"; + test_content += " Attribute"; + test_content += " selectors2
E[foo^='bar']an E element whose 'foo' attribute value begins exactly"; + test_content += " Attribute"; + test_content += " selectors3
E[foo$='bar']an E element whose 'foo' attribute value ends exactly"; + test_content += " Attribute"; + test_content += " selectors3
E[foo*='bar']an E element whose 'foo' attribute value contains the"; + test_content += " Attribute"; + test_content += " selectors3
E[hreflang|='en']an E element whose 'hreflang' attribute has a"; + test_content += " Attribute"; + test_content += " selectors2
E:rootan E element, root of the documentStructural"; + test_content += " pseudo-classes3
E:nth-child(n)an E element, the n-th child of its parentStructural"; + test_content += " pseudo-classes3
E:nth-last-child(n)an E element, the n-th child of its parent, counting"; + test_content += " Structural"; + test_content += " pseudo-classes3
E:nth-of-type(n)an E element, the n-th sibling of its typeStructural"; + test_content += " pseudo-classes3
E:nth-last-of-type(n)an E element, the n-th sibling of its type, counting"; + test_content += " Structural"; + test_content += " pseudo-classes3
E:first-childan E element, first child of its parentStructural"; + test_content += " pseudo-classes2
E:last-childan E element, last child of its parentStructural"; + test_content += " pseudo-classes3
E:first-of-typean E element, first sibling of its typeStructural"; + test_content += " pseudo-classes3
E:last-of-typean E element, last sibling of its typeStructural"; + test_content += " pseudo-classes3
E:only-childan E element, only child of its parentStructural"; + test_content += " pseudo-classes3
E:only-of-typean E element, only sibling of its typeStructural"; + test_content += " pseudo-classes3
E:emptyan E element that has no children (including text"; + test_content += " Structural"; + test_content += " pseudo-classes3
E:link
E:visited
an E element being the source anchor of a hyperlink of"; + test_content += " The link"; + test_content += " pseudo-classes1
E:active
E:hover
E:focus
an E element during certain user actionsThe user"; + test_content += " action pseudo-classes1 and 2
E:targetan E element being the target of the referring URIThe target"; + test_content += " pseudo-class3
E:lang(fr)an element of type E in language 'fr' (the document"; + test_content += " The :lang()"; + test_content += " pseudo-class2
E:enabled
E:disabled
a user interface element E which is enabled or"; + test_content += " The UI element states"; + test_content += " pseudo-classes3
E:checkeda user interface element E which is checked (for instance a radio-button or checkbox)"; + test_content += " The UI element states"; + test_content += " pseudo-classes3
E::first-linethe first formatted line of an E elementThe ::first-line"; + test_content += " pseudo-element1
E::first-letterthe first formatted letter of an E elementThe ::first-letter"; + test_content += " pseudo-element1
E::selectionthe portion of an E element that is currently"; + test_content += " The UI element"; + test_content += " fragments pseudo-elements3
E::beforegenerated content before an E elementThe ::before"; + test_content += " pseudo-element2
E::aftergenerated content after an E elementThe ::after"; + test_content += " pseudo-element2
E.warningan E element whose class is"; + test_content += " Class"; + test_content += " selectors1
E#myidan E element with ID equal to 'myid'.ID"; + test_content += " selectors1
E:not(s)an E element that does not match simple selector sNegation"; + test_content += " pseudo-class3
E Fan F element descendant of an E elementDescendant"; + test_content += " combinator1
E > Fan F element child of an E elementChild"; + test_content += " combinator2
E + Fan F element immediately preceded by an E elementAdjacent sibling combinator"; + test_content += " 2
E ~ Fan F element preceded by an E elementGeneral sibling combinator"; + test_content += " 3
"; + test_content += "

The meaning of each selector is derived from the table above by"; + test_content += " column.

"; + test_content += "

3. Case sensitivity

"; + test_content += "

The case sensitivity of document language element names, attribute"; + test_content += " names, and attribute values in selectors depends on the document"; + test_content += " but in XML, they are case-sensitive.

"; + test_content += "

4. Selector syntax

"; + test_content += "

A selector is a chain of one"; + test_content += " or more sequences of simple selectors"; + test_content += " separated by combinators.

"; + test_content += "

A sequence of simple selectors"; + test_content += " is a chain of simple selectors"; + test_content += " that are not separated by a combinator. It"; + test_content += " always begins with a type selector or a"; + test_content += " universal selector. No other type"; + test_content += " selector or universal selector is allowed in the sequence.

"; + test_content += "

A simple selector is either a type selector, universal selector, attribute selector, class selector, ID selector, content selector, or pseudo-class. One pseudo-element may be appended to the last"; + test_content += " sequence of simple selectors.

"; + test_content += "

Combinators are: white space, 'greater-than"; + test_content += " sign' (U+003E, >), 'plus sign' (U+002B,"; + test_content += " +) and 'tilde' (U+007E, ~). White"; + test_content += " space may appear between a combinator and the simple selectors around"; + test_content += " it. Only the characters 'space' (U+0020), 'tab'"; + test_content += " never part of white space.

"; + test_content += "

The elements of a document tree that are represented by a selector"; + test_content += " are the subjects of the selector. A"; + test_content += " selector consisting of a single sequence of simple selectors"; + test_content += " sequence of simple selectors and a combinator to a sequence imposes"; + test_content += " simple selectors.

"; + test_content += "

An empty selector, containing no sequence of simple selectors and"; + test_content += " no pseudo-element, is an invalid"; + test_content += " selector.

"; + test_content += "

5. Groups of selectors

"; + test_content += "

When several selectors share the same declarations, they may be"; + test_content += " grouped into a comma-separated list. (A comma is U+002C.)

"; + test_content += "
"; + test_content += "

CSS examples:

"; + test_content += "

In this example, we condense three rules with identical"; + test_content += " declarations into one. Thus,

"; + test_content += "
h1 { font-family: sans-serif }";
+    test_content += "      h3 { font-family: sans-serif }
"; + test_content += "

is equivalent to:

"; + test_content += "
h1, h2, h3 { font-family: sans-serif }
"; + test_content += "
"; + test_content += "

Warning: the equivalence is true in this example"; + test_content += " because all the selectors are valid selectors. If just one of these"; + test_content += " selectors were invalid, the entire group of selectors would be"; + test_content += " heading rules would be invalidated.

"; + test_content += "

6. Simple selectors

"; + test_content += "

6.1. Type selector

"; + test_content += "

A type selector is the name of a document language"; + test_content += " type in the document tree.

"; + test_content += "
"; + test_content += "

Example:

"; + test_content += "

The following selector represents an h1 element in the"; + test_content += " document tree:

"; + test_content += "
h1
"; + test_content += "
"; + test_content += "

6.1.1. Type selectors and namespaces

"; + test_content += "

Type selectors allow an optional namespace ([XMLNAMES]) component. A namespace prefix"; + test_content += " (U+007C, |).

"; + test_content += "

The namespace component may be left empty to indicate that the"; + test_content += " selector is only to represent elements with no declared namespace.

"; + test_content += "

An asterisk may be used for the namespace prefix, indicating that"; + test_content += " with no namespace).

"; + test_content += "

Element type selectors that have no namespace component (no"; + test_content += " element's namespace (equivalent to '*|') unless a default"; + test_content += " namespace.

"; + test_content += "

A type selector containing a namespace prefix that has not been"; + test_content += " previously declared is an invalid selector."; + test_content += " language implementing Selectors. In CSS, such a mechanism is defined"; + test_content += " in the General Syntax module.

"; + test_content += "

In a namespace-aware client, element type selectors will only match"; + test_content += " against the local"; + test_content += " part"; + test_content += " of the element's qualified"; + test_content += " name. See below for notes about matching"; + test_content += " behaviors in down-level clients.

"; + test_content += "

In summary:

"; + test_content += "
"; + test_content += "
ns|E
"; + test_content += "
elements with name E in namespace ns
"; + test_content += "
*|E
"; + test_content += "
elements with name E in any namespace, including those without any"; + test_content += "
"; + test_content += "
|E
"; + test_content += "
elements with name E without any declared namespace
"; + test_content += "
E
"; + test_content += "
if no default namespace has been specified, this is equivalent to *|E."; + test_content += "
"; + test_content += "
"; + test_content += "
"; + test_content += "

CSS examples:

"; + test_content += "
@namespace foo url(http://www.example.com);";
+    test_content += "       h1 { color: green }
"; + test_content += "

The first rule will match only h1 elements in the"; + test_content += " 'http://www.example.com' namespace.

"; + test_content += "

The second rule will match all elements in the"; + test_content += " 'http://www.example.com' namespace.

"; + test_content += "

The third rule will match only h1 elements without"; + test_content += " any declared namespace.

"; + test_content += "

The fourth rule will match h1 elements in any"; + test_content += " namespace (including those without any declared namespace).

"; + test_content += "

The last rule is equivalent to the fourth rule because no default"; + test_content += " namespace has been defined.

"; + test_content += "
"; + test_content += "

6.2. Universal selector

"; + test_content += "

The universal selector, written 'asterisk'"; + test_content += " (*), represents the qualified name of any element"; + test_content += " specified, see Universal selector and"; + test_content += " Namespaces below.

"; + test_content += "

If the universal selector is not the only component of a sequence"; + test_content += " of simple selectors, the * may be omitted.

"; + test_content += "
"; + test_content += "

Examples:

"; + test_content += "
    "; + test_content += "
  • *[hreflang|=en] and [hreflang|=en] are"; + test_content += "
  • "; + test_content += "
  • *.warning and .warning are equivalent,"; + test_content += "
  • "; + test_content += "
  • *#myid and #myid are equivalent.
  • "; + test_content += "
"; + test_content += "
"; + test_content += "

Note: it is recommended that the"; + test_content += " *, representing the universal selector, not be"; + test_content += " omitted.

"; + test_content += "

6.2.1. Universal selector and namespaces

"; + test_content += "

The universal selector allows an optional namespace component. It"; + test_content += " is used as follows:

"; + test_content += "
"; + test_content += "
ns|*
"; + test_content += "
all elements in namespace ns
"; + test_content += "
*|*
"; + test_content += "
all elements
"; + test_content += "
|*
"; + test_content += "
all elements without any declared namespace
"; + test_content += "
*
"; + test_content += "
if no default namespace has been specified, this is equivalent to *|*."; + test_content += "
"; + test_content += "
"; + test_content += "

A universal selector containing a namespace prefix that has not"; + test_content += " been previously declared is an invalid"; + test_content += " to the language implementing Selectors. In CSS, such a mechanism is"; + test_content += " defined in the General Syntax module.

"; + test_content += "

6.3. Attribute selectors

"; + test_content += "

Selectors allow the representation of an element's attributes. When"; + test_content += " attribute selectors must be considered to match an element if that"; + test_content += " attribute selector.

"; + test_content += "

6.3.1. Attribute presence and values"; + test_content += " selectors

"; + test_content += "

CSS2 introduced four attribute selectors:

"; + test_content += "
"; + test_content += "
[att]"; + test_content += "
Represents an element with the att attribute, whatever the"; + test_content += "
"; + test_content += "
[att=val]
"; + test_content += "
Represents an element with the att attribute whose value is"; + test_content += "
"; + test_content += "
[att~=val]
"; + test_content += "
Represents an element with the att attribute whose value is"; + test_content += " a whitespace-separated list of words, one"; + test_content += " represent anything (since the words are separated by"; + test_content += "
"; + test_content += "
[att|=val]"; + test_content += "
Represents an element with the att attribute, its value"; + test_content += " matches (e.g., the hreflang attribute on the"; + test_content += " link element in HTML) as described in RFC 3066 ([RFC3066]). For lang (or"; + test_content += " xml:lang) language subcode matching, please see the :lang pseudo-class."; + test_content += "
"; + test_content += "
"; + test_content += "

Attribute values must be identifiers or strings. The"; + test_content += " case-sensitivity of attribute names and values in selectors depends on"; + test_content += " the document language.

"; + test_content += "
"; + test_content += "

Examples:

"; + test_content += "

The following attribute selector represents an h1"; + test_content += " element that carries the title attribute, whatever its"; + test_content += " value:

"; + test_content += "
h1[title]
"; + test_content += "

In the following example, the selector represents a"; + test_content += " span element whose class attribute has"; + test_content += " exactly the value 'example':

"; + test_content += "
span[class='example']
"; + test_content += "

Multiple attribute selectors can be used to represent several"; + test_content += " attribute. Here, the selector represents a span element"; + test_content += " whose hello attribute has exactly the value 'Cleveland'"; + test_content += " and whose goodbye attribute has exactly the value"; + test_content += " 'Columbus':

"; + test_content += "
span[hello='Cleveland'][goodbye='Columbus']
"; + test_content += "

The following selectors illustrate the differences between '='"; + test_content += " 'copyright copyleft copyeditor' on a rel attribute. The"; + test_content += " second selector will only represent an a element with"; + test_content += " an href attribute having the exact value"; + test_content += " 'http://www.w3.org/'.

"; + test_content += "
a[rel~='copyright']";
+    test_content += "      a[href='http://www.w3.org/']
"; + test_content += "

The following selector represents a link element"; + test_content += " whose hreflang attribute is exactly 'fr'.

"; + test_content += "
link[hreflang=fr]
"; + test_content += "

The following selector represents a link element for"; + test_content += " which the values of the hreflang attribute begins with"; + test_content += " 'en', including 'en', 'en-US', and 'en-cockney':

"; + test_content += "
link[hreflang|='en']
"; + test_content += "

Similarly, the following selectors represents a"; + test_content += " DIALOGUE element whenever it has one of two different"; + test_content += " values for an attribute character:

"; + test_content += "
DIALOGUE[character=romeo]";
+    test_content += "      DIALOGUE[character=juliet]
"; + test_content += "
"; + test_content += "

6.3.2. Substring matching attribute"; + test_content += " selectors

"; + test_content += "

Three additional attribute selectors are provided for matching"; + test_content += " substrings in the value of an attribute:

"; + test_content += "
"; + test_content += "
[att^=val]
"; + test_content += "
Represents an element with the att attribute whose value"; + test_content += "
"; + test_content += "
[att$=val]"; + test_content += "
Represents an element with the att attribute whose value"; + test_content += "
"; + test_content += "
[att*=val]"; + test_content += "
Represents an element with the att attribute whose value"; + test_content += "
"; + test_content += "
"; + test_content += "

Attribute values must be identifiers or strings. The"; + test_content += " case-sensitivity of attribute names in selectors depends on the"; + test_content += " document language.

"; + test_content += "
"; + test_content += "

Examples:

"; + test_content += "

The following selector represents an HTML object,"; + test_content += " image:

"; + test_content += "
object[type^='image/']
"; + test_content += "

The following selector represents an HTML anchor a with an"; + test_content += " href attribute whose value ends with '.html'.

"; + test_content += "
a[href$='.html']
"; + test_content += "

The following selector represents an HTML paragraph with a"; + test_content += " title"; + test_content += " attribute whose value contains the substring 'hello'

"; + test_content += "
p[title*='hello']
"; + test_content += "
"; + test_content += "

6.3.3. Attribute selectors and namespaces

"; + test_content += "

Attribute selectors allow an optional namespace component to the"; + test_content += " separator 'vertical bar' (|). In keeping with"; + test_content += " apply to attributes, therefore attribute selectors without a namespace"; + test_content += " (equivalent to '|attr'). An asterisk may be used for the"; + test_content += "

An attribute selector with an attribute name containing a namespace"; + test_content += " prefix that has not been previously declared is an invalid selector. The mechanism for"; + test_content += " a namespace prefix is left up to the language implementing Selectors."; + test_content += "

"; + test_content += "

CSS examples:

"; + test_content += "
@namespace foo 'http://www.example.com';";
+    test_content += "      [att] { color: green }
"; + test_content += "

The first rule will match only elements with the attribute"; + test_content += " att in the 'http://www.example.com' namespace with the"; + test_content += " value 'val'.

"; + test_content += "

The second rule will match only elements with the attribute"; + test_content += " att regardless of the namespace of the attribute"; + test_content += " (including no declared namespace).

"; + test_content += "

The last two rules are equivalent and will match only elements"; + test_content += " with the attribute att where the attribute is not"; + test_content += " declared to be in a namespace.

"; + test_content += "
"; + test_content += "

6.3.4. Default attribute values in DTDs

"; + test_content += "

Attribute selectors represent explicitly set attribute values in"; + test_content += " selectors. Selectors should be designed so that they work even if the"; + test_content += " default values are not included in the document tree.

"; + test_content += "

More precisely, a UA is not required to read an 'external"; + test_content += " subset' of the DTD but is required to look for default"; + test_content += " attribute values in the document's 'internal subset.' (See [XML10] for definitions of these subsets.)

"; + test_content += "

A UA that recognizes an XML namespace [XMLNAMES] is not required to use its"; + test_content += " required to use its built-in knowledge of the XHTML DTD.)

"; + test_content += "

Note: Typically, implementations"; + test_content += " choose to ignore external subsets.

"; + test_content += "
"; + test_content += "

Example:

"; + test_content += "

Consider an element EXAMPLE with an attribute 'notation' that has a"; + test_content += " default value of 'decimal'. The DTD fragment might be

"; + test_content += "
<!ATTLIST EXAMPLE notation (decimal,octal) 'decimal'>
"; + test_content += "

If the style sheet contains the rules

"; + test_content += "
EXAMPLE[notation=decimal] { /*... default property settings ...*/ }";
+    test_content += "      EXAMPLE[notation=octal]   { /*... other settings...*/ }
"; + test_content += "

the first rule will not match elements whose 'notation' attribute"; + test_content += " attribute selector for the default value must be dropped:

"; + test_content += "
EXAMPLE                   { /*... default property settings ...*/ }";
+    test_content += "      EXAMPLE[notation=octal]   { /*... other settings...*/ }
"; + test_content += "

Here, because the selector EXAMPLE[notation=octal] is"; + test_content += " cases' style rules.

"; + test_content += "
"; + test_content += "

6.4. Class selectors

"; + test_content += "

Working with HTML, authors may use the period (U+002E,"; + test_content += " .) notation as an alternative to the ~="; + test_content += " notation when representing the class attribute. Thus, for"; + test_content += " HTML, div.value and div[class~=value] have"; + test_content += " 'period' (.).

"; + test_content += "

UAs may apply selectors using the period (.) notation in XML"; + test_content += " 1.0 [SVG] describes the SVG"; + test_content += " 'class' attribute and how a UA should interpret it, and"; + test_content += " similarly MathML 1.01 [MATH] describes the MathML"; + test_content += " 'class' attribute.)

"; + test_content += "
"; + test_content += "

CSS examples:

"; + test_content += "

We can assign style information to all elements with"; + test_content += " class~='pastoral' as follows:

"; + test_content += "
*.pastoral { color: green }  /* all elements with class~=pastoral */
"; + test_content += "

or just

"; + test_content += "
.pastoral { color: green }  /* all elements with class~=pastoral */
"; + test_content += "

The following assigns style only to H1 elements with"; + test_content += " class~='pastoral':

"; + test_content += "
H1.pastoral { color: green }  /* H1 elements with class~=pastoral */
"; + test_content += "

Given these rules, the first H1 instance below would not have"; + test_content += " green text, while the second would:

"; + test_content += "
<H1>Not green</H1>";
+    test_content += "      <H1 class='pastoral'>Very green</H1>
"; + test_content += "
"; + test_content += "

To represent a subset of 'class' values, each value must be preceded"; + test_content += " by a '.', in any order.

"; + test_content += "
"; + test_content += "

CSS example:

"; + test_content += "

The following rule matches any P element whose 'class' attribute"; + test_content += " has been assigned a list of whitespace-separated values that includes"; + test_content += " 'pastoral' and 'marine':

"; + test_content += "
p.pastoral.marine { color: green }
"; + test_content += "

This rule matches when class='pastoral blue aqua"; + test_content += " marine' but does not match for class='pastoral"; + test_content += " blue'.

"; + test_content += "
"; + test_content += "

Note: Because CSS gives considerable"; + test_content += " not.

"; + test_content += "

Note: If an element has multiple"; + test_content += " this specification.

"; + test_content += "

6.5. ID selectors

"; + test_content += "

Document languages may contain attributes that are declared to be"; + test_content += " applies.

"; + test_content += "

An ID-typed attribute of a document language allows authors to"; + test_content += " ID selectors represent an element instance based on its identifier. An"; + test_content += " #) immediately followed by the ID value, which must be an"; + test_content += " identifier.

"; + test_content += "

Selectors does not specify how a UA knows the ID-typed attribute of"; + test_content += "

"; + test_content += "

Examples:

"; + test_content += "

The following ID selector represents an h1 element"; + test_content += " whose ID-typed attribute has the value 'chapter1':

"; + test_content += "
h1#chapter1
"; + test_content += "

The following ID selector represents any element whose ID-typed"; + test_content += " attribute has the value 'chapter1':

"; + test_content += "
#chapter1
"; + test_content += "

The following selector represents any element whose ID-typed"; + test_content += " attribute has the value 'z98y'.

"; + test_content += "
*#z98y
"; + test_content += "
"; + test_content += "

Note. In XML 1.0 [XML10], the information about which attribute"; + test_content += " should use normal attribute selectors instead:"; + test_content += " [name=p371] instead of #p371. Elements in"; + test_content += " XML 1.0 documents without a DTD do not have IDs at all.

"; + test_content += "

If an element has multiple ID attributes, all of them must be"; + test_content += " DOM3 Core, XML DTDs, and namespace-specific knowledge.

"; + test_content += "

6.6. Pseudo-classes

"; + test_content += "

The pseudo-class concept is introduced to permit selection based on"; + test_content += " expressed using the other simple selectors.

"; + test_content += "

A pseudo-class always consists of a 'colon'"; + test_content += " (:) followed by the name of the pseudo-class and"; + test_content += " optionally by a value between parentheses.

"; + test_content += "

Pseudo-classes are allowed in all sequences of simple selectors"; + test_content += " sequences of simple selectors, after the leading type selector or"; + test_content += " document.

"; + test_content += "

6.6.1. Dynamic pseudo-classes

"; + test_content += "

Dynamic pseudo-classes classify elements on characteristics other"; + test_content += " that cannot be deduced from the document tree.

"; + test_content += "

Dynamic pseudo-classes do not appear in the document source or"; + test_content += " document tree.

"; + test_content += "
The link pseudo-classes: :link and :visited
"; + test_content += "

User agents commonly display unvisited links differently from"; + test_content += " previously visited ones. Selectors"; + test_content += " provides the pseudo-classes :link and"; + test_content += " :visited to distinguish them:

"; + test_content += "
    "; + test_content += "
  • The :link pseudo-class applies to links that have"; + test_content += "
  • "; + test_content += "
  • The :visited pseudo-class applies once the link has"; + test_content += "
  • "; + test_content += "
"; + test_content += "

After some amount of time, user agents may choose to return a"; + test_content += " visited link to the (unvisited) ':link' state.

"; + test_content += "

The two states are mutually exclusive.

"; + test_content += "
"; + test_content += "

Example:

"; + test_content += "

The following selector represents links carrying class"; + test_content += " external and already visited:

"; + test_content += "
a.external:visited
"; + test_content += "
"; + test_content += "

Note: It is possible for style sheet"; + test_content += "

UAs may therefore treat all links as unvisited links, or implement"; + test_content += " and unvisited links differently.

"; + test_content += "
The user action pseudo-classes"; + test_content += " :hover, :active, and :focus
"; + test_content += "

Interactive user agents sometimes change the rendering in response"; + test_content += " to user actions. Selectors provides"; + test_content += " acting on.

"; + test_content += "
    "; + test_content += "
  • The :hover pseudo-class applies while the user"; + test_content += " element. User agents not that do not support interactive"; + test_content += " media do not have to support this pseudo-class. Some conforming"; + test_content += " user agents that support interactive"; + test_content += " media may not be able to support this pseudo-class (e.g., a pen"; + test_content += "
  • "; + test_content += "
  • The :active pseudo-class applies while an element"; + test_content += "
  • "; + test_content += "
  • The :focus pseudo-class applies while an element"; + test_content += "
  • "; + test_content += "
"; + test_content += "

There may be document language or implementation specific limits on"; + test_content += " which elements can become :active or acquire"; + test_content += " :focus.

"; + test_content += "

These pseudo-classes are not mutually exclusive. An element may"; + test_content += " match several pseudo-classes at the same time.

"; + test_content += "

Selectors doesn't define if the parent of an element that is"; + test_content += " ':active' or ':hover' is also in that state.

"; + test_content += "
"; + test_content += "

Examples:

"; + test_content += "
a:link    /* unvisited links */";
+    test_content += "      a:active  /* active links */
"; + test_content += "

An example of combining dynamic pseudo-classes:

"; + test_content += "
a:focus";
+    test_content += "      a:focus:hover
"; + test_content += "

The last selector matches a elements that are in"; + test_content += " the pseudo-class :focus and in the pseudo-class :hover.

"; + test_content += "
"; + test_content += "

Note: An element can be both ':visited'"; + test_content += " and ':active' (or ':link' and ':active').

"; + test_content += "

6.6.2. The target pseudo-class :target

"; + test_content += "

Some URIs refer to a location within a resource. This kind of URI"; + test_content += " identifier (called the fragment identifier).

"; + test_content += "

URIs with fragment identifiers link to a certain element within the"; + test_content += " pointing to an anchor named section_2 in an HTML"; + test_content += " document:

"; + test_content += "
http://example.com/html/top.html#section_2
"; + test_content += "

A target element can be represented by the :target"; + test_content += " the document has no target element.

"; + test_content += "
"; + test_content += "

Example:

"; + test_content += "
p.note:target
"; + test_content += "

This selector represents a p element of class"; + test_content += " note that is the target element of the referring"; + test_content += " URI.

"; + test_content += "
"; + test_content += "
"; + test_content += "

CSS example:

"; + test_content += "

Here, the :target pseudo-class is used to make the"; + test_content += " target element red and place an image before it, if there is one:

"; + test_content += "
*:target { color : red }";
+    test_content += "      *:target::before { content : url(target.png) }
"; + test_content += "
"; + test_content += "

6.6.3. The language pseudo-class :lang

"; + test_content += "

If the document language specifies how the human language of an"; + test_content += " element is determined, it is possible to write selectors that"; + test_content += " represent an element based on its language. For example, in HTML [HTML4], the language is determined by a"; + test_content += " combination of the lang attribute, the meta"; + test_content += " headers). XML uses an attribute called xml:lang, and"; + test_content += " the language.

"; + test_content += "

The pseudo-class :lang(C) represents an element that"; + test_content += " :lang() selector is based solely on the identifier C"; + test_content += " element's language value, in the same way as if performed by the '|=' operator in attribute"; + test_content += " selectors. The identifier C does not have to be a valid language"; + test_content += " name.

"; + test_content += "

C must not be empty. (If it is, the selector is invalid.)

"; + test_content += "

Note: It is recommended that"; + test_content += " documents and protocols indicate language using codes from RFC 3066 [RFC3066] or its successor, and by means of"; + test_content += " 'xml:lang' attributes in the case of XML-based documents [XML10]. See "; + test_content += " 'FAQ: Two-letter or three-letter language codes.'

"; + test_content += "
"; + test_content += "

Examples:

"; + test_content += "

The two following selectors represent an HTML document that is in"; + test_content += " Belgian, French, or German. The two next selectors represent"; + test_content += " q quotations in an arbitrary element in Belgian, French,"; + test_content += " or German.

"; + test_content += "
html:lang(fr-be)";
+    test_content += "      :lang(de) > q
"; + test_content += "
"; + test_content += "

6.6.4. The UI element states pseudo-classes

"; + test_content += "
The :enabled and :disabled pseudo-classes
"; + test_content += "

The :enabled pseudo-class allows authors to customize"; + test_content += " an enabled input element without also specifying what it"; + test_content += " would look like when it was disabled.

"; + test_content += "

Similar to :enabled, :disabled allows the"; + test_content += " element should look.

"; + test_content += "

Most elements will be neither enabled nor disabled. An element is"; + test_content += " presently activate it or transfer focus to it.

"; + test_content += "
The :checked pseudo-class
"; + test_content += "

Radio and checkbox elements can be toggled by the user. Some menu"; + test_content += " toggled 'on' the :checked pseudo-class applies. The"; + test_content += " :checked pseudo-class initially applies to such elements"; + test_content += " that have the HTML4 selected and checked"; + test_content += " attributes as described in Section"; + test_content += " 17.2.1 of HTML4, but of course the user can toggle 'off' such"; + test_content += " elements in which case the :checked pseudo-class would no"; + test_content += " longer apply. While the :checked pseudo-class is dynamic"; + test_content += " on the presence of the semantic HTML4 selected and"; + test_content += " checked attributes, it applies to all media."; + test_content += "

The :indeterminate pseudo-class
"; + test_content += "
"; + test_content += "

Radio and checkbox elements can be toggled by the user, but are"; + test_content += " This can be due to an element attribute, or DOM manipulation.

"; + test_content += "

A future version of this specification may introduce an"; + test_content += " :indeterminate pseudo-class that applies to such elements."; + test_content += "

"; + test_content += "
"; + test_content += "

6.6.5. Structural pseudo-classes

"; + test_content += "

Selectors introduces the concept of structural"; + test_content += " pseudo-classes to permit selection based on extra information that"; + test_content += " the document tree but cannot be represented by other simple selectors or"; + test_content += "

Note that standalone pieces of PCDATA (text nodes in the DOM) are"; + test_content += "

:root pseudo-class
"; + test_content += "

The :root pseudo-class represents an element that is"; + test_content += " HTML element."; + test_content += "

:nth-child() pseudo-class
"; + test_content += "

The"; + test_content += " :nth-child(an+b)"; + test_content += " an+b-1 siblings"; + test_content += " before it in the document tree, for a given positive"; + test_content += " integer or zero value of n, and has a parent element. In"; + test_content += " other words, this matches the bth child of an element after"; + test_content += " all the children have been split into groups of a elements"; + test_content += " each. For example, this allows the selectors to address every other"; + test_content += " of paragraph text in a cycle of four. The a and"; + test_content += " b values must be zero, negative integers or positive"; + test_content += "

In addition to this, :nth-child() can take"; + test_content += " 'odd' and 'even' as arguments instead."; + test_content += " 'odd' has the same signification as 2n+1,"; + test_content += " and 'even' has the same signification as 2n."; + test_content += "

"; + test_content += "

Examples:

"; + test_content += "
tr:nth-child(2n+1) /* represents every odd row of an HTML table */";
+    test_content += "      p:nth-child(4n+4) { color: purple; }
"; + test_content += "
"; + test_content += "

When a=0, no repeating is used, so for example"; + test_content += " :nth-child(0n+5) matches only the fifth child. When"; + test_content += " a=0, the an part need not be"; + test_content += " :nth-child(b) and the last example simplifies"; + test_content += " to :nth-child(5)."; + test_content += "

"; + test_content += "

Examples:

"; + test_content += "
foo:nth-child(0n+1)   /* represents an element foo, first child of its parent element */";
+    test_content += "      foo:nth-child(1)      /* same */
"; + test_content += "
"; + test_content += "

When a=1, the number may be omitted from the rule."; + test_content += "

"; + test_content += "

Examples:

"; + test_content += "

The following selectors are therefore equivalent:

"; + test_content += "
bar:nth-child(1n+0)   /* represents all bar elements, specificity (0,1,1) */";
+    test_content += "      bar                   /* same but lower specificity (0,0,1) */
"; + test_content += "
"; + test_content += "

If b=0, then every ath element is picked. In"; + test_content += " such a case, the b part may be omitted."; + test_content += "

"; + test_content += "

Examples:

"; + test_content += "
tr:nth-child(2n+0) /* represents every even row of an HTML table */";
+    test_content += "      tr:nth-child(2n) /* same */
"; + test_content += "
"; + test_content += "

If both a and b are equal to zero, the"; + test_content += " pseudo-class represents no element in the document tree.

"; + test_content += "

The value a can be negative, but only the positive"; + test_content += " values of an+b, for"; + test_content += " n≥0, may represent an element in the document"; + test_content += " tree.

"; + test_content += "
"; + test_content += "

Example:

"; + test_content += "
html|tr:nth-child(-n+6)  /* represents the 6 first rows of XHTML tables */
"; + test_content += "
"; + test_content += "

When the value b is negative, the '+' character in the"; + test_content += " character indicating the negative value of b).

"; + test_content += "
"; + test_content += "

Examples:

"; + test_content += "
:nth-child(10n-1)  /* represents the 9th, 19th, 29th, etc, element */";
+    test_content += "      :nth-child(10n+-1) /* Syntactically invalid, and would be ignored */
"; + test_content += "
"; + test_content += "
:nth-last-child() pseudo-class
"; + test_content += "

The :nth-last-child(an+b)"; + test_content += " an+b-1 siblings"; + test_content += " after it in the document tree, for a given positive"; + test_content += " integer or zero value of n, and has a parent element. See"; + test_content += " :nth-child() pseudo-class for the syntax of its argument."; + test_content += " It also accepts the 'even' and 'odd' values"; + test_content += "

"; + test_content += "

Examples:

"; + test_content += "
tr:nth-last-child(-n+2)    /* represents the two last rows of an HTML table */";
+    test_content += "                                    counting from the last one */
"; + test_content += "
"; + test_content += "
:nth-of-type() pseudo-class
"; + test_content += "

The :nth-of-type(an+b)"; + test_content += " an+b-1 siblings with the same"; + test_content += " element name before it in the document tree, for a"; + test_content += " given zero or positive integer value of n, and has a"; + test_content += " parent element. In other words, this matches the bth child"; + test_content += " groups of a elements each. See :nth-child() pseudo-class"; + test_content += " 'even' and 'odd' values."; + test_content += "

"; + test_content += "

CSS example:

"; + test_content += "

This allows an author to alternate the position of floated images:

"; + test_content += "
img:nth-of-type(2n+1) { float: right; }";
+    test_content += "      img:nth-of-type(2n) { float: left; }
"; + test_content += "
"; + test_content += "
:nth-last-of-type() pseudo-class
"; + test_content += "

The :nth-last-of-type(an+b)"; + test_content += " an+b-1 siblings with the same"; + test_content += " element name after it in the document tree, for a"; + test_content += " given zero or positive integer value of n, and has a"; + test_content += " parent element. See :nth-child() pseudo-class for the"; + test_content += " syntax of its argument. It also accepts the 'even' and 'odd'"; + test_content += "

"; + test_content += "

Example:

"; + test_content += "

To represent all h2 children of an XHTML"; + test_content += " body except the first and last, one could use the"; + test_content += " following selector:

"; + test_content += "
body > h2:nth-of-type(n+2):nth-last-of-type(n+2)
"; + test_content += "

In this case, one could also use :not(), although the"; + test_content += " selector ends up being just as long:

"; + test_content += "
body > h2:not(:first-of-type):not(:last-of-type)
"; + test_content += "
"; + test_content += "
:first-child pseudo-class
"; + test_content += "

Same as :nth-child(1). The :first-child"; + test_content += "

"; + test_content += "

Examples:

"; + test_content += "

The following selector represents a p element that is"; + test_content += " the first child of a div element:

"; + test_content += "
div > p:first-child
"; + test_content += "

This selector can represent the p inside the"; + test_content += " div of the following fragment:

"; + test_content += "
<p> The last P before the note.</p>";
+    test_content += "      </div>
"; + test_content += " but cannot represent the second p in the following"; + test_content += "
<p> The last P before the note.</p>";
+    test_content += "      </div>
"; + test_content += "

The following two selectors are usually equivalent:

"; + test_content += "
* > a:first-child /* a is first child of any element */";
+    test_content += "      a:first-child /* Same (assuming a is not the root element) */
"; + test_content += "
"; + test_content += "
:last-child pseudo-class
"; + test_content += "

Same as :nth-last-child(1). The :last-child"; + test_content += "

"; + test_content += "

Example:

"; + test_content += "

The following selector represents a list item li that"; + test_content += " is the last child of an ordered list ol."; + test_content += "

ol > li:last-child
"; + test_content += "
"; + test_content += "
:first-of-type pseudo-class
"; + test_content += "

Same as :nth-of-type(1). The :first-of-type"; + test_content += "

"; + test_content += "

Example:

"; + test_content += "

The following selector represents a definition title"; + test_content += " dt inside a definition list dl, this"; + test_content += " dt being the first of its type in the list of children of"; + test_content += " its parent element.

"; + test_content += "
dl dt:first-of-type
"; + test_content += "

It is a valid description for the first two dt"; + test_content += " elements in the following example but not for the third one:

"; + test_content += "
<dl>";
+    test_content += "      </dl>
"; + test_content += "
"; + test_content += "
:last-of-type pseudo-class
"; + test_content += "

Same as :nth-last-of-type(1). The"; + test_content += " :last-of-type pseudo-class represents an element that is"; + test_content += " element.

"; + test_content += "
"; + test_content += "

Example:

"; + test_content += "

The following selector represents the last data cell"; + test_content += " td of a table row.

"; + test_content += "
tr > td:last-of-type
"; + test_content += "
"; + test_content += "
:only-child pseudo-class
"; + test_content += "

Represents an element that has a parent element and whose parent"; + test_content += " :first-child:last-child or"; + test_content += " :nth-child(1):nth-last-child(1), but with a lower"; + test_content += " specificity.

"; + test_content += "
:only-of-type pseudo-class
"; + test_content += "

Represents an element that has a parent element and whose parent"; + test_content += " as :first-of-type:last-of-type or"; + test_content += " :nth-of-type(1):nth-last-of-type(1), but with a lower"; + test_content += " specificity.

"; + test_content += "
:empty pseudo-class
"; + test_content += "

The :empty pseudo-class represents an element that has"; + test_content += " empty or not.

"; + test_content += "
"; + test_content += "

Examples:

"; + test_content += "

p:empty is a valid representation of the following fragment:"; + test_content += "

"; + test_content += "
<p></p>
"; + test_content += "

foo:empty is not a valid representation for the"; + test_content += " following fragments:

"; + test_content += "
<foo>bar</foo>
"; + test_content += "
<foo><bar>bla</bar></foo>
"; + test_content += "
<foo>this is not <bar>:empty</bar></foo>
"; + test_content += "
"; + test_content += "

6.6.6. Blank

"; + test_content += " "; + test_content += "

This section intentionally left blank.

"; + test_content += " "; + test_content += "

6.6.7. The negation pseudo-class

"; + test_content += "

The negation pseudo-class, :not(X), is a"; + test_content += " functional notation taking a simple"; + test_content += " selector (excluding the negation pseudo-class itself and"; + test_content += " "; + test_content += "

"; + test_content += "

Examples:

"; + test_content += "

The following CSS selector matches all button"; + test_content += " elements in an HTML document that are not disabled.

"; + test_content += "
button:not([DISABLED])
"; + test_content += "

The following selector represents all but FOO"; + test_content += " elements.

"; + test_content += "
*:not(FOO)
"; + test_content += "

The following group of selectors represents all HTML elements"; + test_content += " except links.

"; + test_content += "
html|*:not(:link):not(:visited)
"; + test_content += "
"; + test_content += "

Default namespace declarations do not affect the argument of the"; + test_content += " type selector.

"; + test_content += "
"; + test_content += "

Examples:

"; + test_content += "

Assuming that the default namespace is bound to"; + test_content += " elements that are not in that namespace:

"; + test_content += "
*|*:not(*)
"; + test_content += "

The following CSS selector matches any element being hovered,"; + test_content += " rule when they are being hovered.

"; + test_content += "
*|*:not(:hover)
"; + test_content += "
"; + test_content += "

Note: the :not() pseudo allows"; + test_content += " useless selectors to be written. For instance :not(*|*),"; + test_content += " which represents no element at all, or foo:not(bar),"; + test_content += " which is equivalent to foo but with a higher"; + test_content += " specificity.

"; + test_content += "

7. Pseudo-elements

"; + test_content += "

Pseudo-elements create abstractions about the document tree beyond"; + test_content += " source document (e.g., the ::before and"; + test_content += " ::after pseudo-elements give access to generated"; + test_content += " content).

"; + test_content += "

A pseudo-element is made of two colons (::) followed"; + test_content += " by the name of the pseudo-element.

"; + test_content += "

This :: notation is introduced by the current document"; + test_content += " :first-line, :first-letter,"; + test_content += " :before and :after). This compatibility is"; + test_content += " not allowed for the new pseudo-elements introduced in CSS level 3.

"; + test_content += "

Only one pseudo-element may appear per selector, and if present it"; + test_content += " must appear after the sequence of simple selectors that represents the"; + test_content += " subjects of the selector. A"; + test_content += " pesudo-elements per selector.

"; + test_content += "

7.1. The ::first-line pseudo-element

"; + test_content += "

The ::first-line pseudo-element describes the contents"; + test_content += "

"; + test_content += "

CSS example:

"; + test_content += "
p::first-line { text-transform: uppercase }
"; + test_content += "

The above rule means 'change the letters of the first line of every"; + test_content += " paragraph to uppercase'.

"; + test_content += "
"; + test_content += "

The selector p::first-line does not match any real"; + test_content += " agents will insert at the beginning of every paragraph.

"; + test_content += "

Note that the length of the first line depends on a number of"; + test_content += " an ordinary HTML paragraph such as:

"; + test_content += "
      <P>This is a somewhat long HTML ";
+    test_content += "      
"; + test_content += "

the lines of which happen to be broken as follows:"; + test_content += "

      THIS IS A SOMEWHAT LONG HTML PARAGRAPH THAT";
+    test_content += "      
"; + test_content += "

This paragraph might be 'rewritten' by user agents to include the"; + test_content += " fictional tag sequence for ::first-line. This"; + test_content += " fictional tag sequence helps to show how properties are inherited.

"; + test_content += "
      <P><P::first-line> This is a somewhat long HTML ";
+    test_content += "      paragraph that </P::first-line> will be broken into several";
+    test_content += "      
"; + test_content += "

If a pseudo-element breaks up a real element, the desired effect"; + test_content += " with a span element:

"; + test_content += "
      <P><SPAN class='test'> This is a somewhat long HTML";
+    test_content += "      lines.</SPAN> The first line will be identified";
+    test_content += "      
"; + test_content += "

the user agent could simulate start and end tags for"; + test_content += " span when inserting the fictional tag sequence for"; + test_content += " ::first-line."; + test_content += "

      <P><P::first-line><SPAN class='test'> This is a";
+    test_content += "      paragraph that will </SPAN></P::first-line><SPAN";
+    test_content += "          class='test'> be";
+    test_content += "      lines.</SPAN> The first line will be identified";
+    test_content += "      
"; + test_content += "

In CSS, the ::first-line pseudo-element can only be"; + test_content += " or a table-cell.

"; + test_content += "

The 'first formatted line' of an"; + test_content += " line of the div in <DIV><P>This"; + test_content += " line...</P></DIV> is the first line of the p"; + test_content += " that both p and div are block-level)."; + test_content += "

The first line of a table-cell or inline-block cannot be the first"; + test_content += " formatted line of an ancestor element. Thus, in <DIV><P"; + test_content += " etcetera</DIV> the first formatted line of the"; + test_content += " div is not the line 'Hello'."; + test_content += "

Note that the first line of the p in this"; + test_content += " fragment: <p><br>First... doesn't contain any"; + test_content += " letters (assuming the default style for br in HTML"; + test_content += "

A UA should act as if the fictional start tags of the"; + test_content += " ::first-line pseudo-elements were nested just inside the"; + test_content += " is an example. The fictional tag sequence for

"; + test_content += "
      <DIV>";
+    test_content += "      
"; + test_content += "

is

"; + test_content += "
      <DIV>";
+    test_content += "      
"; + test_content += "

The ::first-line pseudo-element is similar to an"; + test_content += " following properties apply to a ::first-line"; + test_content += " properties as well.

"; + test_content += "

7.2. The ::first-letter pseudo-element

"; + test_content += "

The ::first-letter pseudo-element represents the first"; + test_content += " is 'none'; otherwise, it is similar to a floated element.

"; + test_content += "

In CSS, these are the properties that apply to ::first-letter"; + test_content += " of the letter, unlike for normal elements.

"; + test_content += "
"; + test_content += "

Example:

"; + test_content += "

This example shows a possible rendering of an initial cap. Note"; + test_content += " ::first-letter"; + test_content += " fictional start tag of the first letter is inside the span,"; + test_content += " the font weight of the first letter is normal, not bold as the span:"; + test_content += "

      p { line-height: 1.1 }";
+    test_content += "      
"; + test_content += "
"; + test_content += "

Image illustrating the ::first-letter pseudo-element"; + test_content += "

"; + test_content += "
"; + test_content += "
"; + test_content += "

The following CSS will make a drop cap initial letter span about two"; + test_content += " lines:

"; + test_content += "
      <!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01//EN'>";
+    test_content += "      
"; + test_content += "

This example might be formatted as follows:

"; + test_content += "
"; + test_content += "

Image illustrating the combined effect of the ::first-letter and ::first-line pseudo-elements"; + test_content += "

"; + test_content += "
"; + test_content += "

The fictional tag sequence is:

"; + test_content += "
      <P>";
+    test_content += "      
"; + test_content += "

Note that the ::first-letter pseudo-element tags abut"; + test_content += " block element.

"; + test_content += "

In order to achieve traditional drop caps formatting, user agents"; + test_content += " glyph outline may be taken into account when formatting.

"; + test_content += "

Punctuation (i.e, characters defined in Unicode in the 'open' (Ps),"; + test_content += " be included. [UNICODE]

"; + test_content += "
"; + test_content += "

Quotes that precede the";
+    test_content += "      first letter should be included.

"; + test_content += "
"; + test_content += "

The ::first-letter also applies if the first letter is"; + test_content += " money.'

"; + test_content += "

In CSS, the ::first-letter pseudo-element applies to"; + test_content += " elements. A future version of this specification"; + test_content += " types.

"; + test_content += "

The ::first-letter pseudo-element can be used with all"; + test_content += " the element, even if that first text is in a descendant.

"; + test_content += "
"; + test_content += "

Example:

"; + test_content += "

The fictional tag sequence for this HTMLfragment:"; + test_content += "

<div>";
+    test_content += "      <p>The first text.
"; + test_content += "

is:"; + test_content += "

<div>";
+    test_content += "      <p><div::first-letter><p::first-letter>T</...></...>he first text.
"; + test_content += "
"; + test_content += "

The first letter of a table-cell or inline-block cannot be the"; + test_content += " first letter of an ancestor element. Thus, in <DIV><P"; + test_content += " etcetera</DIV> the first letter of the div is"; + test_content += " letter 'H'. In fact, the div doesn't have a first letter."; + test_content += "

The first letter must occur on the first formatted line. For example, in"; + test_content += " this fragment: <p><br>First... the first line"; + test_content += " doesn't contain any letters and ::first-letter doesn't"; + test_content += " match anything (assuming the default style for br in HTML"; + test_content += "

In CSS, if an element is a list item ('display: list-item'), the"; + test_content += " ::first-letter applies to the first letter in the"; + test_content += " ::first-letter on list items with 'list-style-position:"; + test_content += " inside'. If an element has ::before or"; + test_content += " ::after content, the ::first-letter applies"; + test_content += " to the first letter of the element including that content."; + test_content += "

"; + test_content += "

Example:

"; + test_content += "

After the rule 'p::before {content: 'Note: '}', the selector"; + test_content += " 'p::first-letter' matches the 'N' of 'Note'.

"; + test_content += "
"; + test_content += "

Some languages may have specific rules about how to treat certain"; + test_content += " considered within the ::first-letter pseudo-element."; + test_content += "

If the letters that would form the ::first-letter are not in the"; + test_content += " same element, such as ''T' in <p>'<em>T..., the UA"; + test_content += " both elements, or simply not create a pseudo-element.

"; + test_content += "

Similarly, if the first letter(s) of the block are not at the start"; + test_content += "

"; + test_content += "

Example:

"; + test_content += "

The following example illustrates"; + test_content += " paragraph will be 'red'.

"; + test_content += "
p { color: red; font-size: 12pt }";
+    test_content += "      <P>Some text that ends up on two lines</P>
"; + test_content += "

Assuming that a line break will occur before the word 'ends', the"; + test_content += " fictional tag"; + test_content += " sequence for this fragment might be:

"; + test_content += "
<P>";
+    test_content += "      </P>
"; + test_content += "

Note that the ::first-letter element is inside the ::first-line"; + test_content += " element. Properties set on ::first-line are inherited by"; + test_content += " ::first-letter, but are overridden if the same property is"; + test_content += " ::first-letter.

"; + test_content += "
"; + test_content += "

7.3. The ::selection"; + test_content += " pseudo-element

"; + test_content += "

The ::selection pseudo-element applies to the portion"; + test_content += " field. This pseudo-element should not be confused with the :checked pseudo-class (which used to be"; + test_content += " named :selected)"; + test_content += "

Although the ::selection pseudo-element is dynamic in"; + test_content += " [CSS21]) which was originally rendered to a"; + test_content += " ::selection state to that other medium, and have all the"; + test_content += " required — UAs may omit the ::selection"; + test_content += "

These are the CSS properties that apply to ::selection"; + test_content += " ::selection may be ignored."; + test_content += "

7.4. The ::before and ::after pseudo-elements

"; + test_content += "

The ::before and ::after pseudo-elements"; + test_content += " content. They are explained in CSS 2.1 [CSS21].

"; + test_content += "

When the ::first-letter and ::first-line"; + test_content += " pseudo-elements are combined with ::before and"; + test_content += " ::after, they apply to the first letter or line of the"; + test_content += " element including the inserted text.

"; + test_content += "

8. Combinators

"; + test_content += "

8.1. Descendant combinator

"; + test_content += "

At times, authors may want selectors to describe an element that is"; + test_content += " EM element that is contained within an H1"; + test_content += " descendant combinator is white space that"; + test_content += " separates two sequences of simple selectors. A selector of the form"; + test_content += " 'A B' represents an element B that is an"; + test_content += " arbitrary descendant of some ancestor element A."; + test_content += "

"; + test_content += "

Examples:

"; + test_content += "

For example, consider the following selector:

"; + test_content += "
h1 em
"; + test_content += "

It represents an em element being the descendant of"; + test_content += " an h1 element. It is a correct and valid, but partial,"; + test_content += " description of the following fragment:

"; + test_content += "
<h1>This <span class='myclass'>headline";
+    test_content += "      is <em>very</em> important</span></h1>
"; + test_content += "

The following selector:

"; + test_content += "
div * p
"; + test_content += "

represents a p element that is a grandchild or later"; + test_content += " descendant of a div element. Note the whitespace on"; + test_content += " of the P.

"; + test_content += "

The following selector, which combines descendant combinators and"; + test_content += " attribute selectors, represents an"; + test_content += " element that (1) has the href attribute set and (2) is"; + test_content += " inside a p that is itself inside a div:

"; + test_content += "
div p *[href]
"; + test_content += "
"; + test_content += "

8.2. Child combinators

"; + test_content += "

A child combinator describes a childhood relationship"; + test_content += " 'greater-than sign' (>) character and"; + test_content += " separates two sequences of simple selectors."; + test_content += "

"; + test_content += "

Examples:

"; + test_content += "

The following selector represents a p element that is"; + test_content += " child of body:

"; + test_content += "
body > p
"; + test_content += "

The following example combines descendant combinators and child"; + test_content += " combinators.

"; + test_content += "
div ol>li p
"; + test_content += " "; + test_content += "

It represents a p element that is a descendant of an"; + test_content += " li element; the li element must be the"; + test_content += " child of an ol element; the ol element must"; + test_content += " be a descendant of a div. Notice that the optional white"; + test_content += " space around the '>' combinator has been left out.

"; + test_content += "
"; + test_content += "

For information on selecting the first child of an element, please"; + test_content += " see the section on the :first-child pseudo-class"; + test_content += " above.

"; + test_content += "

8.3. Sibling combinators

"; + test_content += "

There are two different sibling combinators: the adjacent sibling"; + test_content += " considering adjacency of elements.

"; + test_content += "

8.3.1. Adjacent sibling combinator"; + test_content += "

"; + test_content += "

The adjacent sibling combinator is made of the 'plus"; + test_content += " sign' (U+002B, +) character that separates two"; + test_content += " sequences of simple selectors. The elements represented by the two"; + test_content += " represented by the second one.

"; + test_content += "
"; + test_content += "

Examples:

"; + test_content += "

The following selector represents a p element"; + test_content += " immediately following a math element:

"; + test_content += "
math + p
"; + test_content += "

The following selector is conceptually similar to the one in the"; + test_content += " adds a constraint to the h1 element, that it must have"; + test_content += " class='opener':

"; + test_content += "
h1.opener + h2
"; + test_content += "
"; + test_content += "

8.3.2. General sibling combinator"; + test_content += "

"; + test_content += "

The general sibling combinator is made of the 'tilde'"; + test_content += " (U+007E, ~) character that separates two sequences of"; + test_content += " simple selectors. The elements represented by the two sequences share"; + test_content += " represented by the second one.

"; + test_content += "
"; + test_content += "

Example:

"; + test_content += "
h1 ~ pre
"; + test_content += "

represents a pre element following an h1. It"; + test_content += " is a correct and valid, but partial, description of:

"; + test_content += "
<h1>Definition of the function a</h1>";
+    test_content += "      <pre>function a(x) = 12x/13.5</pre>
"; + test_content += "
"; + test_content += "

9. Calculating a selector's specificity

"; + test_content += "

A selector's specificity is calculated as follows:

"; + test_content += "
    "; + test_content += "
  • count the number of ID selectors in the selector (= a)
  • "; + test_content += "
  • count the number of class selectors, attributes selectors, and"; + test_content += "
  • "; + test_content += "
  • count the number of element names in the selector (= c)
  • "; + test_content += "
  • ignore pseudo-elements
  • "; + test_content += "
"; + test_content += "

Selectors inside the negation pseudo-class"; + test_content += " a pseudo-class.

"; + test_content += "

Concatenating the three numbers a-b-c (in a number system with a"; + test_content += " large base) gives the specificity.

"; + test_content += "
"; + test_content += "

Examples:

"; + test_content += "
*               /* a=0 b=0 c=0 -> specificity =   0 */";
+    test_content += "      
"; + test_content += "
"; + test_content += "

Note: the specificity of the styles"; + test_content += " specified in an HTML style attribute is described in CSS"; + test_content += " 2.1. [CSS21].

"; + test_content += "

10. The grammar of Selectors

"; + test_content += "

10.1. Grammar

"; + test_content += "

The grammar below defines the syntax of Selectors. It is globally"; + test_content += " shorthand notations beyond Yacc (see [YACC])"; + test_content += " are used:

"; + test_content += "
    "; + test_content += "
  • *: 0 or more"; + test_content += "
  • +: 1 or more"; + test_content += "
  • ?: 0 or 1"; + test_content += "
  • |: separates alternatives"; + test_content += "
  • [ ]: grouping
  • "; + test_content += "
"; + test_content += "

The productions are:

"; + test_content += "
selectors_group";
+    test_content += "        ;
"; + test_content += "

10.2. Lexical scanner

"; + test_content += "

The following is the tokenizer, written in Flex (see"; + test_content += " [FLEX]) notation. The tokenizer is"; + test_content += " case-insensitive.

"; + test_content += "

The two occurrences of '\377' represent the highest character"; + test_content += " possible code point in Unicode/ISO-10646. [UNICODE]

"; + test_content += "
%option case-insensitive";
+    test_content += "      .                return *yytext;
"; + test_content += "

11. Namespaces and down-level clients

"; + test_content += "

An important issue is the interaction of CSS selectors with XML"; + test_content += " to construct a CSS style sheet which will properly match selectors in"; + test_content += " is possible to construct a style sheet in which selectors would match"; + test_content += " elements and attributes correctly.

"; + test_content += "

It should be noted that a down-level CSS client will (if it"; + test_content += " @namespace at-rules, as well as all style rules that make"; + test_content += " use of namespace qualified element type or attribute selectors. The"; + test_content += " than possibly match them incorrectly.

"; + test_content += "

The use of default namespaces in CSS makes it possible to write"; + test_content += " element type selectors that will function in both namespace aware CSS"; + test_content += " down-level clients may incorrectly match selectors against XML"; + test_content += " elements in other namespaces.

"; + test_content += "

The following are scenarios and examples in which it is possible to"; + test_content += " that do not implement this proposal.

"; + test_content += "
    "; + test_content += "
  1. "; + test_content += "

    The XML document does not use namespaces.

    "; + test_content += "
      "; + test_content += "
    • In this case, it is obviously not necessary to declare or use"; + test_content += " attribute selectors will function adequately in a down-level"; + test_content += "
    • "; + test_content += "
    • In a CSS namespace aware client, the default behavior of"; + test_content += " element selectors matching without regard to namespace will"; + test_content += " present. However, the use of specific element type selectors"; + test_content += " match only elements that have no namespace ('|name')"; + test_content += " will guarantee that selectors will match only XML elements that"; + test_content += "
    • "; + test_content += "
    "; + test_content += "
  2. "; + test_content += "
  3. "; + test_content += "

    The XML document defines a single, default namespace used"; + test_content += " names.

    "; + test_content += "
      "; + test_content += "
    • In this case, a down-level client will function as if"; + test_content += " element type and attribute selectors will match against all"; + test_content += "
    • "; + test_content += "
    "; + test_content += "
  4. "; + test_content += "
  5. "; + test_content += "

    The XML document does not use a default namespace, all"; + test_content += " to the same URI).

    "; + test_content += "
      "; + test_content += "
    • In this case, the down-level client will view and match"; + test_content += " element type and attribute selectors based on their fully"; + test_content += " qualified name, not the local part as outlined in the Type selectors and Namespaces"; + test_content += " selectors may be declared using an escaped colon"; + test_content += " '\\:'"; + test_content += " 'html\\:h1' will match"; + test_content += " <html:h1>. Selectors using the qualified name"; + test_content += "
    • "; + test_content += "
    • Note that selectors declared in this fashion will"; + test_content += " only match in down-level clients. A CSS namespace aware"; + test_content += " client will match element type and attribute selectors based on"; + test_content += " the name's local part. Selectors declared with the fully"; + test_content += "
    • "; + test_content += "
    "; + test_content += "
  6. "; + test_content += "
"; + test_content += "

In other scenarios: when the namespace prefixes used in the XML are"; + test_content += " different namespace URIs within the same document, or in"; + test_content += " a CSS and XML namespace aware client.

"; + test_content += "

12. Profiles

"; + test_content += "

Each specification using Selectors must define the subset of W3C"; + test_content += " Selectors it allows and excludes, and describe the local meaning of"; + test_content += " all the components of that subset.

"; + test_content += "

Non normative examples:"; + test_content += "

"; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += "
Selectors profile
SpecificationCSS level 1
Acceptstype selectors
class selectors
ID selectors
:link,"; + test_content += " :visited and :active pseudo-classes
descendant combinator"; + test_content += "
::first-line and ::first-letter pseudo-elements"; + test_content += "
Excludes"; + test_content += "

universal selector
attribute selectors
:hover and"; + test_content += " pseudo-classes
:target pseudo-class
:lang()"; + test_content += " pseudo-class
all UI"; + test_content += " element states pseudo-classes
all structural"; + test_content += " pseudo-classes
negation pseudo-class
all"; + test_content += " UI element fragments pseudo-elements
::before and ::after"; + test_content += " pseudo-elements
child combinators
sibling combinators"; + test_content += "

namespaces

Extra constraintsonly one class selector allowed per sequence of simple"; + test_content += " selectors"; + test_content += "
"; + test_content += "

"; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += "
Selectors profile
SpecificationCSS level 2
Acceptstype selectors
universal selector
attribute presence and"; + test_content += " values selectors
class selectors
ID selectors
:link,"; + test_content += "
descendant combinator
child combinator
adjacent"; + test_content += " combinator
::first-line and ::first-letter"; + test_content += " pseudo-elements
::before"; + test_content += "
Excludes"; + test_content += "

content selectors
substring matching attribute"; + test_content += " selectors
:target pseudo-classes
all UI element"; + test_content += " states pseudo-classes
all structural pseudo-classes other"; + test_content += " than :first-child
negation pseudo-class
all UI element"; + test_content += " fragments pseudo-elements
general sibling combinators"; + test_content += "

namespaces

Extra constraintsmore than one class selector per sequence of simple selectors"; + test_content += "
"; + test_content += "

In CSS, selectors express pattern matching rules that determine which"; + test_content += "

The following selector (CSS level 2) will match all anchors a"; + test_content += " with attribute name set inside a section 1 header"; + test_content += " h1:"; + test_content += "

h1 a[name]
"; + test_content += "

All CSS declarations attached to such a selector are applied to elements"; + test_content += " matching it.

"; + test_content += "
"; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += " "; + test_content += "
Selectors profile
SpecificationSTTS 3
Accepts"; + test_content += "

type selectors
universal selectors
attribute"; + test_content += " selectors
class"; + test_content += " selectors
ID selectors
all structural"; + test_content += " pseudo-classes
"; + test_content += "

namespaces

Excludesnon-accepted pseudo-classes
pseudo-elements
Extra constraintssome selectors and combinators are not allowed in fragment"; + test_content += "
"; + test_content += "

Selectors can be used in STTS 3 in two different"; + test_content += "

    "; + test_content += "
  1. a selection mechanism equivalent to CSS selection mechanism:"; + test_content += "
  2. fragment descriptions that appear on the right side of declarations."; + test_content += "
  3. "; + test_content += "
"; + test_content += "
"; + test_content += "

13. Conformance and requirements

"; + test_content += "

This section defines conformance with the present specification only."; + test_content += "

The inability of a user agent to implement part of this specification due to"; + test_content += "

All specifications reusing Selectors must contain a Profile listing the"; + test_content += " subset of Selectors it accepts or excludes, and describing the constraints"; + test_content += "

Invalidity is caused by a parsing error, e.g. an unrecognized token or a"; + test_content += "

User agents must observe the rules for handling parsing errors:"; + test_content += "

    "; + test_content += "
  • a simple selector containing an undeclared namespace prefix is invalid"; + test_content += "
  • "; + test_content += "
  • a selector containing an invalid simple selector, an invalid combinator"; + test_content += "
  • "; + test_content += "
  • a group of selectors containing an invalid selector is invalid.
  • "; + test_content += "
"; + test_content += "

Specifications reusing Selectors must define how to handle parsing"; + test_content += " used is dropped.)

"; + test_content += " "; + test_content += "

14. Tests

"; + test_content += "

This specification has a test"; + test_content += " suite allowing user agents to verify their basic conformance to"; + test_content += " and does not cover all possible combined cases of Selectors.

"; + test_content += "

15. Acknowledgements

"; + test_content += "

The CSS working group would like to thank everyone who has sent"; + test_content += " comments on this specification over the years.

"; + test_content += "

The working group would like to extend special thanks to Donna"; + test_content += " the final editorial review.

"; + test_content += "

16. References

"; + test_content += "
"; + test_content += "
[CSS1]"; + test_content += "
Bert Bos, HÃ¥kon Wium Lie; 'Cascading"; + test_content += " Style Sheets, level 1', W3C Recommendation, 17 Dec 1996, revised"; + test_content += "
(http://www.w3.org/TR/REC-CSS1)"; + test_content += "
[CSS21]"; + test_content += "
Bert Bos, Tantek Çelik, Ian Hickson, Håkon"; + test_content += " Wium Lie, editors; 'Cascading Style Sheets, level 2 revision"; + test_content += " 1', W3C Working Draft, 13 June 2005"; + test_content += "
(http://www.w3.org/TR/CSS21)"; + test_content += "
[CWWW]"; + test_content += "
Martin J. Dürst, François Yergeau,"; + test_content += " Misha Wolf, Asmus Freytag, Tex Texin, editors; 'Character Model"; + test_content += " for the World Wide Web', W3C Recommendation, 15 February 2005"; + test_content += "
(http://www.w3.org/TR/charmod/)"; + test_content += "
[FLEX]"; + test_content += "
'Flex: The Lexical Scanner"; + test_content += " Generator', Version 2.3.7, ISBN 1882114213"; + test_content += "
[HTML4]"; + test_content += "
Dave Ragget, Arnaud Le Hors, Ian Jacobs,"; + test_content += " editors; 'HTML 4.01 Specification', W3C Recommendation, 24"; + test_content += "
"; + test_content += " (http://www.w3.org/TR/html4/)"; + test_content += "
[MATH]"; + test_content += "
Patrick Ion, Robert Miner, editors; 'Mathematical"; + test_content += " Markup Language (MathML) 1.01', W3C Recommendation, revision of 7"; + test_content += "
(http://www.w3.org/TR/REC-MathML/)"; + test_content += "
[RFC3066]"; + test_content += "
H. Alvestrand; 'Tags for the"; + test_content += " Identification of Languages', Request for Comments 3066, January"; + test_content += "
(http://www.ietf.org/rfc/rfc3066.txt)"; + test_content += "
[STTS]"; + test_content += "
Daniel Glazman; 'Simple Tree Transformation"; + test_content += " Sheets 3', Electricité de France, submission to the W3C,"; + test_content += "
(http://www.w3.org/TR/NOTE-STTS3)"; + test_content += "
[SVG]"; + test_content += "
Jon Ferraiolo, 藤沢 淳, Dean"; + test_content += " Jackson, editors; 'Scalable Vector Graphics (SVG) 1.1"; + test_content += " Specification', W3C Recommendation, 14 January 2003"; + test_content += "
(http://www.w3.org/TR/SVG/)"; + test_content += "
[UNICODE]
"; + test_content += "
The Unicode"; + test_content += " Standard, Version 4.1, The Unicode Consortium. Boston, MA,"; + test_content += " Addison-Wesley, March 2005. ISBN 0-321-18578-1, as amended by Unicode"; + test_content += " 4.0.1 and Unicode"; + test_content += " 4.1.0."; + test_content += "
(http://www.unicode.org/versions/)"; + test_content += "
"; + test_content += "
[XML10]"; + test_content += "
Tim Bray, Jean Paoli, C. M. Sperberg-McQueen,"; + test_content += " Eve Maler, François Yergeau, editors; 'Extensible Markup"; + test_content += " Language (XML) 1.0 (Third Edition)', W3C Recommendation, 4"; + test_content += "
(http://www.w3.org/TR/REC-xml/)"; + test_content += "
[XMLNAMES]"; + test_content += "
Tim Bray, Dave Hollander, Andrew Layman,"; + test_content += " editors; 'Namespaces in XML', W3C Recommendation, 14"; + test_content += "
(http://www.w3.org/TR/REC-xml-names/)"; + test_content += "
[YACC]"; + test_content += "
S. C. Johnson; 'YACC — Yet another"; + test_content += " compiler compiler', Technical Report, Murray Hill, 1975"; + test_content += "
';
"; + test_content += " 1"; + test_content += " 2"; + test_content += ""; + return test_content; + } + } -- 2.39.5