1
+ /** version 0.1 2009-04-30
2
+ * @author Andrea Giammarchi
3
+ * @license Mit Style License
4
+ * @project http://code.google.com/p/css2xpath/
5
+ */
6
+
7
+ /** css2xpath - generic CSS to XPath selector transformer
8
+ * @author Andrea Giammarchi
9
+ * @license Mit Style License
10
+ * @blog http://webreflection.blogspot.com/
11
+ * @project http://code.google.com/p/css2xpath/
12
+ * @version 0.1 - Converts correctly every SlickSpeed CSS selector [http://mootools.net/slickspeed/]
13
+ * @note stand alone vice-versa subproject [http://code.google.com/p/css2xpath/]
14
+ * @info http://www.w3.org/TR/CSS2/selector.html
15
+ * @credits some tips from Aristotle Pagaltzis [http://plasmasturm.org/log/444/]
16
+ */
17
+ css2xpath = ( function ( ) {
18
+ var re = [
19
+ // add @ for attribs
20
+ / \[ ( [ ^ \] ~ \$ \* \^ \| \! ] + ) ( = [ ^ \] ] + ) ? \] / g, "[@$1$2]" ,
21
+ // multiple queries
22
+ / \s * , \s * / g, "|" ,
23
+ // , + ~ >
24
+ / \s * ( \+ | ~ | > ) \s * / g, "$1" ,
25
+ //* ~ + >
26
+ / ( [ a - z A - Z 0 - 9 \_ \- \* ] ) ~ ( [ a - z A - Z 0 - 9 \_ \- \* ] ) / g, "$1/following-sibling::$2" ,
27
+ / ( [ a - z A - Z 0 - 9 \_ \- \* ] ) \+ ( [ a - z A - Z 0 - 9 \_ \- \* ] ) / g, "$1/following-sibling::*[1]/self::$2" ,
28
+ / ( [ a - z A - Z 0 - 9 \_ \- \* ] ) > ( [ a - z A - Z 0 - 9 \_ \- \* ] ) / g, "$1/$2" ,
29
+ // all unescaped stuff escaped
30
+ / \[ ( [ ^ = ] + ) = ( [ ^ ' | " ] [ ^ \] ] * ) \] / g, "[$1='$2']" ,
31
+ // all descendant or self to //
32
+ / ( ^ | [ ^ a - z A - Z 0 - 9 \_ \- \* ] ) ( # | \. ) ( [ a - z A - Z 0 - 9 \_ \- ] + ) / g, "$1*$2$3" ,
33
+ / ( [ \> \+ \| \~ \, \s ] ) ( [ a - z A - Z \* ] + ) / g, '$1//$2' ,
34
+ / \s + \/ \/ / g, '//' ,
35
+ // :first-child
36
+ / ( [ a - z A - Z 0 - 9 \_ \- \* ] + ) : f i r s t - c h i l d / g, "*[1]/self::$1" ,
37
+ // :last-child
38
+ / ( [ a - z A - Z 0 - 9 \_ \- \* ] + ) : l a s t - c h i l d / g, "$1[not(following-sibling::*)]" ,
39
+ // :only-child
40
+ / ( [ a - z A - Z 0 - 9 \_ \- \* ] + ) : o n l y - c h i l d / g, "*[last()=1]/self::$1" ,
41
+ // :empty
42
+ / ( [ a - z A - Z 0 - 9 \_ \- \* ] + ) : e m p t y / g, "$1[not(*) and not(normalize-space())]" ,
43
+ // :not
44
+ / ( [ a - z A - Z 0 - 9 \_ \- \* ] + ) : n o t \( ( [ ^ \) ] * ) \) / g, function ( s , a , b ) { return a . concat ( "[not(" , css2xpath ( b ) . replace ( / ^ [ ^ \[ ] + \[ ( [ ^ \] ] * ) \] .* $ / g, "$1" ) , ")]" ) ; } ,
45
+ // :nth-child
46
+ / ( [ a - z A - Z 0 - 9 \_ \- \* ] + ) : n t h - c h i l d \( ( [ ^ \) ] * ) \) / g, function ( s , a , b ) {
47
+ switch ( b ) {
48
+ case "n" :
49
+ return a ;
50
+ case "even" :
51
+ return "*[position() mod 2=0 and position()>=0]/self::" + a ;
52
+ case "odd" :
53
+ return a + "[(count(preceding-sibling::*) + 1) mod 2=1]" ;
54
+ default :
55
+ b = ( b || "0" ) . replace ( / ^ ( [ 0 - 9 ] * ) n .* ?( [ 0 - 9 ] * ) $ / , "$1+$2" ) . split ( "+" ) ;
56
+ b [ 1 ] = b [ 1 ] || "0" ;
57
+ return "*[(position()-" . concat ( b [ 1 ] , ") mod " , b [ 0 ] , "=0 and position()>=" , b [ 1 ] , "]/self::" , a ) ;
58
+ }
59
+ } ,
60
+ // :contains(selectors)
61
+ / : c o n t a i n s \( ( [ ^ \) ] * ) \) / g, function ( s , a ) {
62
+ /*return "[contains(css:lower-case(string(.)),'" + a.toLowerCase() + "')]"; // it does not work in firefox 3*/
63
+ return "[contains(string(.),'" + a + "')]" ;
64
+ } ,
65
+ // |= attrib
66
+ / \[ ( [ a - z A - Z 0 - 9 \_ \- ] + ) \| = ( [ ^ \] ] + ) \] / g, "[@$1=$2 or starts-with(@$1,concat($2,'-'))]" ,
67
+ // *= attrib
68
+ / \[ ( [ a - z A - Z 0 - 9 \_ \- ] + ) \* = ( [ ^ \] ] + ) \] / g, "[contains(@$1,$2)]" ,
69
+ // ~= attrib
70
+ / \[ ( [ a - z A - Z 0 - 9 \_ \- ] + ) ~ = ( [ ^ \] ] + ) \] / g, "[contains(concat(' ',normalize-space(@$1),' '),concat(' ',$2,' '))]" ,
71
+ // ^= attrib
72
+ / \[ ( [ a - z A - Z 0 - 9 \_ \- ] + ) \^ = ( [ ^ \] ] + ) \] / g, "[starts-with(@$1,$2)]" ,
73
+ // $= attrib
74
+ / \[ ( [ a - z A - Z 0 - 9 \_ \- ] + ) \$ = ( [ ^ \] ] + ) \] / g, function ( s , a , b ) { return "[substring(@" . concat ( a , ",string-length(@" , a , ")-" , b . length - 3 , ")=" , b , "]" ) ; } ,
75
+ // != attrib
76
+ / \[ ( [ a - z A - Z 0 - 9 \_ \- ] + ) \! = ( [ ^ \] ] + ) \] / g, "[not(@$1) or @$1!=$2]" ,
77
+ // ids and classes
78
+ / # ( [ a - z A - Z 0 - 9 \_ \- ] + ) / g, "[@id='$1']" ,
79
+ / \. ( [ a - z A - Z 0 - 9 \_ \- ] + ) / g, "[contains(concat(' ',normalize-space(@class),' '),' $1 ')]" ,
80
+ // normalize multiple filters
81
+ / \] \[ ( [ ^ \] ] + ) / g, " and ($1)"
82
+ ] ,
83
+ length = re . length
84
+ ;
85
+ return function css2xpath ( s ) {
86
+ var i = 0 ;
87
+ while ( i < length )
88
+ s = s . replace ( re [ i ++ ] , re [ i ++ ] ) ;
89
+ return "//" + s ;
90
+ } ;
91
+ } ) ( ) ;
0 commit comments